jsgen.nim 83 KB

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