jsgen.nim 87 KB

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