jsgen.nim 85 KB

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