jsgen.nim 93 KB

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