jsgen.nim 100 KB

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