jsgen.nim 104 KB

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