jsgen.nim 93 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # This is the JavaScript code generator.
  10. discard """
  11. The JS code generator contains only 2 tricks:
  12. Trick 1
  13. -------
  14. Some locations (for example 'var int') require "fat pointers" (`etyBaseIndex`)
  15. which are pairs (array, index). The derefence operation is then 'array[index]'.
  16. Check `mapType` for the details.
  17. Trick 2
  18. -------
  19. It is preferable to generate '||' and '&&' if possible since that is more
  20. idiomatic and hence should be friendlier for the JS JIT implementation. However
  21. code like `foo and (let bar = baz())` cannot be translated this way. Instead
  22. the expressions need to be transformed into statements. `isSimpleExpr`
  23. implements the required case distinction.
  24. """
  25. import
  26. ast, trees, magicsys, options,
  27. nversion, msgs, idents, types,
  28. ropes, passes, ccgutils, wordrecg, renderer,
  29. cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
  30. transf, injectdestructors, sourcemap, astmsgs
  31. import json, sets, math, tables, intsets
  32. import strutils except addf
  33. when defined(nimPreviewSlimSystem):
  34. import std/[assertions, syncio]
  35. type
  36. TJSGen = object of PPassContext
  37. module: PSym
  38. graph: ModuleGraph
  39. config: ConfigRef
  40. sigConflicts: CountTable[SigHash]
  41. BModule = ref TJSGen
  42. TJSTypeKind = enum # necessary JS "types"
  43. etyNone, # no type
  44. etyNull, # null type
  45. etyProc, # proc type
  46. etyBool, # bool type
  47. etySeq, # Nim seq or string type
  48. etyInt, # JavaScript's int
  49. etyFloat, # JavaScript's float
  50. etyString, # JavaScript's string
  51. etyObject, # JavaScript's reference to an object
  52. etyBaseIndex # base + index needed
  53. TResKind = enum
  54. resNone, # not set
  55. resExpr, # is some complex expression
  56. resVal, # is a temporary/value/l-value
  57. resCallee # expression is callee
  58. TCompRes = object
  59. kind: TResKind
  60. typ: TJSTypeKind
  61. res: Rope # result part; index if this is an
  62. # (address, index)-tuple
  63. address: Rope # address of an (address, index)-tuple
  64. tmpLoc: Rope # tmp var which stores the (address, index)
  65. # pair to prevent multiple evals.
  66. # the tmp is initialized upon evaling the
  67. # address.
  68. # might be nil.
  69. # (see `maybeMakeTemp`)
  70. TBlock = object
  71. id: int # the ID of the label; positive means that it
  72. # has been used (i.e. the label should be emitted)
  73. isLoop: bool # whether it's a 'block' or 'while'
  74. PGlobals = ref object of RootObj
  75. typeInfo, constants, code: Rope
  76. forwarded: seq[PSym]
  77. generatedSyms: IntSet
  78. typeInfoGenerated: IntSet
  79. unique: int # for temp identifier generation
  80. inSystem: bool
  81. PProc = ref TProc
  82. TProc = object
  83. procDef: PNode
  84. prc: PSym
  85. globals, locals, body: Rope
  86. options: TOptions
  87. module: BModule
  88. g: PGlobals
  89. generatedParamCopies: IntSet
  90. beforeRetNeeded: bool
  91. unique: int # for temp identifier generation
  92. blocks: seq[TBlock]
  93. extraIndent: int
  94. up: PProc # up the call chain; required for closure support
  95. declaredGlobals: IntSet
  96. template config*(p: PProc): ConfigRef = p.module.config
  97. proc indentLine(p: PProc, r: Rope): Rope =
  98. var p = p
  99. var ind = 0
  100. while true:
  101. inc ind, p.blocks.len + p.extraIndent
  102. if p.up == nil or p.up.prc != p.prc.owner:
  103. break
  104. p = p.up
  105. result = repeat(' ', ind*2) & r
  106. template line(p: PProc, added: string) =
  107. p.body.add(indentLine(p, rope(added)))
  108. template lineF(p: PProc, frmt: FormatStr, args: varargs[Rope]) =
  109. p.body.add(indentLine(p, ropes.`%`(frmt, args)))
  110. template nested(p, body) =
  111. inc p.extraIndent
  112. body
  113. dec p.extraIndent
  114. proc newGlobals(): PGlobals =
  115. new(result)
  116. result.forwarded = @[]
  117. result.generatedSyms = initIntSet()
  118. result.typeInfoGenerated = initIntSet()
  119. proc initCompRes(r: var TCompRes) =
  120. r.address = ""
  121. r.res = ""
  122. r.tmpLoc = ""
  123. r.typ = etyNone
  124. r.kind = resNone
  125. proc rdLoc(a: TCompRes): Rope {.inline.} =
  126. if a.typ != etyBaseIndex:
  127. result = a.res
  128. else:
  129. result = "$1[$2]" % [a.address, a.res]
  130. proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
  131. options: TOptions): PProc =
  132. result = PProc(
  133. blocks: @[],
  134. options: options,
  135. module: module,
  136. procDef: procDef,
  137. g: globals,
  138. extraIndent: int(procDef != nil))
  139. if procDef != nil: result.prc = procDef[namePos].sym
  140. proc initProcOptions(module: BModule): TOptions =
  141. result = module.config.options
  142. if PGlobals(module.graph.backend).inSystem:
  143. result.excl(optStackTrace)
  144. proc newInitProc(globals: PGlobals, module: BModule): PProc =
  145. result = newProc(globals, module, nil, initProcOptions(module))
  146. proc declareGlobal(p: PProc; id: int; r: Rope) =
  147. if p.prc != nil and not p.declaredGlobals.containsOrIncl(id):
  148. p.locals.addf("global $1;$n", [r])
  149. const
  150. MappedToObject = {tyObject, tyArray, tyTuple, tyOpenArray,
  151. tySet, tyVarargs}
  152. proc mapType(typ: PType): TJSTypeKind =
  153. let t = skipTypes(typ, abstractInst)
  154. case t.kind
  155. of tyVar, tyRef, tyPtr:
  156. if skipTypes(t.lastSon, abstractInst).kind in MappedToObject:
  157. result = etyObject
  158. else:
  159. result = etyBaseIndex
  160. of tyPointer:
  161. # treat a tyPointer like a typed pointer to an array of bytes
  162. result = etyBaseIndex
  163. of tyRange, tyDistinct, tyOrdinal, tyProxy, tyLent:
  164. # tyLent is no-op as JS has pass-by-reference semantics
  165. result = mapType(t[0])
  166. of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
  167. of tyBool: result = etyBool
  168. of tyFloat..tyFloat128: result = etyFloat
  169. of tySet: result = etyObject # map a set to a table
  170. of tyString, tySequence: result = etySeq
  171. of tyObject, tyArray, tyTuple, tyOpenArray, tyVarargs, tyUncheckedArray:
  172. result = etyObject
  173. of tyNil: result = etyNull
  174. of tyGenericParam, tyGenericBody, tyGenericInvocation,
  175. tyNone, tyFromExpr, tyForward, tyEmpty,
  176. tyUntyped, tyTyped, tyTypeDesc, tyBuiltInTypeClass, tyCompositeTypeClass,
  177. tyAnd, tyOr, tyNot, tyAnything, tyVoid:
  178. result = etyNone
  179. of tyGenericInst, tyInferred, tyAlias, tyUserTypeClass, tyUserTypeClassInst,
  180. tySink, tyOwned:
  181. result = mapType(typ.lastSon)
  182. of tyStatic:
  183. if t.n != nil: result = mapType(lastSon t)
  184. else: result = etyNone
  185. of tyProc: result = etyProc
  186. of tyCstring: result = etyString
  187. of tyConcept, tyIterable: doAssert false
  188. proc mapType(p: PProc; typ: PType): TJSTypeKind =
  189. result = mapType(typ)
  190. proc mangleName(m: BModule, s: PSym): Rope =
  191. proc validJsName(name: string): bool =
  192. result = true
  193. const reservedWords = ["abstract", "await", "boolean", "break", "byte",
  194. "case", "catch", "char", "class", "const", "continue", "debugger",
  195. "default", "delete", "do", "double", "else", "enum", "export", "extends",
  196. "false", "final", "finally", "float", "for", "function", "goto", "if",
  197. "implements", "import", "in", "instanceof", "int", "interface", "let",
  198. "long", "native", "new", "null", "package", "private", "protected",
  199. "public", "return", "short", "static", "super", "switch", "synchronized",
  200. "this", "throw", "throws", "transient", "true", "try", "typeof", "var",
  201. "void", "volatile", "while", "with", "yield"]
  202. case name
  203. of reservedWords:
  204. return false
  205. else:
  206. discard
  207. if name[0] in {'0'..'9'}: return false
  208. for chr in name:
  209. if chr notin {'A'..'Z','a'..'z','_','$','0'..'9'}:
  210. return false
  211. result = s.loc.r
  212. if result == "":
  213. if s.kind == skField and s.name.s.validJsName:
  214. result = rope(s.name.s)
  215. elif s.kind == skTemp:
  216. result = rope(mangle(s.name.s))
  217. else:
  218. var x = newStringOfCap(s.name.s.len)
  219. var i = 0
  220. while i < s.name.s.len:
  221. let c = s.name.s[i]
  222. case c
  223. of 'A'..'Z', 'a'..'z', '_', '0'..'9':
  224. x.add c
  225. else:
  226. x.add("HEX" & toHex(ord(c), 2))
  227. inc i
  228. result = rope(x)
  229. # From ES5 on reserved words can be used as object field names
  230. if s.kind != skField:
  231. if m.config.hcrOn:
  232. # When hot reloading is enabled, we must ensure that the names
  233. # of functions and types will be preserved across rebuilds:
  234. result.add(idOrSig(s, m.module.name.s, m.sigConflicts))
  235. else:
  236. result.add("_")
  237. result.add(rope(s.id))
  238. s.loc.r = result
  239. proc escapeJSString(s: string): string =
  240. result = newStringOfCap(s.len + s.len shr 2)
  241. result.add("\"")
  242. for c in items(s):
  243. case c
  244. of '\l': result.add("\\n")
  245. of '\r': result.add("\\r")
  246. of '\t': result.add("\\t")
  247. of '\b': result.add("\\b")
  248. of '\a': result.add("\\a")
  249. of '\e': result.add("\\e")
  250. of '\v': result.add("\\v")
  251. of '\\': result.add("\\\\")
  252. of '\"': result.add("\\\"")
  253. else: result.add(c)
  254. result.add("\"")
  255. proc makeJSString(s: string, escapeNonAscii = true): Rope =
  256. if escapeNonAscii:
  257. result = strutils.escape(s).rope
  258. else:
  259. result = escapeJSString(s).rope
  260. proc makeJsNimStrLit(s: string): Rope =
  261. var x = newStringOfCap(4*s.len+1)
  262. x.add "["
  263. var i = 0
  264. if i < s.len:
  265. x.addInt int64(s[i])
  266. inc i
  267. while i < s.len:
  268. x.add ","
  269. x.addInt int64(s[i])
  270. inc i
  271. x.add "]"
  272. result = rope(x)
  273. include jstypes
  274. proc gen(p: PProc, n: PNode, r: var TCompRes)
  275. proc genStmt(p: PProc, n: PNode)
  276. proc genProc(oldProc: PProc, prc: PSym): Rope
  277. proc genConstant(p: PProc, c: PSym)
  278. proc useMagic(p: PProc, name: string) =
  279. if name.len == 0: return
  280. var s = magicsys.getCompilerProc(p.module.graph, name)
  281. if s != nil:
  282. internalAssert p.config, s.kind in {skProc, skFunc, skMethod, skConverter}
  283. if not p.g.generatedSyms.containsOrIncl(s.id):
  284. let code = genProc(p, s)
  285. p.g.constants.add(code)
  286. else:
  287. if p.prc != nil:
  288. globalError(p.config, p.prc.info, "system module needs: " & name)
  289. else:
  290. rawMessage(p.config, errGenerated, "system module needs: " & name)
  291. proc isSimpleExpr(p: PProc; n: PNode): bool =
  292. # calls all the way down --> can stay expression based
  293. case n.kind
  294. of nkCallKinds, nkBracketExpr, nkDotExpr, nkPar, nkTupleConstr,
  295. nkObjConstr, nkBracket, nkCurly,
  296. nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr,
  297. nkConv, nkHiddenStdConv, nkHiddenSubConv:
  298. for c in n:
  299. if not p.isSimpleExpr(c): return false
  300. result = true
  301. of nkStmtListExpr:
  302. for i in 0..<n.len-1:
  303. if n[i].kind notin {nkCommentStmt, nkEmpty}: return false
  304. result = isSimpleExpr(p, n.lastSon)
  305. else:
  306. if n.isAtom:
  307. result = true
  308. proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
  309. inc(p.unique)
  310. result = "Temporary$1" % [rope(p.unique)]
  311. if defineInLocals:
  312. p.locals.add(p.indentLine("var $1;$n" % [result]))
  313. proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
  314. assert r.kind == resNone
  315. var x, y: TCompRes
  316. if p.isSimpleExpr(a) and p.isSimpleExpr(b):
  317. gen(p, a, x)
  318. gen(p, b, y)
  319. r.kind = resExpr
  320. r.res = "($1 && $2)" % [x.rdLoc, y.rdLoc]
  321. else:
  322. r.res = p.getTemp
  323. r.kind = resVal
  324. # while a and b:
  325. # -->
  326. # while true:
  327. # aa
  328. # if not a: tmp = false
  329. # else:
  330. # bb
  331. # tmp = b
  332. # tmp
  333. gen(p, a, x)
  334. lineF(p, "if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
  335. p.nested:
  336. gen(p, b, y)
  337. lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
  338. line(p, "}")
  339. proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
  340. assert r.kind == resNone
  341. var x, y: TCompRes
  342. if p.isSimpleExpr(a) and p.isSimpleExpr(b):
  343. gen(p, a, x)
  344. gen(p, b, y)
  345. r.kind = resExpr
  346. r.res = "($1 || $2)" % [x.rdLoc, y.rdLoc]
  347. else:
  348. r.res = p.getTemp
  349. r.kind = resVal
  350. gen(p, a, x)
  351. lineF(p, "if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
  352. p.nested:
  353. gen(p, b, y)
  354. lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
  355. line(p, "}")
  356. type
  357. TMagicFrmt = array[0..1, string]
  358. TMagicOps = array[mAddI..mStrToStr, TMagicFrmt]
  359. const # magic checked op; magic unchecked op;
  360. jsMagics: TMagicOps = [
  361. mAddI: ["addInt", ""],
  362. mSubI: ["subInt", ""],
  363. mMulI: ["mulInt", ""],
  364. mDivI: ["divInt", ""],
  365. mModI: ["modInt", ""],
  366. mSucc: ["addInt", ""],
  367. mPred: ["subInt", ""],
  368. mAddF64: ["", ""],
  369. mSubF64: ["", ""],
  370. mMulF64: ["", ""],
  371. mDivF64: ["", ""],
  372. mShrI: ["", ""],
  373. mShlI: ["", ""],
  374. mAshrI: ["", ""],
  375. mBitandI: ["", ""],
  376. mBitorI: ["", ""],
  377. mBitxorI: ["", ""],
  378. mMinI: ["nimMin", "nimMin"],
  379. mMaxI: ["nimMax", "nimMax"],
  380. mAddU: ["", ""],
  381. mSubU: ["", ""],
  382. mMulU: ["", ""],
  383. mDivU: ["", ""],
  384. mModU: ["", ""],
  385. mEqI: ["", ""],
  386. mLeI: ["", ""],
  387. mLtI: ["", ""],
  388. mEqF64: ["", ""],
  389. mLeF64: ["", ""],
  390. mLtF64: ["", ""],
  391. mLeU: ["", ""],
  392. mLtU: ["", ""],
  393. mEqEnum: ["", ""],
  394. mLeEnum: ["", ""],
  395. mLtEnum: ["", ""],
  396. mEqCh: ["", ""],
  397. mLeCh: ["", ""],
  398. mLtCh: ["", ""],
  399. mEqB: ["", ""],
  400. mLeB: ["", ""],
  401. mLtB: ["", ""],
  402. mEqRef: ["", ""],
  403. mLePtr: ["", ""],
  404. mLtPtr: ["", ""],
  405. mXor: ["", ""],
  406. mEqCString: ["", ""],
  407. mEqProc: ["", ""],
  408. mUnaryMinusI: ["negInt", ""],
  409. mUnaryMinusI64: ["negInt64", ""],
  410. mAbsI: ["absInt", ""],
  411. mNot: ["", ""],
  412. mUnaryPlusI: ["", ""],
  413. mBitnotI: ["", ""],
  414. mUnaryPlusF64: ["", ""],
  415. mUnaryMinusF64: ["", ""],
  416. mCharToStr: ["nimCharToStr", "nimCharToStr"],
  417. mBoolToStr: ["nimBoolToStr", "nimBoolToStr"],
  418. mIntToStr: ["cstrToNimstr", "cstrToNimstr"],
  419. mInt64ToStr: ["cstrToNimstr", "cstrToNimstr"],
  420. mFloatToStr: ["cstrToNimstr", "cstrToNimstr"],
  421. mCStrToStr: ["cstrToNimstr", "cstrToNimstr"],
  422. mStrToStr: ["", ""]]
  423. proc needsTemp(p: PProc; n: PNode): bool =
  424. # check if n contains a call to determine
  425. # if a temp should be made to prevent multiple evals
  426. if n.kind in nkCallKinds + {nkTupleConstr, nkObjConstr, nkBracket, nkCurly}:
  427. return true
  428. for c in n:
  429. if needsTemp(p, c):
  430. return true
  431. proc maybeMakeTemp(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] =
  432. var
  433. a = x.rdLoc
  434. b = a
  435. if needsTemp(p, n):
  436. # if we have tmp just use it
  437. if x.tmpLoc != "" and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}):
  438. b = "$1[0][$1[1]]" % [x.tmpLoc]
  439. (a: a, tmp: b)
  440. else:
  441. let tmp = p.getTemp
  442. b = tmp
  443. a = "($1 = $2, $1)" % [tmp, a]
  444. (a: a, tmp: b)
  445. else:
  446. (a: a, tmp: b)
  447. proc maybeMakeTempAssignable(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] =
  448. var
  449. a = x.rdLoc
  450. b = a
  451. if needsTemp(p, n):
  452. # if we have tmp just use it
  453. if x.tmpLoc != "" and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}):
  454. b = "$1[0][$1[1]]" % [x.tmpLoc]
  455. result = (a: a, tmp: b)
  456. elif x.tmpLoc != "" and n.kind == nkBracketExpr:
  457. # genArrayAddr
  458. var
  459. address, index: TCompRes
  460. first: Int128
  461. gen(p, n[0], address)
  462. gen(p, n[1], index)
  463. let (m1, tmp1) = maybeMakeTemp(p, n[0], address)
  464. let typ = skipTypes(n[0].typ, abstractPtrs)
  465. if typ.kind == tyArray:
  466. first = firstOrd(p.config, typ[0])
  467. if optBoundsCheck in p.options:
  468. useMagic(p, "chckIndx")
  469. if first == 0: # save a couple chars
  470. index.res = "chckIndx($1, 0, ($2).length - 1)" % [index.res, tmp1]
  471. else:
  472. index.res = "chckIndx($1, $2, ($3).length + ($2) - 1) - ($2)" % [
  473. index.res, rope(first), tmp1]
  474. elif first != 0:
  475. index.res = "($1) - ($2)" % [index.res, rope(first)]
  476. else:
  477. discard # index.res = index.res
  478. let (n1, tmp2) = maybeMakeTemp(p, n[1], index)
  479. result = (a: "$1[$2]" % [m1, n1], tmp: "$1[$2]" % [tmp1, tmp2])
  480. # could also put here: nkDotExpr -> genFieldAccess, nkCheckedFieldExpr -> genCheckedFieldOp
  481. # but the uses of maybeMakeTempAssignable don't need them
  482. else:
  483. result = (a: a, tmp: b)
  484. else:
  485. result = (a: a, tmp: b)
  486. template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string,
  487. reassign = false) =
  488. # $1 and $2 in the `frmt` string bind to lhs and rhs of the expr,
  489. # if $3 or $4 are present they will be substituted with temps for
  490. # lhs and rhs respectively
  491. var x, y: TCompRes
  492. useMagic(p, magic)
  493. gen(p, n[1], x)
  494. gen(p, n[2], y)
  495. var
  496. a, tmp = x.rdLoc
  497. b, tmp2 = y.rdLoc
  498. when reassign:
  499. (a, tmp) = maybeMakeTempAssignable(p, n[1], x)
  500. else:
  501. when "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
  502. when "$4" in frmt: (b, tmp2) = maybeMakeTemp(p, n[2], y)
  503. r.res = frmt % [a, b, tmp, tmp2]
  504. r.kind = resExpr
  505. proc unsignedTrimmerJS(size: BiggestInt): Rope =
  506. case size
  507. of 1: rope"& 0xff"
  508. of 2: rope"& 0xffff"
  509. of 4: rope">>> 0"
  510. else: rope""
  511. template unsignedTrimmer(size: BiggestInt): Rope =
  512. size.unsignedTrimmerJS
  513. proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
  514. reassign: static[bool] = false) =
  515. var x, y: TCompRes
  516. gen(p, n[1], x)
  517. gen(p, n[2], y)
  518. let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
  519. when reassign:
  520. let (a, tmp) = maybeMakeTempAssignable(p, n[1], x)
  521. r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp]
  522. else:
  523. r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
  524. r.kind = resExpr
  525. template ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
  526. var x, y, z: TCompRes
  527. useMagic(p, magic)
  528. gen(p, n[1], x)
  529. gen(p, n[2], y)
  530. gen(p, n[3], z)
  531. r.res = frmt % [x.rdLoc, y.rdLoc, z.rdLoc]
  532. r.kind = resExpr
  533. template unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
  534. # $1 binds to n[1], if $2 is present it will be substituted to a tmp of $1
  535. useMagic(p, magic)
  536. gen(p, n[1], r)
  537. var a, tmp = r.rdLoc
  538. if "$2" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], r)
  539. r.res = frmt % [a, tmp]
  540. r.kind = resExpr
  541. proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
  542. var
  543. x, y: TCompRes
  544. xLoc, yLoc: Rope
  545. let i = ord(optOverflowCheck notin p.options)
  546. useMagic(p, jsMagics[op][i])
  547. if n.len > 2:
  548. gen(p, n[1], x)
  549. gen(p, n[2], y)
  550. xLoc = x.rdLoc
  551. yLoc = y.rdLoc
  552. else:
  553. gen(p, n[1], r)
  554. xLoc = r.rdLoc
  555. template applyFormat(frmt) =
  556. r.res = frmt % [xLoc, yLoc]
  557. template applyFormat(frmtA, frmtB) =
  558. if i == 0: applyFormat(frmtA) else: applyFormat(frmtB)
  559. case op
  560. of mAddI: applyFormat("addInt($1, $2)", "($1 + $2)")
  561. of mSubI: applyFormat("subInt($1, $2)", "($1 - $2)")
  562. of mMulI: applyFormat("mulInt($1, $2)", "($1 * $2)")
  563. of mDivI: applyFormat("divInt($1, $2)", "Math.trunc($1 / $2)")
  564. of mModI: applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)")
  565. of mSucc: applyFormat("addInt($1, $2)", "($1 + $2)")
  566. of mPred: applyFormat("subInt($1, $2)", "($1 - $2)")
  567. of mAddF64: applyFormat("($1 + $2)", "($1 + $2)")
  568. of mSubF64: applyFormat("($1 - $2)", "($1 - $2)")
  569. of mMulF64: applyFormat("($1 * $2)", "($1 * $2)")
  570. of mDivF64: applyFormat("($1 / $2)", "($1 / $2)")
  571. of mShrI: applyFormat("", "")
  572. of mShlI:
  573. if n[1].typ.size <= 4:
  574. applyFormat("($1 << $2)", "($1 << $2)")
  575. else:
  576. applyFormat("($1 * Math.pow(2, $2))", "($1 * Math.pow(2, $2))")
  577. of mAshrI:
  578. if n[1].typ.size <= 4:
  579. applyFormat("($1 >> $2)", "($1 >> $2)")
  580. else:
  581. applyFormat("Math.floor($1 / Math.pow(2, $2))", "Math.floor($1 / Math.pow(2, $2))")
  582. of mBitandI: applyFormat("($1 & $2)", "($1 & $2)")
  583. of mBitorI: applyFormat("($1 | $2)", "($1 | $2)")
  584. of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)")
  585. of mMinI: applyFormat("nimMin($1, $2)", "nimMin($1, $2)")
  586. of mMaxI: applyFormat("nimMax($1, $2)", "nimMax($1, $2)")
  587. of mAddU: applyFormat("", "")
  588. of mSubU: applyFormat("", "")
  589. of mMulU: applyFormat("", "")
  590. of mDivU: applyFormat("", "")
  591. of mModU: applyFormat("($1 % $2)", "($1 % $2)")
  592. of mEqI: applyFormat("($1 == $2)", "($1 == $2)")
  593. of mLeI: applyFormat("($1 <= $2)", "($1 <= $2)")
  594. of mLtI: applyFormat("($1 < $2)", "($1 < $2)")
  595. of mEqF64: applyFormat("($1 == $2)", "($1 == $2)")
  596. of mLeF64: applyFormat("($1 <= $2)", "($1 <= $2)")
  597. of mLtF64: applyFormat("($1 < $2)", "($1 < $2)")
  598. of mLeU: applyFormat("($1 <= $2)", "($1 <= $2)")
  599. of mLtU: applyFormat("($1 < $2)", "($1 < $2)")
  600. of mEqEnum: applyFormat("($1 == $2)", "($1 == $2)")
  601. of mLeEnum: applyFormat("($1 <= $2)", "($1 <= $2)")
  602. of mLtEnum: applyFormat("($1 < $2)", "($1 < $2)")
  603. of mEqCh: applyFormat("($1 == $2)", "($1 == $2)")
  604. of mLeCh: applyFormat("($1 <= $2)", "($1 <= $2)")
  605. of mLtCh: applyFormat("($1 < $2)", "($1 < $2)")
  606. of mEqB: applyFormat("($1 == $2)", "($1 == $2)")
  607. of mLeB: applyFormat("($1 <= $2)", "($1 <= $2)")
  608. of mLtB: applyFormat("($1 < $2)", "($1 < $2)")
  609. of mEqRef: applyFormat("($1 == $2)", "($1 == $2)")
  610. of mLePtr: applyFormat("($1 <= $2)", "($1 <= $2)")
  611. of mLtPtr: applyFormat("($1 < $2)", "($1 < $2)")
  612. of mXor: applyFormat("($1 != $2)", "($1 != $2)")
  613. of mEqCString: applyFormat("($1 == $2)", "($1 == $2)")
  614. of mEqProc: applyFormat("($1 == $2)", "($1 == $2)")
  615. of mUnaryMinusI: applyFormat("negInt($1)", "-($1)")
  616. of mUnaryMinusI64: applyFormat("negInt64($1)", "-($1)")
  617. of mAbsI: applyFormat("absInt($1)", "Math.abs($1)")
  618. of mNot: applyFormat("!($1)", "!($1)")
  619. of mUnaryPlusI: applyFormat("+($1)", "+($1)")
  620. of mBitnotI: applyFormat("~($1)", "~($1)")
  621. of mUnaryPlusF64: applyFormat("+($1)", "+($1)")
  622. of mUnaryMinusF64: applyFormat("-($1)", "-($1)")
  623. of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)")
  624. of mBoolToStr: applyFormat("nimBoolToStr($1)", "nimBoolToStr($1)")
  625. of mIntToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")")
  626. of mInt64ToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")")
  627. of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)")
  628. of mStrToStr, mUnown, mIsolate, mFinished: applyFormat("$1", "$1")
  629. else:
  630. assert false, $op
  631. proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
  632. case op
  633. of mAddU: binaryUintExpr(p, n, r, "+")
  634. of mSubU: binaryUintExpr(p, n, r, "-")
  635. of mMulU: binaryUintExpr(p, n, r, "*")
  636. of mDivU:
  637. binaryUintExpr(p, n, r, "/")
  638. if n[1].typ.skipTypes(abstractRange).size == 8:
  639. r.res = "Math.trunc($1)" % [r.res]
  640. of mDivI:
  641. arithAux(p, n, r, op)
  642. of mModI:
  643. arithAux(p, n, r, op)
  644. of mShrI:
  645. var x, y: TCompRes
  646. gen(p, n[1], x)
  647. gen(p, n[2], y)
  648. r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc]
  649. of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr:
  650. arithAux(p, n, r, op)
  651. of mEqRef:
  652. if mapType(n[1].typ) != etyBaseIndex:
  653. arithAux(p, n, r, op)
  654. else:
  655. var x, y: TCompRes
  656. gen(p, n[1], x)
  657. gen(p, n[2], y)
  658. r.res = "($# == $# && $# == $#)" % [x.address, y.address, x.res, y.res]
  659. else:
  660. arithAux(p, n, r, op)
  661. r.kind = resExpr
  662. proc hasFrameInfo(p: PProc): bool =
  663. ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
  664. ((p.prc == nil) or not (sfPure in p.prc.flags))
  665. proc lineDir(config: ConfigRef, info: TLineInfo, line: int): Rope =
  666. ropes.`%`("/* line $2 \"$1\" */$n",
  667. [rope(toFullPath(config, info)), rope(line)])
  668. proc genLineDir(p: PProc, n: PNode) =
  669. let line = toLinenumber(n.info)
  670. if line < 0:
  671. return
  672. if optLineDir in p.options or optLineDir in p.config.options:
  673. lineF(p, "$1", [lineDir(p.config, n.info, line)])
  674. if hasFrameInfo(p):
  675. lineF(p, "F.line = $1;$n", [rope(line)])
  676. proc genWhileStmt(p: PProc, n: PNode) =
  677. var cond: TCompRes
  678. internalAssert p.config, isEmptyType(n.typ)
  679. genLineDir(p, n)
  680. inc(p.unique)
  681. setLen(p.blocks, p.blocks.len + 1)
  682. p.blocks[^1].id = -p.unique
  683. p.blocks[^1].isLoop = true
  684. let labl = p.unique.rope
  685. lineF(p, "Label$1: while (true) {$n", [labl])
  686. p.nested: gen(p, n[0], cond)
  687. lineF(p, "if (!$1) break Label$2;$n",
  688. [cond.res, labl])
  689. p.nested: genStmt(p, n[1])
  690. lineF(p, "}$n", [labl])
  691. setLen(p.blocks, p.blocks.len - 1)
  692. proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
  693. if src.kind != resNone:
  694. if dest.kind != resNone:
  695. lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
  696. else:
  697. lineF(p, "$1;$n", [src.rdLoc])
  698. src.kind = resNone
  699. src.res = ""
  700. proc genTry(p: PProc, n: PNode, r: var TCompRes) =
  701. # code to generate:
  702. #
  703. # ++excHandler;
  704. # var tmpFramePtr = framePtr;
  705. # try {
  706. # stmts;
  707. # --excHandler;
  708. # } catch (EXCEPTION) {
  709. # var prevJSError = lastJSError; lastJSError = EXCEPTION;
  710. # framePtr = tmpFramePtr;
  711. # --excHandler;
  712. # if (e.typ && e.typ == NTI433 || e.typ == NTI2321) {
  713. # stmts;
  714. # } else if (e.typ && e.typ == NTI32342) {
  715. # stmts;
  716. # } else {
  717. # stmts;
  718. # }
  719. # lastJSError = prevJSError;
  720. # } finally {
  721. # framePtr = tmpFramePtr;
  722. # stmts;
  723. # }
  724. genLineDir(p, n)
  725. if not isEmptyType(n.typ):
  726. r.kind = resVal
  727. r.res = getTemp(p)
  728. inc(p.unique)
  729. var i = 1
  730. var catchBranchesExist = n.len > 1 and n[i].kind == nkExceptBranch
  731. if catchBranchesExist:
  732. p.body.add("++excHandler;\L")
  733. var tmpFramePtr = rope"F"
  734. lineF(p, "try {$n", [])
  735. var a: TCompRes
  736. gen(p, n[0], a)
  737. moveInto(p, a, r)
  738. var generalCatchBranchExists = false
  739. if catchBranchesExist:
  740. p.body.addf("--excHandler;$n} catch (EXCEPTION) {$n var prevJSError = lastJSError;$n" &
  741. " lastJSError = EXCEPTION;$n --excHandler;$n", [])
  742. if hasFrameInfo(p):
  743. line(p, "framePtr = $1;$n" % [tmpFramePtr])
  744. while i < n.len and n[i].kind == nkExceptBranch:
  745. if n[i].len == 1:
  746. # general except section:
  747. generalCatchBranchExists = true
  748. if i > 1: lineF(p, "else {$n", [])
  749. gen(p, n[i][0], a)
  750. moveInto(p, a, r)
  751. if i > 1: lineF(p, "}$n", [])
  752. else:
  753. var orExpr: Rope = ""
  754. var excAlias: PNode = nil
  755. useMagic(p, "isObj")
  756. for j in 0..<n[i].len - 1:
  757. var throwObj: PNode
  758. let it = n[i][j]
  759. if it.isInfixAs():
  760. throwObj = it[1]
  761. excAlias = it[2]
  762. # If this is a ``except exc as sym`` branch there must be no following
  763. # nodes
  764. doAssert orExpr == ""
  765. elif it.kind == nkType:
  766. throwObj = it
  767. else:
  768. internalError(p.config, n.info, "genTryStmt")
  769. if orExpr != "": orExpr.add("||")
  770. # Generate the correct type checking code depending on whether this is a
  771. # NIM-native or a JS-native exception
  772. # if isJsObject(throwObj.typ):
  773. if isImportedException(throwObj.typ, p.config):
  774. orExpr.addf("lastJSError instanceof $1",
  775. [throwObj.typ.sym.loc.r])
  776. else:
  777. orExpr.addf("isObj(lastJSError.m_type, $1)",
  778. [genTypeInfo(p, throwObj.typ)])
  779. if i > 1: line(p, "else ")
  780. lineF(p, "if (lastJSError && ($1)) {$n", [orExpr])
  781. # If some branch requires a local alias introduce it here. This is needed
  782. # since JS cannot do ``catch x as y``.
  783. if excAlias != nil:
  784. excAlias.sym.loc.r = mangleName(p.module, excAlias.sym)
  785. lineF(p, "var $1 = lastJSError;$n", excAlias.sym.loc.r)
  786. gen(p, n[i][^1], a)
  787. moveInto(p, a, r)
  788. lineF(p, "}$n", [])
  789. inc(i)
  790. if catchBranchesExist:
  791. if not generalCatchBranchExists:
  792. useMagic(p, "reraiseException")
  793. line(p, "else {\L")
  794. line(p, "\treraiseException();\L")
  795. line(p, "}\L")
  796. lineF(p, "lastJSError = prevJSError;$n")
  797. line(p, "} finally {\L")
  798. if hasFrameInfo(p):
  799. line(p, "framePtr = $1;$n" % [tmpFramePtr])
  800. if i < n.len and n[i].kind == nkFinally:
  801. genStmt(p, n[i][0])
  802. line(p, "}\L")
  803. proc genRaiseStmt(p: PProc, n: PNode) =
  804. if n[0].kind != nkEmpty:
  805. var a: TCompRes
  806. gen(p, n[0], a)
  807. let typ = skipTypes(n[0].typ, abstractPtrs)
  808. genLineDir(p, n)
  809. useMagic(p, "raiseException")
  810. lineF(p, "raiseException($1, $2);$n",
  811. [a.rdLoc, makeJSString(typ.sym.name.s)])
  812. else:
  813. genLineDir(p, n)
  814. useMagic(p, "reraiseException")
  815. line(p, "reraiseException();\L")
  816. proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
  817. var
  818. a, b, cond, stmt: TCompRes
  819. totalRange = 0
  820. genLineDir(p, n)
  821. gen(p, n[0], cond)
  822. let typeKind = skipTypes(n[0].typ, abstractVar).kind
  823. var transferRange = false
  824. let anyString = typeKind in {tyString, tyCstring}
  825. case typeKind
  826. of tyString:
  827. useMagic(p, "toJSStr")
  828. lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc])
  829. of tyFloat..tyFloat128:
  830. transferRange = true
  831. else:
  832. lineF(p, "switch ($1) {$n", [cond.rdLoc])
  833. if not isEmptyType(n.typ):
  834. r.kind = resVal
  835. r.res = getTemp(p)
  836. for i in 1..<n.len:
  837. let it = n[i]
  838. let itLen = it.len
  839. case it.kind
  840. of nkOfBranch:
  841. if transferRange:
  842. if i == 1:
  843. lineF(p, "if (", [])
  844. else:
  845. lineF(p, "else if (", [])
  846. for j in 0..<itLen - 1:
  847. let e = it[j]
  848. if e.kind == nkRange:
  849. if transferRange:
  850. gen(p, e[0], a)
  851. gen(p, e[1], b)
  852. if j != itLen - 2:
  853. lineF(p, "$1 >= $2 && $1 <= $3 || $n", [cond.rdLoc, a.rdLoc, b.rdLoc])
  854. else:
  855. lineF(p, "$1 >= $2 && $1 <= $3", [cond.rdLoc, a.rdLoc, b.rdLoc])
  856. else:
  857. var v = copyNode(e[0])
  858. inc(totalRange, int(e[1].intVal - v.intVal))
  859. if totalRange > 65535:
  860. localError(p.config, n.info,
  861. "Your case statement contains too many branches, consider using if/else instead!")
  862. while v.intVal <= e[1].intVal:
  863. gen(p, v, cond)
  864. lineF(p, "case $1:$n", [cond.rdLoc])
  865. inc(v.intVal)
  866. else:
  867. if anyString:
  868. case e.kind
  869. of nkStrLit..nkTripleStrLit: lineF(p, "case $1:$n",
  870. [makeJSString(e.strVal, false)])
  871. of nkNilLit: lineF(p, "case null:$n", [])
  872. else: internalError(p.config, e.info, "jsgen.genCaseStmt: 2")
  873. else:
  874. if transferRange:
  875. gen(p, e, a)
  876. if j != itLen - 2:
  877. lineF(p, "$1 == $2 || $n", [cond.rdLoc, a.rdLoc])
  878. else:
  879. lineF(p, "$1 == $2", [cond.rdLoc, a.rdLoc])
  880. else:
  881. gen(p, e, a)
  882. lineF(p, "case $1:$n", [a.rdLoc])
  883. if transferRange:
  884. lineF(p, "){", [])
  885. p.nested:
  886. gen(p, lastSon(it), stmt)
  887. moveInto(p, stmt, r)
  888. if transferRange:
  889. lineF(p, "}$n", [])
  890. else:
  891. lineF(p, "break;$n", [])
  892. of nkElse:
  893. if transferRange:
  894. lineF(p, "else{$n", [])
  895. else:
  896. lineF(p, "default: $n", [])
  897. p.nested:
  898. gen(p, it[0], stmt)
  899. moveInto(p, stmt, r)
  900. if transferRange:
  901. lineF(p, "}$n", [])
  902. else:
  903. lineF(p, "break;$n", [])
  904. else: internalError(p.config, it.info, "jsgen.genCaseStmt")
  905. if not transferRange:
  906. lineF(p, "}$n", [])
  907. proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
  908. inc(p.unique)
  909. let idx = p.blocks.len
  910. if n[0].kind != nkEmpty:
  911. # named block?
  912. if (n[0].kind != nkSym): internalError(p.config, n.info, "genBlock")
  913. var sym = n[0].sym
  914. sym.loc.k = locOther
  915. sym.position = idx+1
  916. let labl = p.unique
  917. lineF(p, "Label$1: {$n", [labl.rope])
  918. setLen(p.blocks, idx + 1)
  919. p.blocks[idx].id = - p.unique # negative because it isn't used yet
  920. gen(p, n[1], r)
  921. setLen(p.blocks, idx)
  922. lineF(p, "};$n", [labl.rope])
  923. proc genBreakStmt(p: PProc, n: PNode) =
  924. var idx: int
  925. genLineDir(p, n)
  926. if n[0].kind != nkEmpty:
  927. # named break?
  928. assert(n[0].kind == nkSym)
  929. let sym = n[0].sym
  930. assert(sym.loc.k == locOther)
  931. idx = sym.position-1
  932. else:
  933. # an unnamed 'break' can only break a loop after 'transf' pass:
  934. idx = p.blocks.len - 1
  935. while idx >= 0 and not p.blocks[idx].isLoop: dec idx
  936. if idx < 0 or not p.blocks[idx].isLoop:
  937. internalError(p.config, n.info, "no loop to break")
  938. p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
  939. lineF(p, "break Label$1;$n", [rope(p.blocks[idx].id)])
  940. proc genAsmOrEmitStmt(p: PProc, n: PNode) =
  941. genLineDir(p, n)
  942. p.body.add p.indentLine("")
  943. for i in 0..<n.len:
  944. let it = n[i]
  945. case it.kind
  946. of nkStrLit..nkTripleStrLit:
  947. p.body.add(it.strVal)
  948. of nkSym:
  949. let v = it.sym
  950. # for backwards compatibility we don't deref syms here :-(
  951. if false:
  952. discard
  953. else:
  954. var r: TCompRes
  955. gen(p, it, r)
  956. if it.typ.kind == tyPointer:
  957. # A fat pointer is disguised as an array
  958. r.res = r.address
  959. r.address = ""
  960. r.typ = etyNone
  961. elif r.typ == etyBaseIndex:
  962. # Deference first
  963. r.res = "$1[$2]" % [r.address, r.res]
  964. r.address = ""
  965. r.typ = etyNone
  966. p.body.add(r.rdLoc)
  967. else:
  968. var r: TCompRes
  969. gen(p, it, r)
  970. p.body.add(r.rdLoc)
  971. p.body.add "\L"
  972. proc genIf(p: PProc, n: PNode, r: var TCompRes) =
  973. var cond, stmt: TCompRes
  974. var toClose = 0
  975. if not isEmptyType(n.typ):
  976. r.kind = resVal
  977. r.res = getTemp(p)
  978. for i in 0..<n.len:
  979. let it = n[i]
  980. if it.len != 1:
  981. if i > 0:
  982. lineF(p, "else {$n", [])
  983. inc(toClose)
  984. p.nested: gen(p, it[0], cond)
  985. lineF(p, "if ($1) {$n", [cond.rdLoc])
  986. gen(p, it[1], stmt)
  987. else:
  988. # else part:
  989. lineF(p, "else {$n", [])
  990. p.nested: gen(p, it[0], stmt)
  991. moveInto(p, stmt, r)
  992. lineF(p, "}$n", [])
  993. line(p, repeat('}', toClose) & "\L")
  994. proc generateHeader(p: PProc, typ: PType): Rope =
  995. result = ""
  996. for i in 1..<typ.n.len:
  997. assert(typ.n[i].kind == nkSym)
  998. var param = typ.n[i].sym
  999. if isCompileTimeOnly(param.typ): continue
  1000. if result != "": result.add(", ")
  1001. var name = mangleName(p.module, param)
  1002. result.add(name)
  1003. if mapType(param.typ) == etyBaseIndex:
  1004. result.add(", ")
  1005. result.add(name)
  1006. result.add("_Idx")
  1007. proc countJsParams(typ: PType): int =
  1008. for i in 1..<typ.n.len:
  1009. assert(typ.n[i].kind == nkSym)
  1010. var param = typ.n[i].sym
  1011. if isCompileTimeOnly(param.typ): continue
  1012. if mapType(param.typ) == etyBaseIndex:
  1013. inc result, 2
  1014. else:
  1015. inc result
  1016. const
  1017. nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
  1018. nkFloatLit..nkFloat64Lit, nkPar, nkStringToCString,
  1019. nkObjConstr, nkTupleConstr, nkBracket,
  1020. nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
  1021. nkCommand, nkHiddenCallConv, nkCallStrLit}
  1022. proc needsNoCopy(p: PProc; y: PNode): bool =
  1023. return y.kind in nodeKindsNeedNoCopy or
  1024. ((mapType(y.typ) != etyBaseIndex or (y.kind == nkSym and y.sym.kind == skParam)) and
  1025. (skipTypes(y.typ, abstractInst).kind in
  1026. {tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned} + IntegralTypes))
  1027. proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
  1028. var a, b: TCompRes
  1029. var xtyp = mapType(p, x.typ)
  1030. # disable `[]=` for cstring
  1031. if x.kind == nkBracketExpr and x.len >= 2 and x[0].typ.skipTypes(abstractInst).kind == tyCstring:
  1032. localError(p.config, x.info, "cstring doesn't support `[]=` operator")
  1033. gen(p, x, a)
  1034. genLineDir(p, y)
  1035. gen(p, y, b)
  1036. # we don't care if it's an etyBaseIndex (global) of a string, it's
  1037. # still a string that needs to be copied properly:
  1038. if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}:
  1039. xtyp = etySeq
  1040. case xtyp
  1041. of etySeq:
  1042. if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
  1043. lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
  1044. else:
  1045. useMagic(p, "nimCopy")
  1046. lineF(p, "$1 = nimCopy(null, $2, $3);$n",
  1047. [a.rdLoc, b.res, genTypeInfo(p, y.typ)])
  1048. of etyObject:
  1049. if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
  1050. lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
  1051. else:
  1052. useMagic(p, "nimCopy")
  1053. # supports proc getF(): var T
  1054. if x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].kind in nkCallKinds:
  1055. lineF(p, "nimCopy($1, $2, $3);$n",
  1056. [a.res, b.res, genTypeInfo(p, x.typ)])
  1057. else:
  1058. lineF(p, "$1 = nimCopy($1, $2, $3);$n",
  1059. [a.res, b.res, genTypeInfo(p, x.typ)])
  1060. of etyBaseIndex:
  1061. if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
  1062. if y.kind == nkCall:
  1063. let tmp = p.getTemp(false)
  1064. lineF(p, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc])
  1065. elif b.typ == etyBaseIndex:
  1066. lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
  1067. elif b.typ == etyNone:
  1068. internalAssert p.config, b.address == ""
  1069. lineF(p, "$# = [$#, 0];$n", [a.address, b.res])
  1070. elif x.typ.kind == tyVar and y.typ.kind == tyPtr:
  1071. lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
  1072. lineF(p, "$1 = $2;$n", [a.address, b.res])
  1073. lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
  1074. elif a.typ == etyBaseIndex:
  1075. # array indexing may not map to var type
  1076. if b.address != "":
  1077. lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
  1078. else:
  1079. lineF(p, "$1 = $2;$n", [a.address, b.res])
  1080. else:
  1081. internalError(p.config, x.info, $("genAsgn", b.typ, a.typ))
  1082. elif b.address != "":
  1083. lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
  1084. else:
  1085. lineF(p, "$1 = $2;$n", [a.address, b.res])
  1086. else:
  1087. lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
  1088. proc genAsgn(p: PProc, n: PNode) =
  1089. genAsgnAux(p, n[0], n[1], noCopyNeeded=false)
  1090. proc genFastAsgn(p: PProc, n: PNode) =
  1091. # 'shallowCopy' always produced 'noCopyNeeded = true' here but this is wrong
  1092. # for code like
  1093. # while j >= pos:
  1094. # dest[i].shallowCopy(dest[j])
  1095. # See bug #5933. So we try to be more compatible with the C backend semantics
  1096. # here for 'shallowCopy'. This is an educated guess and might require further
  1097. # changes later:
  1098. let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyString}
  1099. genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy)
  1100. proc genSwap(p: PProc, n: PNode) =
  1101. var a, b: TCompRes
  1102. gen(p, n[1], a)
  1103. gen(p, n[2], b)
  1104. var tmp = p.getTemp(false)
  1105. if mapType(p, skipTypes(n[1].typ, abstractVar)) == etyBaseIndex:
  1106. let tmp2 = p.getTemp(false)
  1107. if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
  1108. internalError(p.config, n.info, "genSwap")
  1109. lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n",
  1110. [tmp, a.address, b.address])
  1111. tmp = tmp2
  1112. lineF(p, "var $1 = $2; $2 = $3; $3 = $1;",
  1113. [tmp, a.res, b.res])
  1114. proc getFieldPosition(p: PProc; f: PNode): int =
  1115. case f.kind
  1116. of nkIntLit..nkUInt64Lit: result = int(f.intVal)
  1117. of nkSym: result = f.sym.position
  1118. else: internalError(p.config, f.info, "genFieldPosition")
  1119. proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
  1120. var a: TCompRes
  1121. r.typ = etyBaseIndex
  1122. let b = if n.kind == nkHiddenAddr: n[0] else: n
  1123. gen(p, b[0], a)
  1124. if skipTypes(b[0].typ, abstractVarRange).kind == tyTuple:
  1125. r.res = makeJSString("Field" & $getFieldPosition(p, b[1]))
  1126. else:
  1127. if b[1].kind != nkSym: internalError(p.config, b[1].info, "genFieldAddr")
  1128. var f = b[1].sym
  1129. if f.loc.r == "": f.loc.r = mangleName(p.module, f)
  1130. r.res = makeJSString($f.loc.r)
  1131. internalAssert p.config, a.typ != etyBaseIndex
  1132. r.address = a.res
  1133. r.kind = resExpr
  1134. proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
  1135. gen(p, n[0], r)
  1136. r.typ = mapType(n.typ)
  1137. let otyp = skipTypes(n[0].typ, abstractVarRange)
  1138. template mkTemp(i: int) =
  1139. if r.typ == etyBaseIndex:
  1140. if needsTemp(p, n[i]):
  1141. let tmp = p.getTemp
  1142. r.address = "($1 = $2, $1)[0]" % [tmp, r.res]
  1143. r.res = "$1[1]" % [tmp]
  1144. r.tmpLoc = tmp
  1145. else:
  1146. r.address = "$1[0]" % [r.res]
  1147. r.res = "$1[1]" % [r.res]
  1148. if otyp.kind == tyTuple:
  1149. r.res = ("$1.Field$2") %
  1150. [r.res, getFieldPosition(p, n[1]).rope]
  1151. mkTemp(0)
  1152. else:
  1153. if n[1].kind != nkSym: internalError(p.config, n[1].info, "genFieldAccess")
  1154. var f = n[1].sym
  1155. if f.loc.r == "": f.loc.r = mangleName(p.module, f)
  1156. r.res = "$1.$2" % [r.res, f.loc.r]
  1157. mkTemp(1)
  1158. r.kind = resExpr
  1159. proc genAddr(p: PProc, n: PNode, r: var TCompRes)
  1160. proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
  1161. internalAssert p.config, n.kind == nkCheckedFieldExpr
  1162. # nkDotExpr to access the requested field
  1163. let accessExpr = n[0]
  1164. # nkCall to check if the discriminant is valid
  1165. var checkExpr = n[1]
  1166. let negCheck = checkExpr[0].sym.magic == mNot
  1167. if negCheck:
  1168. checkExpr = checkExpr[^1]
  1169. # Field symbol
  1170. var field = accessExpr[1].sym
  1171. internalAssert p.config, field.kind == skField
  1172. if field.loc.r == "": field.loc.r = mangleName(p.module, field)
  1173. # Discriminant symbol
  1174. let disc = checkExpr[2].sym
  1175. internalAssert p.config, disc.kind == skField
  1176. if disc.loc.r == "": disc.loc.r = mangleName(p.module, disc)
  1177. var setx: TCompRes
  1178. gen(p, checkExpr[1], setx)
  1179. var obj: TCompRes
  1180. gen(p, accessExpr[0], obj)
  1181. # Avoid evaluating the LHS twice (one to read the discriminant and one to read
  1182. # the field)
  1183. let tmp = p.getTemp()
  1184. lineF(p, "var $1 = $2;$n", tmp, obj.res)
  1185. useMagic(p, "raiseFieldError2")
  1186. useMagic(p, "makeNimstrLit")
  1187. useMagic(p, "reprDiscriminant") # no need to offset by firstOrd unlike for cgen
  1188. let msg = genFieldDefect(p.config, field.name.s, disc)
  1189. lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError2(makeNimstrLit($5), reprDiscriminant($2.$3, $6)); }$n",
  1190. setx.res, tmp, disc.loc.r, if negCheck: "!==" else: "===",
  1191. makeJSString(msg), genTypeInfo(p, disc.typ))
  1192. if addrTyp != nil and mapType(p, addrTyp) == etyBaseIndex:
  1193. r.typ = etyBaseIndex
  1194. r.res = makeJSString($field.loc.r)
  1195. r.address = tmp
  1196. else:
  1197. r.typ = etyNone
  1198. r.res = "$1.$2" % [tmp, field.loc.r]
  1199. r.kind = resExpr
  1200. proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
  1201. var
  1202. a, b: TCompRes
  1203. first: Int128
  1204. r.typ = etyBaseIndex
  1205. let m = if n.kind == nkHiddenAddr: n[0] else: n
  1206. gen(p, m[0], a)
  1207. gen(p, m[1], b)
  1208. #internalAssert p.config, a.typ != etyBaseIndex and b.typ != etyBaseIndex
  1209. let (x, tmp) = maybeMakeTemp(p, m[0], a)
  1210. r.address = x
  1211. var typ = skipTypes(m[0].typ, abstractPtrs)
  1212. if typ.kind == tyArray:
  1213. first = firstOrd(p.config, typ[0])
  1214. if optBoundsCheck in p.options:
  1215. useMagic(p, "chckIndx")
  1216. if first == 0: # save a couple chars
  1217. r.res = "chckIndx($1, 0, ($2).length - 1)" % [b.res, tmp]
  1218. else:
  1219. r.res = "chckIndx($1, $2, ($3).length + ($2) - 1) - ($2)" % [
  1220. b.res, rope(first), tmp]
  1221. elif first != 0:
  1222. r.res = "($1) - ($2)" % [b.res, rope(first)]
  1223. else:
  1224. r.res = b.res
  1225. r.kind = resExpr
  1226. proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
  1227. var ty = skipTypes(n[0].typ, abstractVarRange)
  1228. if ty.kind in {tyRef, tyPtr, tyLent, tyOwned}: ty = skipTypes(ty.lastSon, abstractVarRange)
  1229. case ty.kind
  1230. of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs:
  1231. genArrayAddr(p, n, r)
  1232. of tyTuple:
  1233. genFieldAddr(p, n, r)
  1234. else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
  1235. r.typ = mapType(n.typ)
  1236. if r.res == "": internalError(p.config, n.info, "genArrayAccess")
  1237. if ty.kind == tyCstring:
  1238. r.res = "$1.charCodeAt($2)" % [r.address, r.res]
  1239. elif r.typ == etyBaseIndex:
  1240. if needsTemp(p, n[0]):
  1241. let tmp = p.getTemp
  1242. r.address = "($1 = $2, $1)[0]" % [tmp, r.rdLoc]
  1243. r.res = "$1[1]" % [tmp]
  1244. r.tmpLoc = tmp
  1245. else:
  1246. let x = r.rdLoc
  1247. r.address = "$1[0]" % [x]
  1248. r.res = "$1[1]" % [x]
  1249. else:
  1250. r.res = "$1[$2]" % [r.address, r.res]
  1251. r.kind = resExpr
  1252. template isIndirect(x: PSym): bool =
  1253. let v = x
  1254. ({sfAddrTaken, sfGlobal} * v.flags != {} and
  1255. #(mapType(v.typ) != etyObject) and
  1256. {sfImportc, sfExportc} * v.flags == {} and
  1257. v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
  1258. skConst, skTemp, skLet})
  1259. proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
  1260. let s = n.sym
  1261. if s.loc.r == "": internalError(p.config, n.info, "genAddr: 3")
  1262. case s.kind
  1263. of skParam:
  1264. r.res = s.loc.r
  1265. r.address = ""
  1266. r.typ = etyNone
  1267. of skVar, skLet, skResult:
  1268. r.kind = resExpr
  1269. let jsType = mapType(p):
  1270. if typ.isNil:
  1271. n.typ
  1272. else:
  1273. typ
  1274. if jsType == etyObject:
  1275. # make addr() a no-op:
  1276. r.typ = etyNone
  1277. if isIndirect(s):
  1278. r.res = s.loc.r & "[0]"
  1279. else:
  1280. r.res = s.loc.r
  1281. r.address = ""
  1282. elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
  1283. # for ease of code generation, we do not distinguish between
  1284. # sfAddrTaken and sfGlobal.
  1285. r.typ = etyBaseIndex
  1286. r.address = s.loc.r
  1287. r.res = rope("0")
  1288. else:
  1289. # 'var openArray' for instance produces an 'addr' but this is harmless:
  1290. gen(p, n, r)
  1291. #internalError(p.config, n.info, "genAddr: 4 " & renderTree(n))
  1292. else: internalError(p.config, n.info, $("genAddr: 2", s.kind))
  1293. proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
  1294. if n.kind == nkSym:
  1295. genSymAddr(p, n, nil, r)
  1296. else:
  1297. case n[0].kind
  1298. of nkSym:
  1299. genSymAddr(p, n[0], n.typ, r)
  1300. of nkCheckedFieldExpr:
  1301. genCheckedFieldOp(p, n[0], n.typ, r)
  1302. of nkDotExpr:
  1303. if mapType(p, n.typ) == etyBaseIndex:
  1304. genFieldAddr(p, n[0], r)
  1305. else:
  1306. genFieldAccess(p, n[0], r)
  1307. of nkBracketExpr:
  1308. var ty = skipTypes(n[0].typ, abstractVarRange)
  1309. if ty.kind in MappedToObject:
  1310. gen(p, n[0], r)
  1311. else:
  1312. let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind
  1313. case kindOfIndexedExpr
  1314. of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs:
  1315. genArrayAddr(p, n[0], r)
  1316. of tyTuple:
  1317. genFieldAddr(p, n[0], r)
  1318. of tyGenericBody:
  1319. genAddr(p, n[^1], r)
  1320. else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
  1321. of nkObjDownConv:
  1322. gen(p, n[0], r)
  1323. of nkHiddenDeref:
  1324. gen(p, n[0], r)
  1325. of nkHiddenAddr:
  1326. gen(p, n[0], r)
  1327. of nkConv:
  1328. genAddr(p, n[0], r)
  1329. of nkStmtListExpr:
  1330. if n.len == 1: gen(p, n[0], r)
  1331. else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr")
  1332. of nkCallKinds:
  1333. if n[0].typ.kind == tyOpenArray:
  1334. # 'var openArray' for instance produces an 'addr' but this is harmless:
  1335. # namely toOpenArray(a, 1, 3)
  1336. gen(p, n[0], r)
  1337. else:
  1338. internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
  1339. else:
  1340. internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
  1341. proc attachProc(p: PProc; content: Rope; s: PSym) =
  1342. p.g.code.add(content)
  1343. proc attachProc(p: PProc; s: PSym) =
  1344. let newp = genProc(p, s)
  1345. attachProc(p, newp, s)
  1346. proc genProcForSymIfNeeded(p: PProc, s: PSym) =
  1347. if not p.g.generatedSyms.containsOrIncl(s.id):
  1348. let newp = genProc(p, s)
  1349. var owner = p
  1350. while owner != nil and owner.prc != s.owner:
  1351. owner = owner.up
  1352. if owner != nil: owner.locals.add(newp)
  1353. else: attachProc(p, newp, s)
  1354. proc genCopyForParamIfNeeded(p: PProc, n: PNode) =
  1355. let s = n.sym
  1356. if p.prc == s.owner or needsNoCopy(p, n):
  1357. return
  1358. var owner = p.up
  1359. while true:
  1360. if owner == nil:
  1361. internalError(p.config, n.info, "couldn't find the owner proc of the closed over param: " & s.name.s)
  1362. if owner.prc == s.owner:
  1363. if not owner.generatedParamCopies.containsOrIncl(s.id):
  1364. let copy = "$1 = nimCopy(null, $1, $2);$n" % [s.loc.r, genTypeInfo(p, s.typ)]
  1365. owner.locals.add(owner.indentLine(copy))
  1366. return
  1367. owner = owner.up
  1368. proc genVarInit(p: PProc, v: PSym, n: PNode)
  1369. proc genSym(p: PProc, n: PNode, r: var TCompRes) =
  1370. var s = n.sym
  1371. case s.kind
  1372. of skVar, skLet, skParam, skTemp, skResult, skForVar:
  1373. if s.loc.r == "":
  1374. internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
  1375. if sfCompileTime in s.flags:
  1376. genVarInit(p, s, if s.astdef != nil: s.astdef else: newNodeI(nkEmpty, s.info))
  1377. if s.kind == skParam:
  1378. genCopyForParamIfNeeded(p, n)
  1379. let k = mapType(p, s.typ)
  1380. if k == etyBaseIndex:
  1381. r.typ = etyBaseIndex
  1382. if {sfAddrTaken, sfGlobal} * s.flags != {}:
  1383. if isIndirect(s):
  1384. r.address = "$1[0][0]" % [s.loc.r]
  1385. r.res = "$1[0][1]" % [s.loc.r]
  1386. else:
  1387. r.address = "$1[0]" % [s.loc.r]
  1388. r.res = "$1[1]" % [s.loc.r]
  1389. else:
  1390. r.address = s.loc.r
  1391. r.res = s.loc.r & "_Idx"
  1392. elif isIndirect(s):
  1393. r.res = "$1[0]" % [s.loc.r]
  1394. else:
  1395. r.res = s.loc.r
  1396. of skConst:
  1397. genConstant(p, s)
  1398. if s.loc.r == "":
  1399. internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
  1400. r.res = s.loc.r
  1401. of skProc, skFunc, skConverter, skMethod:
  1402. if sfCompileTime in s.flags:
  1403. localError(p.config, n.info, "request to generate code for .compileTime proc: " &
  1404. s.name.s)
  1405. discard mangleName(p.module, s)
  1406. r.res = s.loc.r
  1407. if lfNoDecl in s.loc.flags or s.magic notin generatedMagics or
  1408. {sfImportc, sfInfixCall} * s.flags != {}:
  1409. discard
  1410. elif s.kind == skMethod and getBody(p.module.graph, s).kind == nkEmpty:
  1411. # we cannot produce code for the dispatcher yet:
  1412. discard
  1413. elif sfForward in s.flags:
  1414. p.g.forwarded.add(s)
  1415. else:
  1416. genProcForSymIfNeeded(p, s)
  1417. else:
  1418. if s.loc.r == "":
  1419. internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
  1420. if mapType(p, s.typ) == etyBaseIndex:
  1421. r.address = s.loc.r
  1422. r.res = s.loc.r & "_Idx"
  1423. else:
  1424. r.res = s.loc.r
  1425. r.kind = resVal
  1426. proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
  1427. let it = n[0]
  1428. let t = mapType(p, it.typ)
  1429. if t == etyObject or it.typ.kind == tyLent:
  1430. gen(p, it, r)
  1431. else:
  1432. var a: TCompRes
  1433. gen(p, it, a)
  1434. r.kind = a.kind
  1435. r.typ = mapType(p, n.typ)
  1436. if r.typ == etyBaseIndex:
  1437. let tmp = p.getTemp
  1438. r.address = "($1 = $2, $1)[0]" % [tmp, a.rdLoc]
  1439. r.res = "$1[1]" % [tmp]
  1440. r.tmpLoc = tmp
  1441. elif a.typ == etyBaseIndex:
  1442. if a.tmpLoc != "":
  1443. r.tmpLoc = a.tmpLoc
  1444. r.res = a.rdLoc
  1445. else:
  1446. internalError(p.config, n.info, "genDeref")
  1447. proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
  1448. var a: TCompRes
  1449. gen(p, n, a)
  1450. if a.typ == etyBaseIndex:
  1451. r.res.add(a.address)
  1452. r.res.add(", ")
  1453. r.res.add(a.res)
  1454. else:
  1455. r.res.add(a.res)
  1456. proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes; emitted: ptr int = nil) =
  1457. var a: TCompRes
  1458. gen(p, n, a)
  1459. if skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
  1460. a.typ == etyBaseIndex:
  1461. r.res.add("$1[$2]" % [a.address, a.res])
  1462. elif a.typ == etyBaseIndex:
  1463. r.res.add(a.address)
  1464. r.res.add(", ")
  1465. r.res.add(a.res)
  1466. if emitted != nil: inc emitted[]
  1467. elif n.typ.kind in {tyVar, tyPtr, tyRef, tyLent, tyOwned} and
  1468. n.kind in nkCallKinds and mapType(param.typ) == etyBaseIndex:
  1469. # this fixes bug #5608:
  1470. let tmp = getTemp(p)
  1471. r.res.add("($1 = $2, $1[0]), $1[1]" % [tmp, a.rdLoc])
  1472. if emitted != nil: inc emitted[]
  1473. else:
  1474. r.res.add(a.res)
  1475. proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) =
  1476. r.res.add("(")
  1477. var hasArgs = false
  1478. var typ = skipTypes(n[0].typ, abstractInst)
  1479. assert(typ.kind == tyProc)
  1480. assert(typ.len == typ.n.len)
  1481. var emitted = start-1
  1482. for i in start..<n.len:
  1483. let it = n[i]
  1484. var paramType: PNode = nil
  1485. if i < typ.len:
  1486. assert(typ.n[i].kind == nkSym)
  1487. paramType = typ.n[i]
  1488. if paramType.typ.isCompileTimeOnly: continue
  1489. if hasArgs: r.res.add(", ")
  1490. if paramType.isNil:
  1491. genArgNoParam(p, it, r)
  1492. else:
  1493. genArg(p, it, paramType.sym, r, addr emitted)
  1494. inc emitted
  1495. hasArgs = true
  1496. r.res.add(")")
  1497. when false:
  1498. # XXX look into this:
  1499. let jsp = countJsParams(typ)
  1500. if emitted != jsp and tfVarargs notin typ.flags:
  1501. localError(p.config, n.info, "wrong number of parameters emitted; expected: " & $jsp &
  1502. " but got: " & $emitted)
  1503. r.kind = resExpr
  1504. proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
  1505. generated: var int; r: var TCompRes) =
  1506. if i >= n.len:
  1507. globalError(p.config, n.info, "wrong importcpp pattern; expected parameter at position " & $i &
  1508. " but got only: " & $(n.len-1))
  1509. let it = n[i]
  1510. var paramType: PNode = nil
  1511. if i < typ.len:
  1512. assert(typ.n[i].kind == nkSym)
  1513. paramType = typ.n[i]
  1514. if paramType.typ.isCompileTimeOnly: return
  1515. if paramType.isNil:
  1516. genArgNoParam(p, it, r)
  1517. else:
  1518. genArg(p, it, paramType.sym, r)
  1519. inc generated
  1520. proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
  1521. r: var TCompRes) =
  1522. var i = 0
  1523. var j = 1
  1524. r.kind = resExpr
  1525. while i < pat.len:
  1526. case pat[i]
  1527. of '@':
  1528. var generated = 0
  1529. for k in j..<n.len:
  1530. if generated > 0: r.res.add(", ")
  1531. genOtherArg(p, n, k, typ, generated, r)
  1532. inc i
  1533. of '#':
  1534. var generated = 0
  1535. genOtherArg(p, n, j, typ, generated, r)
  1536. inc j
  1537. inc i
  1538. of '\31':
  1539. # unit separator
  1540. r.res.add("#")
  1541. inc i
  1542. of '\29':
  1543. # group separator
  1544. r.res.add("@")
  1545. inc i
  1546. else:
  1547. let start = i
  1548. while i < pat.len:
  1549. if pat[i] notin {'@', '#', '\31', '\29'}: inc(i)
  1550. else: break
  1551. if i - 1 >= start:
  1552. r.res.add(substr(pat, start, i - 1))
  1553. proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
  1554. # don't call '$' here for efficiency:
  1555. let f = n[0].sym
  1556. if f.loc.r == "": f.loc.r = mangleName(p.module, f)
  1557. if sfInfixCall in f.flags:
  1558. let pat = $n[0].sym.loc.r
  1559. internalAssert p.config, pat.len > 0
  1560. if pat.contains({'#', '(', '@'}):
  1561. var typ = skipTypes(n[0].typ, abstractInst)
  1562. assert(typ.kind == tyProc)
  1563. genPatternCall(p, n, pat, typ, r)
  1564. return
  1565. if n.len != 1:
  1566. gen(p, n[1], r)
  1567. if r.typ == etyBaseIndex:
  1568. if r.address == "":
  1569. globalError(p.config, n.info, "cannot invoke with infix syntax")
  1570. r.res = "$1[$2]" % [r.address, r.res]
  1571. r.address = ""
  1572. r.typ = etyNone
  1573. r.res.add(".")
  1574. var op: TCompRes
  1575. gen(p, n[0], op)
  1576. r.res.add(op.res)
  1577. genArgs(p, n, r, 2)
  1578. proc genCall(p: PProc, n: PNode, r: var TCompRes) =
  1579. gen(p, n[0], r)
  1580. genArgs(p, n, r)
  1581. if n.typ != nil:
  1582. let t = mapType(n.typ)
  1583. if t == etyBaseIndex:
  1584. let tmp = p.getTemp
  1585. r.address = "($1 = $2, $1)[0]" % [tmp, r.rdLoc]
  1586. r.res = "$1[1]" % [tmp]
  1587. r.tmpLoc = tmp
  1588. r.typ = t
  1589. proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
  1590. let n = n[1].skipConv
  1591. internalAssert p.config, n.kind == nkBracket
  1592. useMagic(p, "toJSStr") # Used in rawEcho
  1593. useMagic(p, "rawEcho")
  1594. r.res.add("rawEcho(")
  1595. for i in 0..<n.len:
  1596. let it = n[i]
  1597. if it.typ.isCompileTimeOnly: continue
  1598. if i > 0: r.res.add(", ")
  1599. genArgNoParam(p, it, r)
  1600. r.res.add(")")
  1601. r.kind = resExpr
  1602. proc putToSeq(s: string, indirect: bool): Rope =
  1603. result = rope(s)
  1604. if indirect: result = "[$1]" % [result]
  1605. proc createVar(p: PProc, typ: PType, indirect: bool): Rope
  1606. proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output: var Rope) =
  1607. case rec.kind
  1608. of nkRecList:
  1609. for i in 0..<rec.len:
  1610. createRecordVarAux(p, rec[i], excludedFieldIDs, output)
  1611. of nkRecCase:
  1612. createRecordVarAux(p, rec[0], excludedFieldIDs, output)
  1613. for i in 1..<rec.len:
  1614. createRecordVarAux(p, lastSon(rec[i]), excludedFieldIDs, output)
  1615. of nkSym:
  1616. # Do not produce code for void types
  1617. if isEmptyType(rec.sym.typ): return
  1618. if rec.sym.id notin excludedFieldIDs:
  1619. if output.len > 0: output.add(", ")
  1620. output.addf("$#: ", [mangleName(p.module, rec.sym)])
  1621. output.add(createVar(p, rec.sym.typ, false))
  1622. else: internalError(p.config, rec.info, "createRecordVarAux")
  1623. proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: var Rope) =
  1624. var t = typ
  1625. if objHasTypeField(t):
  1626. if output.len > 0: output.add(", ")
  1627. output.addf("m_type: $1", [genTypeInfo(p, t)])
  1628. while t != nil:
  1629. t = t.skipTypes(skipPtrs)
  1630. createRecordVarAux(p, t.n, excludedFieldIDs, output)
  1631. t = t[0]
  1632. proc arrayTypeForElemType(typ: PType): string =
  1633. let typ = typ.skipTypes(abstractRange)
  1634. case typ.kind
  1635. of tyInt, tyInt32: "Int32Array"
  1636. of tyInt16: "Int16Array"
  1637. of tyInt8: "Int8Array"
  1638. of tyUInt, tyUInt32: "Uint32Array"
  1639. of tyUInt16: "Uint16Array"
  1640. of tyUInt8, tyChar, tyBool: "Uint8Array"
  1641. of tyFloat32: "Float32Array"
  1642. of tyFloat64, tyFloat: "Float64Array"
  1643. of tyEnum:
  1644. case typ.size
  1645. of 1: "Uint8Array"
  1646. of 2: "Uint16Array"
  1647. of 4: "Uint32Array"
  1648. else: ""
  1649. else: ""
  1650. proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
  1651. var t = skipTypes(typ, abstractInst)
  1652. case t.kind
  1653. of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar:
  1654. if $t.sym.loc.r == "bigint":
  1655. result = putToSeq("0n", indirect)
  1656. else:
  1657. result = putToSeq("0", indirect)
  1658. of tyFloat..tyFloat128:
  1659. result = putToSeq("0.0", indirect)
  1660. of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent:
  1661. result = createVar(p, lastSon(typ), indirect)
  1662. of tySet:
  1663. result = putToSeq("{}", indirect)
  1664. of tyBool:
  1665. result = putToSeq("false", indirect)
  1666. of tyNil:
  1667. result = putToSeq("null", indirect)
  1668. of tyArray:
  1669. let length = toInt(lengthOrd(p.config, t))
  1670. let e = elemType(t)
  1671. let jsTyp = arrayTypeForElemType(e)
  1672. if jsTyp.len > 0:
  1673. result = "new $1($2)" % [rope(jsTyp), rope(length)]
  1674. elif length > 32:
  1675. useMagic(p, "arrayConstr")
  1676. # XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary.
  1677. useMagic(p, "nimCopy")
  1678. result = "arrayConstr($1, $2, $3)" % [rope(length),
  1679. createVar(p, e, false), genTypeInfo(p, e)]
  1680. else:
  1681. result = rope("[")
  1682. var i = 0
  1683. while i < length:
  1684. if i > 0: result.add(", ")
  1685. result.add(createVar(p, e, false))
  1686. inc(i)
  1687. result.add("]")
  1688. if indirect: result = "[$1]" % [result]
  1689. of tyTuple:
  1690. result = rope("{")
  1691. for i in 0..<t.len:
  1692. if i > 0: result.add(", ")
  1693. result.addf("Field$1: $2", [i.rope,
  1694. createVar(p, t[i], false)])
  1695. result.add("}")
  1696. if indirect: result = "[$1]" % [result]
  1697. of tyObject:
  1698. var initList: Rope
  1699. createObjInitList(p, t, initIntSet(), initList)
  1700. result = ("({$1})") % [initList]
  1701. if indirect: result = "[$1]" % [result]
  1702. of tyVar, tyPtr, tyRef, tyPointer:
  1703. if mapType(p, t) == etyBaseIndex:
  1704. result = putToSeq("[null, 0]", indirect)
  1705. else:
  1706. result = putToSeq("null", indirect)
  1707. of tySequence, tyString:
  1708. result = putToSeq("[]", indirect)
  1709. of tyCstring, tyProc:
  1710. result = putToSeq("null", indirect)
  1711. of tyStatic:
  1712. if t.n != nil:
  1713. result = createVar(p, lastSon t, indirect)
  1714. else:
  1715. internalError(p.config, "createVar: " & $t.kind)
  1716. result = ""
  1717. else:
  1718. internalError(p.config, "createVar: " & $t.kind)
  1719. result = ""
  1720. template returnType: untyped = ""
  1721. proc genVarInit(p: PProc, v: PSym, n: PNode) =
  1722. var
  1723. a: TCompRes
  1724. s: Rope
  1725. varCode: string
  1726. varName = mangleName(p.module, v)
  1727. useReloadingGuard = sfGlobal in v.flags and p.config.hcrOn
  1728. useGlobalPragmas = sfGlobal in v.flags and ({sfPure, sfThread} * v.flags != {})
  1729. if v.constraint.isNil:
  1730. if useReloadingGuard:
  1731. lineF(p, "var $1;$n", varName)
  1732. lineF(p, "if ($1 === undefined) {$n", varName)
  1733. varCode = $varName
  1734. inc p.extraIndent
  1735. elif useGlobalPragmas:
  1736. lineF(p, "if (globalThis.$1 === undefined) {$n", varName)
  1737. varCode = "globalThis." & $varName
  1738. inc p.extraIndent
  1739. else:
  1740. varCode = "var $2"
  1741. else:
  1742. # Is this really a thought through feature? this basically unused
  1743. # feature makes it impossible for almost all format strings in
  1744. # this function to be checked at compile time.
  1745. varCode = v.constraint.strVal
  1746. if n.kind == nkEmpty:
  1747. if not isIndirect(v) and
  1748. v.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and mapType(p, v.typ) == etyBaseIndex:
  1749. lineF(p, "var $1 = null;$n", [varName])
  1750. lineF(p, "var $1_Idx = 0;$n", [varName])
  1751. else:
  1752. line(p, runtimeFormat(varCode & " = $3;$n", [returnType, varName, createVar(p, v.typ, isIndirect(v))]))
  1753. else:
  1754. gen(p, n, a)
  1755. case mapType(p, v.typ)
  1756. of etyObject, etySeq:
  1757. if needsNoCopy(p, n):
  1758. s = a.res
  1759. else:
  1760. useMagic(p, "nimCopy")
  1761. s = "nimCopy(null, $1, $2)" % [a.res, genTypeInfo(p, n.typ)]
  1762. of etyBaseIndex:
  1763. let targetBaseIndex = {sfAddrTaken, sfGlobal} * v.flags == {}
  1764. if a.typ == etyBaseIndex:
  1765. if targetBaseIndex:
  1766. line(p, runtimeFormat(varCode & " = $3, $2_Idx = $4;$n",
  1767. [returnType, v.loc.r, a.address, a.res]))
  1768. else:
  1769. if isIndirect(v):
  1770. line(p, runtimeFormat(varCode & " = [[$3, $4]];$n",
  1771. [returnType, v.loc.r, a.address, a.res]))
  1772. else:
  1773. line(p, runtimeFormat(varCode & " = [$3, $4];$n",
  1774. [returnType, v.loc.r, a.address, a.res]))
  1775. else:
  1776. if targetBaseIndex:
  1777. let tmp = p.getTemp
  1778. lineF(p, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
  1779. [tmp, a.res, v.loc.r])
  1780. else:
  1781. line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.r, a.res]))
  1782. return
  1783. else:
  1784. s = a.res
  1785. if isIndirect(v):
  1786. line(p, runtimeFormat(varCode & " = [$3];$n", [returnType, v.loc.r, s]))
  1787. else:
  1788. line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.r, s]))
  1789. if useReloadingGuard or useGlobalPragmas:
  1790. dec p.extraIndent
  1791. lineF(p, "}$n")
  1792. proc genVarStmt(p: PProc, n: PNode) =
  1793. for i in 0..<n.len:
  1794. var a = n[i]
  1795. if a.kind != nkCommentStmt:
  1796. if a.kind == nkVarTuple:
  1797. let unpacked = lowerTupleUnpacking(p.module.graph, a, p.module.idgen, p.prc)
  1798. genStmt(p, unpacked)
  1799. else:
  1800. assert(a.kind == nkIdentDefs)
  1801. assert(a[0].kind == nkSym)
  1802. var v = a[0].sym
  1803. if lfNoDecl notin v.loc.flags and sfImportc notin v.flags:
  1804. genLineDir(p, a)
  1805. if sfCompileTime notin v.flags:
  1806. genVarInit(p, v, a[2])
  1807. else:
  1808. # lazy emit, done when it's actually used.
  1809. if v.ast == nil: v.ast = a[2]
  1810. proc genConstant(p: PProc, c: PSym) =
  1811. if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
  1812. let oldBody = move p.body
  1813. #genLineDir(p, c.astdef)
  1814. genVarInit(p, c, c.astdef)
  1815. p.g.constants.add(p.body)
  1816. p.body = oldBody
  1817. proc genNew(p: PProc, n: PNode) =
  1818. var a: TCompRes
  1819. gen(p, n[1], a)
  1820. var t = skipTypes(n[1].typ, abstractVar)[0]
  1821. if mapType(t) == etyObject:
  1822. lineF(p, "$1 = $2;$n", [a.rdLoc, createVar(p, t, false)])
  1823. elif a.typ == etyBaseIndex:
  1824. lineF(p, "$1 = [$3]; $2 = 0;$n", [a.address, a.res, createVar(p, t, false)])
  1825. else:
  1826. lineF(p, "$1 = [[$2], 0];$n", [a.rdLoc, createVar(p, t, false)])
  1827. proc genNewSeq(p: PProc, n: PNode) =
  1828. var x, y: TCompRes
  1829. gen(p, n[1], x)
  1830. gen(p, n[2], y)
  1831. let t = skipTypes(n[1].typ, abstractVar)[0]
  1832. lineF(p, "$1 = new Array($2); for (var i = 0 ; i < $2 ; ++i) { $1[i] = $3; }", [
  1833. x.rdLoc, y.rdLoc, createVar(p, t, false)])
  1834. proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
  1835. case skipTypes(n[1].typ, abstractVar + abstractRange).kind
  1836. of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n[1], r)
  1837. of tyBool: unaryExpr(p, n, r, "", "($1 ? 1 : 0)")
  1838. else: internalError(p.config, n.info, "genOrd")
  1839. proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
  1840. var a: TCompRes
  1841. gen(p, n[1], a)
  1842. r.kind = resExpr
  1843. if skipTypes(n[1].typ, abstractVarRange).kind == tyChar:
  1844. r.res.add("[$1].concat(" % [a.res])
  1845. else:
  1846. r.res.add("($1 || []).concat(" % [a.res])
  1847. for i in 2..<n.len - 1:
  1848. gen(p, n[i], a)
  1849. if skipTypes(n[i].typ, abstractVarRange).kind == tyChar:
  1850. r.res.add("[$1]," % [a.res])
  1851. else:
  1852. r.res.add("$1 || []," % [a.res])
  1853. gen(p, n[^1], a)
  1854. if skipTypes(n[^1].typ, abstractVarRange).kind == tyChar:
  1855. r.res.add("[$1])" % [a.res])
  1856. else:
  1857. r.res.add("$1 || [])" % [a.res])
  1858. proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = "") =
  1859. useMagic(p, magic)
  1860. r.res.add(magic & "(")
  1861. var a: TCompRes
  1862. gen(p, n[1], a)
  1863. if magic == "reprAny":
  1864. # the pointer argument in reprAny is expandend to
  1865. # (pointedto, pointer), so we need to fill it
  1866. if a.address.len == 0:
  1867. r.res.add(a.res)
  1868. r.res.add(", null")
  1869. else:
  1870. r.res.add("$1, $2" % [a.address, a.res])
  1871. else:
  1872. r.res.add(a.res)
  1873. if typ != "":
  1874. r.res.add(", ")
  1875. r.res.add(typ)
  1876. r.res.add(")")
  1877. proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
  1878. let t = skipTypes(n[1].typ, abstractVarRange)
  1879. case t.kind
  1880. of tyInt..tyInt64, tyUInt..tyUInt64:
  1881. genReprAux(p, n, r, "reprInt")
  1882. of tyChar:
  1883. genReprAux(p, n, r, "reprChar")
  1884. of tyBool:
  1885. genReprAux(p, n, r, "reprBool")
  1886. of tyFloat..tyFloat128:
  1887. genReprAux(p, n, r, "reprFloat")
  1888. of tyString:
  1889. genReprAux(p, n, r, "reprStr")
  1890. of tyEnum, tyOrdinal:
  1891. genReprAux(p, n, r, "reprEnum", genTypeInfo(p, t))
  1892. of tySet:
  1893. genReprAux(p, n, r, "reprSet", genTypeInfo(p, t))
  1894. of tyEmpty, tyVoid:
  1895. localError(p.config, n.info, "'repr' doesn't support 'void' type")
  1896. of tyPointer:
  1897. genReprAux(p, n, r, "reprPointer")
  1898. of tyOpenArray, tyVarargs:
  1899. genReprAux(p, n, r, "reprJSONStringify")
  1900. else:
  1901. genReprAux(p, n, r, "reprAny", genTypeInfo(p, t))
  1902. r.kind = resExpr
  1903. proc genOf(p: PProc, n: PNode, r: var TCompRes) =
  1904. var x: TCompRes
  1905. let t = skipTypes(n[2].typ,
  1906. abstractVarRange+{tyRef, tyPtr, tyLent, tyTypeDesc, tyOwned})
  1907. gen(p, n[1], x)
  1908. if tfFinal in t.flags:
  1909. r.res = "($1.m_type == $2)" % [x.res, genTypeInfo(p, t)]
  1910. else:
  1911. useMagic(p, "isObj")
  1912. r.res = "isObj($1.m_type, $2)" % [x.res, genTypeInfo(p, t)]
  1913. r.kind = resExpr
  1914. proc genDefault(p: PProc, n: PNode; r: var TCompRes) =
  1915. r.res = createVar(p, n.typ, indirect = false)
  1916. r.kind = resExpr
  1917. proc genReset(p: PProc, n: PNode) =
  1918. var x: TCompRes
  1919. useMagic(p, "genericReset")
  1920. gen(p, n[1], x)
  1921. if x.typ == etyBaseIndex:
  1922. lineF(p, "$1 = null, $2 = 0;$n", [x.address, x.res])
  1923. else:
  1924. let (a, tmp) = maybeMakeTempAssignable(p, n[1], x)
  1925. lineF(p, "$1 = genericReset($3, $2);$n", [a,
  1926. genTypeInfo(p, n[1].typ), tmp])
  1927. proc genMove(p: PProc; n: PNode; r: var TCompRes) =
  1928. var a: TCompRes
  1929. r.kind = resVal
  1930. r.res = p.getTemp()
  1931. gen(p, n[1], a)
  1932. lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc])
  1933. genReset(p, n)
  1934. #lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
  1935. proc genJSArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
  1936. var a: TCompRes
  1937. r.res = rope("[")
  1938. r.kind = resExpr
  1939. for i in 0 ..< n.len:
  1940. if i > 0: r.res.add(", ")
  1941. gen(p, n[i], a)
  1942. if a.typ == etyBaseIndex:
  1943. r.res.addf("[$1, $2]", [a.address, a.res])
  1944. else:
  1945. if not needsNoCopy(p, n[i]):
  1946. let typ = n[i].typ.skipTypes(abstractInst)
  1947. useMagic(p, "nimCopy")
  1948. a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
  1949. r.res.add(a.res)
  1950. r.res.add("]")
  1951. proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
  1952. var
  1953. a: TCompRes
  1954. line, filen: Rope
  1955. var op = n[0].sym.magic
  1956. case op
  1957. of mOr: genOr(p, n[1], n[2], r)
  1958. of mAnd: genAnd(p, n[1], n[2], r)
  1959. of mAddI..mStrToStr: arith(p, n, r, op)
  1960. of mRepr: genRepr(p, n, r)
  1961. of mSwap: genSwap(p, n)
  1962. of mAppendStrCh:
  1963. binaryExpr(p, n, r, "addChar",
  1964. "addChar($1, $2);")
  1965. of mAppendStrStr:
  1966. var lhs, rhs: TCompRes
  1967. gen(p, n[1], lhs)
  1968. gen(p, n[2], rhs)
  1969. if skipTypes(n[1].typ, abstractVarRange).kind == tyCstring:
  1970. let (b, tmp) = maybeMakeTemp(p, n[2], rhs)
  1971. r.res = "if (null != $1) { if (null == $2) $2 = $3; else $2 += $3; }" %
  1972. [b, lhs.rdLoc, tmp]
  1973. else:
  1974. let (a, tmp) = maybeMakeTemp(p, n[1], lhs)
  1975. r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp]
  1976. r.kind = resExpr
  1977. of mAppendSeqElem:
  1978. var x, y: TCompRes
  1979. gen(p, n[1], x)
  1980. gen(p, n[2], y)
  1981. if mapType(n[2].typ) == etyBaseIndex:
  1982. let c = "[$1, $2]" % [y.address, y.res]
  1983. r.res = "$1.push($2);" % [x.rdLoc, c]
  1984. elif needsNoCopy(p, n[2]):
  1985. r.res = "$1.push($2);" % [x.rdLoc, y.rdLoc]
  1986. else:
  1987. useMagic(p, "nimCopy")
  1988. let c = getTemp(p, defineInLocals=false)
  1989. lineF(p, "var $1 = nimCopy(null, $2, $3);$n",
  1990. [c, y.rdLoc, genTypeInfo(p, n[2].typ)])
  1991. r.res = "$1.push($2);" % [x.rdLoc, c]
  1992. r.kind = resExpr
  1993. of mConStrStr:
  1994. genConStrStr(p, n, r)
  1995. of mEqStr:
  1996. binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
  1997. of mLeStr:
  1998. binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
  1999. of mLtStr:
  2000. binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)")
  2001. of mIsNil:
  2002. # we want to accept undefined, so we ==
  2003. if mapType(n[1].typ) != etyBaseIndex:
  2004. unaryExpr(p, n, r, "", "($1 == null)")
  2005. else:
  2006. var x: TCompRes
  2007. gen(p, n[1], x)
  2008. r.res = "($# == null && $# === 0)" % [x.address, x.res]
  2009. of mEnumToStr: genRepr(p, n, r)
  2010. of mNew, mNewFinalize: genNew(p, n)
  2011. of mChr: gen(p, n[1], r)
  2012. of mArrToSeq:
  2013. # only array literals doesn't need copy
  2014. if n[1].kind == nkBracket:
  2015. genJSArrayConstr(p, n[1], r)
  2016. else:
  2017. var x: TCompRes
  2018. gen(p, n[1], x)
  2019. useMagic(p, "nimCopy")
  2020. r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)]
  2021. of mOpenArrayToSeq:
  2022. genCall(p, n, r)
  2023. of mDestroy, mTrace: discard "ignore calls to the default destructor"
  2024. of mOrd: genOrd(p, n, r)
  2025. of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
  2026. var x: TCompRes
  2027. gen(p, n[1], x)
  2028. if skipTypes(n[1].typ, abstractInst).kind == tyCstring:
  2029. let (a, tmp) = maybeMakeTemp(p, n[1], x)
  2030. r.res = "(($1) == null ? 0 : ($2).length)" % [a, tmp]
  2031. else:
  2032. r.res = "($1).length" % [x.rdLoc]
  2033. r.kind = resExpr
  2034. of mHigh:
  2035. var x: TCompRes
  2036. gen(p, n[1], x)
  2037. if skipTypes(n[1].typ, abstractInst).kind == tyCstring:
  2038. let (a, tmp) = maybeMakeTemp(p, n[1], x)
  2039. r.res = "(($1) == null ? -1 : ($2).length - 1)" % [a, tmp]
  2040. else:
  2041. r.res = "($1).length - 1" % [x.rdLoc]
  2042. r.kind = resExpr
  2043. of mInc:
  2044. if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
  2045. binaryUintExpr(p, n, r, "+", true)
  2046. else:
  2047. if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
  2048. else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)", true)
  2049. of ast.mDec:
  2050. if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
  2051. binaryUintExpr(p, n, r, "-", true)
  2052. else:
  2053. if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
  2054. else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true)
  2055. of mSetLengthStr:
  2056. binaryExpr(p, n, r, "mnewString", "($1.length = $2)")
  2057. of mSetLengthSeq:
  2058. var x, y: TCompRes
  2059. gen(p, n[1], x)
  2060. gen(p, n[2], y)
  2061. let t = skipTypes(n[1].typ, abstractVar)[0]
  2062. let (a, tmp) = maybeMakeTemp(p, n[1], x)
  2063. let (b, tmp2) = maybeMakeTemp(p, n[2], y)
  2064. r.res = """if ($1.length < $2) { for (var i = $4.length ; i < $5 ; ++i) $4.push($3); }
  2065. else { $4.length = $5; }""" % [a, b, createVar(p, t, false), tmp, tmp2]
  2066. r.kind = resExpr
  2067. of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
  2068. of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
  2069. of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($1, $2)")
  2070. of mEqSet: binaryExpr(p, n, r, "SetEq", "SetEq($1, $2)")
  2071. of mMulSet: binaryExpr(p, n, r, "SetMul", "SetMul($1, $2)")
  2072. of mPlusSet: binaryExpr(p, n, r, "SetPlus", "SetPlus($1, $2)")
  2073. of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
  2074. of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
  2075. of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]")
  2076. of mInSet:
  2077. binaryExpr(p, n, r, "", "($1[$2] != undefined)")
  2078. of mNewSeq: genNewSeq(p, n)
  2079. of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]")
  2080. of mOf: genOf(p, n, r)
  2081. of mDefault, mZeroDefault: genDefault(p, n, r)
  2082. of mReset, mWasMoved: genReset(p, n)
  2083. of mEcho: genEcho(p, n, r)
  2084. of mNLen..mNError, mSlurp, mStaticExec:
  2085. localError(p.config, n.info, errXMustBeCompileTime % n[0].sym.name.s)
  2086. of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
  2087. of mNewStringOfCap:
  2088. unaryExpr(p, n, r, "mnewString", "mnewString(0)")
  2089. of mDotDot:
  2090. genProcForSymIfNeeded(p, n[0].sym)
  2091. genCall(p, n, r)
  2092. of mParseBiggestFloat:
  2093. useMagic(p, "nimParseBiggestFloat")
  2094. genCall(p, n, r)
  2095. of mSlice:
  2096. # arr.slice([begin[, end]]): 'end' is exclusive
  2097. var x, y, z: TCompRes
  2098. gen(p, n[1], x)
  2099. gen(p, n[2], y)
  2100. gen(p, n[3], z)
  2101. r.res = "($1.slice($2, $3 + 1))" % [x.rdLoc, y.rdLoc, z.rdLoc]
  2102. r.kind = resExpr
  2103. of mMove:
  2104. genMove(p, n, r)
  2105. else:
  2106. genCall(p, n, r)
  2107. #else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]);
  2108. proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
  2109. var
  2110. a, b: TCompRes
  2111. useMagic(p, "setConstr")
  2112. r.res = rope("setConstr(")
  2113. r.kind = resExpr
  2114. for i in 0..<n.len:
  2115. if i > 0: r.res.add(", ")
  2116. var it = n[i]
  2117. if it.kind == nkRange:
  2118. gen(p, it[0], a)
  2119. gen(p, it[1], b)
  2120. if it[0].typ.kind == tyBool:
  2121. r.res.addf("$1, $2", [a.res, b.res])
  2122. else:
  2123. r.res.addf("[$1, $2]", [a.res, b.res])
  2124. else:
  2125. gen(p, it, a)
  2126. r.res.add(a.res)
  2127. r.res.add(")")
  2128. # emit better code for constant sets:
  2129. if isDeepConstExpr(n):
  2130. inc(p.g.unique)
  2131. let tmp = rope("ConstSet") & rope(p.g.unique)
  2132. p.g.constants.addf("var $1 = $2;$n", [tmp, r.res])
  2133. r.res = tmp
  2134. proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
  2135. ## Constructs array or sequence.
  2136. ## Nim array of uint8..uint32, int8..int32 maps to JS typed arrays.
  2137. ## Nim sequence maps to JS array.
  2138. var t = skipTypes(n.typ, abstractInst)
  2139. let e = elemType(t)
  2140. let jsTyp = arrayTypeForElemType(e)
  2141. if skipTypes(n.typ, abstractVarRange).kind != tySequence and jsTyp.len > 0:
  2142. # generate typed array
  2143. # for example Nim generates `new Uint8Array([1, 2, 3])` for `[byte(1), 2, 3]`
  2144. # TODO use `set` or loop to initialize typed array which improves performances in some situations
  2145. var a: TCompRes
  2146. r.res = "new $1([" % [rope(jsTyp)]
  2147. r.kind = resExpr
  2148. for i in 0 ..< n.len:
  2149. if i > 0: r.res.add(", ")
  2150. gen(p, n[i], a)
  2151. r.res.add(a.res)
  2152. r.res.add("])")
  2153. else:
  2154. genJSArrayConstr(p, n, r)
  2155. proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
  2156. var a: TCompRes
  2157. r.res = rope("{")
  2158. r.kind = resExpr
  2159. for i in 0..<n.len:
  2160. if i > 0: r.res.add(", ")
  2161. var it = n[i]
  2162. if it.kind == nkExprColonExpr: it = it[1]
  2163. gen(p, it, a)
  2164. let typ = it.typ.skipTypes(abstractInst)
  2165. if a.typ == etyBaseIndex:
  2166. r.res.addf("Field$#: [$#, $#]", [i.rope, a.address, a.res])
  2167. else:
  2168. if not needsNoCopy(p, it):
  2169. useMagic(p, "nimCopy")
  2170. a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
  2171. r.res.addf("Field$#: $#", [i.rope, a.res])
  2172. r.res.add("}")
  2173. proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
  2174. var a: TCompRes
  2175. r.kind = resExpr
  2176. var initList : Rope
  2177. var fieldIDs = initIntSet()
  2178. let nTyp = n.typ.skipTypes(abstractInst)
  2179. for i in 1..<n.len:
  2180. if i > 1: initList.add(", ")
  2181. var it = n[i]
  2182. internalAssert p.config, it.kind == nkExprColonExpr
  2183. let val = it[1]
  2184. gen(p, val, a)
  2185. var f = it[0].sym
  2186. if f.loc.r == "": f.loc.r = mangleName(p.module, f)
  2187. fieldIDs.incl(lookupFieldAgain(n.typ.skipTypes({tyDistinct}), f).id)
  2188. let typ = val.typ.skipTypes(abstractInst)
  2189. if a.typ == etyBaseIndex:
  2190. initList.addf("$#: [$#, $#]", [f.loc.r, a.address, a.res])
  2191. else:
  2192. if not needsNoCopy(p, val):
  2193. useMagic(p, "nimCopy")
  2194. a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
  2195. initList.addf("$#: $#", [f.loc.r, a.res])
  2196. let t = skipTypes(n.typ, abstractInst + skipPtrs)
  2197. createObjInitList(p, t, fieldIDs, initList)
  2198. r.res = ("{$1}") % [initList]
  2199. proc genConv(p: PProc, n: PNode, r: var TCompRes) =
  2200. var dest = skipTypes(n.typ, abstractVarRange)
  2201. var src = skipTypes(n[1].typ, abstractVarRange)
  2202. gen(p, n[1], r)
  2203. if dest.kind == src.kind:
  2204. # no-op conversion
  2205. return
  2206. let toInt = (dest.kind in tyInt..tyInt32)
  2207. let fromInt = (src.kind in tyInt..tyInt32)
  2208. let toUint = (dest.kind in tyUInt..tyUInt32)
  2209. let fromUint = (src.kind in tyUInt..tyUInt32)
  2210. if toUint and (fromInt or fromUint):
  2211. let trimmer = unsignedTrimmer(dest.size)
  2212. r.res = "($1 $2)" % [r.res, trimmer]
  2213. elif dest.kind == tyBool:
  2214. r.res = "(!!($1))" % [r.res]
  2215. r.kind = resExpr
  2216. elif toInt:
  2217. r.res = "(($1) | 0)" % [r.res]
  2218. else:
  2219. # TODO: What types must we handle here?
  2220. discard
  2221. proc upConv(p: PProc, n: PNode, r: var TCompRes) =
  2222. gen(p, n[0], r) # XXX
  2223. proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
  2224. var a, b: TCompRes
  2225. gen(p, n[0], r)
  2226. if optRangeCheck notin p.options or (skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64} and
  2227. checkUnsignedConversions notin p.config.legacyFeatures):
  2228. discard "XXX maybe emit masking instructions here"
  2229. else:
  2230. gen(p, n[1], a)
  2231. gen(p, n[2], b)
  2232. useMagic(p, "chckRange")
  2233. r.res = "chckRange($1, $2, $3)" % [r.res, a.res, b.res]
  2234. r.kind = resExpr
  2235. proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
  2236. # we do an optimization here as this is likely to slow down
  2237. # much of the code otherwise:
  2238. if n[0].kind == nkCStringToString:
  2239. gen(p, n[0][0], r)
  2240. else:
  2241. gen(p, n[0], r)
  2242. if r.res == "": internalError(p.config, n.info, "convStrToCStr")
  2243. useMagic(p, "toJSStr")
  2244. r.res = "toJSStr($1)" % [r.res]
  2245. r.kind = resExpr
  2246. proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
  2247. # we do an optimization here as this is likely to slow down
  2248. # much of the code otherwise:
  2249. if n[0].kind == nkStringToCString:
  2250. gen(p, n[0][0], r)
  2251. else:
  2252. gen(p, n[0], r)
  2253. if r.res == "": internalError(p.config, n.info, "convCStrToStr")
  2254. useMagic(p, "cstrToNimstr")
  2255. r.res = "cstrToNimstr($1)" % [r.res]
  2256. r.kind = resExpr
  2257. proc genReturnStmt(p: PProc, n: PNode) =
  2258. if p.procDef == nil: internalError(p.config, n.info, "genReturnStmt")
  2259. p.beforeRetNeeded = true
  2260. if n[0].kind != nkEmpty:
  2261. genStmt(p, n[0])
  2262. else:
  2263. genLineDir(p, n)
  2264. lineF(p, "break BeforeRet;$n", [])
  2265. proc frameCreate(p: PProc; procname, filename: Rope): Rope =
  2266. const frameFmt =
  2267. "var F = {procname: $1, prev: framePtr, filename: $2, line: 0};$n"
  2268. result = p.indentLine(frameFmt % [procname, filename])
  2269. result.add p.indentLine(ropes.`%`("framePtr = F;$n", []))
  2270. proc frameDestroy(p: PProc): Rope =
  2271. result = p.indentLine rope(("framePtr = F.prev;") & "\L")
  2272. proc genProcBody(p: PProc, prc: PSym): Rope =
  2273. if hasFrameInfo(p):
  2274. result = frameCreate(p,
  2275. makeJSString(prc.owner.name.s & '.' & prc.name.s),
  2276. makeJSString(toFilenameOption(p.config, prc.info.fileIndex, foStacktrace)))
  2277. else:
  2278. result = ""
  2279. if p.beforeRetNeeded:
  2280. result.add p.indentLine("BeforeRet: {\n")
  2281. result.add p.body
  2282. result.add p.indentLine("};\n")
  2283. else:
  2284. result.add(p.body)
  2285. if prc.typ.callConv == ccSysCall:
  2286. result = ("try {$n$1} catch (e) {$n" &
  2287. " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}") % [result]
  2288. if hasFrameInfo(p):
  2289. result.add(frameDestroy(p))
  2290. proc optionalLine(p: Rope): Rope =
  2291. if p == "":
  2292. return ""
  2293. else:
  2294. return p & "\L"
  2295. proc genProc(oldProc: PProc, prc: PSym): Rope =
  2296. ## Generate a JS procedure ('function').
  2297. var
  2298. resultSym: PSym
  2299. a: TCompRes
  2300. #if gVerbosity >= 3:
  2301. # echo "BEGIN generating code for: " & prc.name.s
  2302. var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
  2303. p.up = oldProc
  2304. var returnStmt: Rope = ""
  2305. var resultAsgn: Rope = ""
  2306. var name = mangleName(p.module, prc)
  2307. let header = generateHeader(p, prc.typ)
  2308. if prc.typ[0] != nil and sfPure notin prc.flags:
  2309. resultSym = prc.ast[resultPos].sym
  2310. let mname = mangleName(p.module, resultSym)
  2311. let returnAddress = not isIndirect(resultSym) and
  2312. resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and
  2313. mapType(p, resultSym.typ) == etyBaseIndex
  2314. if returnAddress:
  2315. resultAsgn = p.indentLine(("var $# = null;$n") % [mname])
  2316. resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
  2317. else:
  2318. let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
  2319. resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
  2320. gen(p, prc.ast[resultPos], a)
  2321. if returnAddress:
  2322. returnStmt = "return [$#, $#];$n" % [a.address, a.res]
  2323. else:
  2324. returnStmt = "return $#;$n" % [a.res]
  2325. var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, dontUseCache)
  2326. if sfInjectDestructors in prc.flags:
  2327. transformedBody = injectDestructorCalls(p.module.graph, p.module.idgen, prc, transformedBody)
  2328. p.nested: genStmt(p, transformedBody)
  2329. if optLineDir in p.config.options:
  2330. result = lineDir(p.config, prc.info, toLinenumber(prc.info))
  2331. var def: Rope
  2332. if not prc.constraint.isNil:
  2333. def = runtimeFormat(prc.constraint.strVal & " {$n$#$#$#$#$#",
  2334. [ returnType,
  2335. name,
  2336. header,
  2337. optionalLine(p.globals),
  2338. optionalLine(p.locals),
  2339. optionalLine(resultAsgn),
  2340. optionalLine(genProcBody(p, prc)),
  2341. optionalLine(p.indentLine(returnStmt))])
  2342. else:
  2343. # if optLineDir in p.config.options:
  2344. # result.add("\L")
  2345. if p.config.hcrOn:
  2346. # Here, we introduce thunks that create the equivalent of a jump table
  2347. # for all global functions, because references to them may be stored
  2348. # in JavaScript variables. The added indirection ensures that such
  2349. # references will end up calling the reloaded code.
  2350. var thunkName = name
  2351. name = name & "IMLP"
  2352. result.add("\Lfunction $#() { return $#.apply(this, arguments); }$n" %
  2353. [thunkName, name])
  2354. def = "\Lfunction $#($#) {$n$#$#$#$#$#" %
  2355. [ name,
  2356. header,
  2357. optionalLine(p.globals),
  2358. optionalLine(p.locals),
  2359. optionalLine(resultAsgn),
  2360. optionalLine(genProcBody(p, prc)),
  2361. optionalLine(p.indentLine(returnStmt))]
  2362. dec p.extraIndent
  2363. result.add p.indentLine(def)
  2364. result.add p.indentLine("}\n")
  2365. #if gVerbosity >= 3:
  2366. # echo "END generated code for: " & prc.name.s
  2367. proc genStmt(p: PProc, n: PNode) =
  2368. var r: TCompRes
  2369. gen(p, n, r)
  2370. if r.res != "": lineF(p, "$#;$n", [r.res])
  2371. proc genPragma(p: PProc, n: PNode) =
  2372. for it in n.sons:
  2373. case whichPragma(it)
  2374. of wEmit: genAsmOrEmitStmt(p, it[1])
  2375. else: discard
  2376. proc genCast(p: PProc, n: PNode, r: var TCompRes) =
  2377. var dest = skipTypes(n.typ, abstractVarRange)
  2378. var src = skipTypes(n[1].typ, abstractVarRange)
  2379. gen(p, n[1], r)
  2380. if dest.kind == src.kind:
  2381. # no-op conversion
  2382. return
  2383. let toInt = (dest.kind in tyInt..tyInt32)
  2384. let toUint = (dest.kind in tyUInt..tyUInt32)
  2385. let fromInt = (src.kind in tyInt..tyInt32)
  2386. let fromUint = (src.kind in tyUInt..tyUInt32)
  2387. if toUint and (fromInt or fromUint):
  2388. let trimmer = unsignedTrimmer(dest.size)
  2389. r.res = "($1 $2)" % [r.res, trimmer]
  2390. elif toInt:
  2391. if fromInt:
  2392. return
  2393. elif fromUint:
  2394. if src.size == 4 and dest.size == 4:
  2395. # XXX prevent multi evaluations
  2396. r.res = "($1 | 0)" % [r.res]
  2397. else:
  2398. let trimmer = unsignedTrimmer(dest.size)
  2399. let minuend = case dest.size
  2400. of 1: "0xfe"
  2401. of 2: "0xfffe"
  2402. of 4: "0xfffffffe"
  2403. else: ""
  2404. r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer]
  2405. elif (src.kind == tyPtr and mapType(p, src) == etyObject) and dest.kind == tyPointer:
  2406. r.address = r.res
  2407. r.res = "null"
  2408. r.typ = etyBaseIndex
  2409. elif (dest.kind == tyPtr and mapType(p, dest) == etyObject) and src.kind == tyPointer:
  2410. r.res = r.address
  2411. r.typ = etyObject
  2412. proc gen(p: PProc, n: PNode, r: var TCompRes) =
  2413. r.typ = etyNone
  2414. if r.kind != resCallee: r.kind = resNone
  2415. #r.address = ""
  2416. r.res = ""
  2417. case n.kind
  2418. of nkSym:
  2419. genSym(p, n, r)
  2420. of nkCharLit..nkUInt64Lit:
  2421. if n.typ.kind == tyBool:
  2422. r.res = if n.intVal == 0: rope"false" else: rope"true"
  2423. else:
  2424. r.res = rope(n.intVal)
  2425. r.kind = resExpr
  2426. of nkNilLit:
  2427. if isEmptyType(n.typ):
  2428. discard
  2429. elif mapType(p, n.typ) == etyBaseIndex:
  2430. r.typ = etyBaseIndex
  2431. r.address = rope"null"
  2432. r.res = rope"0"
  2433. r.kind = resExpr
  2434. else:
  2435. r.res = rope"null"
  2436. r.kind = resExpr
  2437. of nkStrLit..nkTripleStrLit:
  2438. if skipTypes(n.typ, abstractVarRange).kind == tyString:
  2439. if n.strVal.len <= 64:
  2440. r.res = makeJsNimStrLit(n.strVal)
  2441. else:
  2442. useMagic(p, "makeNimstrLit")
  2443. r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
  2444. else:
  2445. r.res = makeJSString(n.strVal, false)
  2446. r.kind = resExpr
  2447. of nkFloatLit..nkFloat64Lit:
  2448. let f = n.floatVal
  2449. case classify(f)
  2450. of fcNan:
  2451. if signbit(f):
  2452. r.res = rope"-NaN"
  2453. else:
  2454. r.res = rope"NaN"
  2455. of fcNegZero:
  2456. r.res = rope"-0.0"
  2457. of fcZero:
  2458. r.res = rope"0.0"
  2459. of fcInf:
  2460. r.res = rope"Infinity"
  2461. of fcNegInf:
  2462. r.res = rope"-Infinity"
  2463. else: r.res = rope(f.toStrMaxPrecision)
  2464. r.kind = resExpr
  2465. of nkCallKinds:
  2466. if isEmptyType(n.typ):
  2467. genLineDir(p, n)
  2468. if (n[0].kind == nkSym) and (n[0].sym.magic != mNone):
  2469. genMagic(p, n, r)
  2470. elif n[0].kind == nkSym and sfInfixCall in n[0].sym.flags and
  2471. n.len >= 1:
  2472. genInfixCall(p, n, r)
  2473. else:
  2474. genCall(p, n, r)
  2475. of nkClosure: gen(p, n[0], r)
  2476. of nkCurly: genSetConstr(p, n, r)
  2477. of nkBracket: genArrayConstr(p, n, r)
  2478. of nkPar, nkTupleConstr: genTupleConstr(p, n, r)
  2479. of nkObjConstr: genObjConstr(p, n, r)
  2480. of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
  2481. of nkAddr, nkHiddenAddr:
  2482. if n.typ.kind in {tyLent}:
  2483. gen(p, n[0], r)
  2484. else:
  2485. genAddr(p, n, r)
  2486. of nkDerefExpr, nkHiddenDeref:
  2487. if n.typ.kind in {tyLent}:
  2488. gen(p, n[0], r)
  2489. else:
  2490. genDeref(p, n, r)
  2491. of nkBracketExpr: genArrayAccess(p, n, r)
  2492. of nkDotExpr: genFieldAccess(p, n, r)
  2493. of nkCheckedFieldExpr: genCheckedFieldOp(p, n, nil, r)
  2494. of nkObjDownConv: gen(p, n[0], r)
  2495. of nkObjUpConv: upConv(p, n, r)
  2496. of nkCast: genCast(p, n, r)
  2497. of nkChckRangeF: genRangeChck(p, n, r, "chckRangeF")
  2498. of nkChckRange64: genRangeChck(p, n, r, "chckRange64")
  2499. of nkChckRange: genRangeChck(p, n, r, "chckRange")
  2500. of nkStringToCString: convStrToCStr(p, n, r)
  2501. of nkCStringToString: convCStrToStr(p, n, r)
  2502. of nkEmpty: discard
  2503. of nkLambdaKinds:
  2504. let s = n[namePos].sym
  2505. discard mangleName(p.module, s)
  2506. r.res = s.loc.r
  2507. if lfNoDecl in s.loc.flags or s.magic notin generatedMagics: discard
  2508. elif not p.g.generatedSyms.containsOrIncl(s.id):
  2509. p.locals.add(genProc(p, s))
  2510. of nkType: r.res = genTypeInfo(p, n.typ)
  2511. of nkStmtList, nkStmtListExpr:
  2512. # this shows the distinction is nice for backends and should be kept
  2513. # in the frontend
  2514. let isExpr = not isEmptyType(n.typ)
  2515. for i in 0..<n.len - isExpr.ord:
  2516. genStmt(p, n[i])
  2517. if isExpr:
  2518. gen(p, lastSon(n), r)
  2519. of nkBlockStmt, nkBlockExpr: genBlock(p, n, r)
  2520. of nkIfStmt, nkIfExpr: genIf(p, n, r)
  2521. of nkWhen:
  2522. # This is "when nimvm" node
  2523. gen(p, n[1][0], r)
  2524. of nkWhileStmt: genWhileStmt(p, n)
  2525. of nkVarSection, nkLetSection: genVarStmt(p, n)
  2526. of nkConstSection: discard
  2527. of nkForStmt, nkParForStmt:
  2528. internalError(p.config, n.info, "for statement not eliminated")
  2529. of nkCaseStmt: genCaseJS(p, n, r)
  2530. of nkReturnStmt: genReturnStmt(p, n)
  2531. of nkBreakStmt: genBreakStmt(p, n)
  2532. of nkAsgn: genAsgn(p, n)
  2533. of nkFastAsgn: genFastAsgn(p, n)
  2534. of nkDiscardStmt:
  2535. if n[0].kind != nkEmpty:
  2536. genLineDir(p, n)
  2537. gen(p, n[0], r)
  2538. r.res = "var _ = " & r.res
  2539. of nkAsmStmt: genAsmOrEmitStmt(p, n)
  2540. of nkTryStmt, nkHiddenTryStmt: genTry(p, n, r)
  2541. of nkRaiseStmt: genRaiseStmt(p, n)
  2542. of nkTypeSection, nkCommentStmt, nkIncludeStmt,
  2543. nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
  2544. nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt,
  2545. nkMixinStmt, nkBindStmt: discard
  2546. of nkIteratorDef:
  2547. if n[0].sym.typ.callConv == TCallingConvention.ccClosure:
  2548. globalError(p.config, n.info, "Closure iterators are not supported by JS backend!")
  2549. of nkPragma: genPragma(p, n)
  2550. of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
  2551. var s = n[namePos].sym
  2552. if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
  2553. genSym(p, n[namePos], r)
  2554. r.res = ""
  2555. of nkGotoState, nkState:
  2556. globalError(p.config, n.info, "First class iterators not implemented")
  2557. of nkPragmaBlock: gen(p, n.lastSon, r)
  2558. of nkComesFrom:
  2559. discard "XXX to implement for better stack traces"
  2560. else: internalError(p.config, n.info, "gen: unknown node type: " & $n.kind)
  2561. proc newModule(g: ModuleGraph; module: PSym): BModule =
  2562. ## Create a new JS backend module node.
  2563. new(result)
  2564. result.module = module
  2565. result.sigConflicts = initCountTable[SigHash]()
  2566. if g.backend == nil:
  2567. g.backend = newGlobals()
  2568. result.graph = g
  2569. result.config = g.config
  2570. if sfSystemModule in module.flags:
  2571. PGlobals(g.backend).inSystem = true
  2572. proc genHeader(): Rope =
  2573. ## Generate the JS header.
  2574. result = rope("""/* Generated by the Nim Compiler v$1 */
  2575. var framePtr = null;
  2576. var excHandler = 0;
  2577. var lastJSError = null;
  2578. """.unindent.format(VersionAsString))
  2579. proc addHcrInitGuards(p: PProc, n: PNode,
  2580. moduleLoadedVar: Rope, inInitGuard: var bool) =
  2581. if n.kind == nkStmtList:
  2582. for child in n:
  2583. addHcrInitGuards(p, child, moduleLoadedVar, inInitGuard)
  2584. else:
  2585. let stmtShouldExecute = n.kind in {
  2586. nkProcDef, nkFuncDef, nkMethodDef,nkConverterDef,
  2587. nkVarSection, nkLetSection} or nfExecuteOnReload in n.flags
  2588. if inInitGuard:
  2589. if stmtShouldExecute:
  2590. dec p.extraIndent
  2591. line(p, "}\L")
  2592. inInitGuard = false
  2593. else:
  2594. if not stmtShouldExecute:
  2595. lineF(p, "if ($1 == undefined) {$n", [moduleLoadedVar])
  2596. inc p.extraIndent
  2597. inInitGuard = true
  2598. genStmt(p, n)
  2599. proc genModule(p: PProc, n: PNode) =
  2600. ## Generate the JS module code.
  2601. ## Called for each top level node in a Nim module.
  2602. if optStackTrace in p.options:
  2603. p.body.add(frameCreate(p,
  2604. makeJSString("module " & p.module.module.name.s),
  2605. makeJSString(toFilenameOption(p.config, p.module.module.info.fileIndex, foStacktrace))))
  2606. var transformedN = transformStmt(p.module.graph, p.module.idgen, p.module.module, n)
  2607. if sfInjectDestructors in p.module.module.flags:
  2608. transformedN = injectDestructorCalls(p.module.graph, p.module.idgen, p.module.module, transformedN)
  2609. if p.config.hcrOn and n.kind == nkStmtList:
  2610. let moduleSym = p.module.module
  2611. var moduleLoadedVar = rope(moduleSym.name.s) & "_loaded" &
  2612. idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts)
  2613. lineF(p, "var $1;$n", [moduleLoadedVar])
  2614. var inGuardedBlock = false
  2615. addHcrInitGuards(p, transformedN, moduleLoadedVar, inGuardedBlock)
  2616. if inGuardedBlock:
  2617. dec p.extraIndent
  2618. line(p, "}\L")
  2619. lineF(p, "$1 = true;$n", [moduleLoadedVar])
  2620. else:
  2621. genStmt(p, transformedN)
  2622. if optStackTrace in p.options:
  2623. p.body.add(frameDestroy(p))
  2624. proc myProcess(b: PPassContext, n: PNode): PNode =
  2625. ## Generate JS code for a node.
  2626. result = n
  2627. let m = BModule(b)
  2628. if passes.skipCodegen(m.config, n): return n
  2629. if m.module == nil: internalError(m.config, n.info, "myProcess")
  2630. let globals = PGlobals(m.graph.backend)
  2631. var p = newInitProc(globals, m)
  2632. p.unique = globals.unique
  2633. genModule(p, n)
  2634. p.g.code.add(p.locals)
  2635. p.g.code.add(p.body)
  2636. proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
  2637. ## Combine source code from all nodes.
  2638. let globals = PGlobals(graph.backend)
  2639. for prc in globals.forwarded:
  2640. if not globals.generatedSyms.containsOrIncl(prc.id):
  2641. var p = newInitProc(globals, m)
  2642. attachProc(p, prc)
  2643. var disp = generateMethodDispatchers(graph)
  2644. for i in 0..<disp.len:
  2645. let prc = disp[i].sym
  2646. if not globals.generatedSyms.containsOrIncl(prc.id):
  2647. var p = newInitProc(globals, m)
  2648. attachProc(p, prc)
  2649. result = globals.typeInfo & globals.constants & globals.code
  2650. proc getClassName(t: PType): Rope =
  2651. var s = t.sym
  2652. if s.isNil or sfAnon in s.flags:
  2653. s = skipTypes(t, abstractPtrs).sym
  2654. if s.isNil or sfAnon in s.flags:
  2655. doAssert(false, "cannot retrieve class name")
  2656. if s.loc.r != "": result = s.loc.r
  2657. else: result = rope(s.name.s)
  2658. proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
  2659. ## Finalize JS code generation of a Nim module.
  2660. ## Param `n` may contain nodes returned from the last module close call.
  2661. var m = BModule(b)
  2662. if sfMainModule in m.module.flags:
  2663. # Add global destructors to the module.
  2664. # This must come before the last call to `myProcess`.
  2665. for i in countdown(high(graph.globalDestructors), 0):
  2666. n.add graph.globalDestructors[i]
  2667. # Process any nodes left over from the last call to `myClose`.
  2668. result = myProcess(b, n)
  2669. # Some codegen is different (such as no stacktraces; see `initProcOptions`)
  2670. # when `std/system` is being processed.
  2671. if sfSystemModule in m.module.flags:
  2672. PGlobals(graph.backend).inSystem = false
  2673. # Check if codegen should continue before any files are generated.
  2674. # It may bail early is if too many errors have been raised.
  2675. if passes.skipCodegen(m.config, n): return n
  2676. # Nim modules are compiled into a single JS file.
  2677. # If this is the main module, then this is the final call to `myClose`.
  2678. if sfMainModule in m.module.flags:
  2679. var code = genHeader() & wholeCode(graph, m)
  2680. let outFile = m.config.prepareToWriteOutput()
  2681. # Generate an optional source map.
  2682. if optSourcemap in m.config.globalOptions:
  2683. var map: SourceMap
  2684. (code, map) = genSourceMap($(code), outFile.string)
  2685. writeFile(outFile.string & ".map", $(%map))
  2686. # Check if the generated JS code matches the output file, or else
  2687. # write it to the file.
  2688. if not equalsFile(code, outFile):
  2689. if not writeRope(code, outFile):
  2690. rawMessage(m.config, errCannotOpenFile, outFile.string)
  2691. proc myOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext =
  2692. ## Create the JS backend pass context `BModule` for a Nim module.
  2693. result = newModule(graph, s)
  2694. result.idgen = idgen
  2695. const JSgenPass* = makePass(myOpen, myProcess, myClose)