jsgen.nim 82 KB

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