jsgen.nim 85 KB

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