jsgen.nim 107 KB

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