jsgen.nim 90 KB

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