jsgen.nim 86 KB

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