jsgen.nim 90 KB

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