transf.nim 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001
  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 module implements the transformator. It transforms the syntax tree
  10. # to ease the work of the code generators. Does some transformations:
  11. #
  12. # * inlines iterators
  13. # * inlines constants
  14. # * performs constant folding
  15. # * converts "continue" to "break"; disambiguates "break"
  16. # * introduces method dispatchers
  17. # * performs lambda lifting for closure support
  18. # * transforms 'defer' into a 'try finally' statement
  19. import
  20. intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os,
  21. idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
  22. lambdalifting, sempass2, lowerings, lookups
  23. # implementation
  24. type
  25. PTransNode* = distinct PNode
  26. PTransCon = ref TTransCon
  27. TTransCon{.final.} = object # part of TContext; stackable
  28. mapping: TIdNodeTable # mapping from symbols to nodes
  29. owner: PSym # current owner
  30. forStmt: PNode # current for stmt
  31. forLoopBody: PTransNode # transformed for loop body
  32. yieldStmts: int # we count the number of yield statements,
  33. # because we need to introduce new variables
  34. # if we encounter the 2nd yield statement
  35. next: PTransCon # for stacking
  36. TTransfContext = object of passes.TPassContext
  37. module: PSym
  38. transCon: PTransCon # top of a TransCon stack
  39. inlining: int # > 0 if we are in inlining context (copy vars)
  40. nestedProcs: int # > 0 if we are in a nested proc
  41. contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
  42. deferDetected, tooEarly: bool
  43. PTransf = ref TTransfContext
  44. proc newTransNode(a: PNode): PTransNode {.inline.} =
  45. result = PTransNode(shallowCopy(a))
  46. proc newTransNode(kind: TNodeKind, info: TLineInfo,
  47. sons: int): PTransNode {.inline.} =
  48. var x = newNodeI(kind, info)
  49. newSeq(x.sons, sons)
  50. result = x.PTransNode
  51. proc newTransNode(kind: TNodeKind, n: PNode,
  52. sons: int): PTransNode {.inline.} =
  53. var x = newNodeIT(kind, n.info, n.typ)
  54. newSeq(x.sons, sons)
  55. x.typ = n.typ
  56. result = x.PTransNode
  57. proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
  58. var n = PNode(a)
  59. n.sons[i] = PNode(x)
  60. proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
  61. var n = PNode(a)
  62. result = n.sons[i].PTransNode
  63. proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
  64. proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
  65. proc newTransCon(owner: PSym): PTransCon =
  66. assert owner != nil
  67. new(result)
  68. initIdNodeTable(result.mapping)
  69. result.owner = owner
  70. proc pushTransCon(c: PTransf, t: PTransCon) =
  71. t.next = c.transCon
  72. c.transCon = t
  73. proc popTransCon(c: PTransf) =
  74. if (c.transCon == nil): internalError("popTransCon")
  75. c.transCon = c.transCon.next
  76. proc getCurrOwner(c: PTransf): PSym =
  77. if c.transCon != nil: result = c.transCon.owner
  78. else: result = c.module
  79. proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
  80. let r = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
  81. r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias})
  82. incl(r.flags, sfFromGeneric)
  83. let owner = getCurrOwner(c)
  84. if owner.isIterator and not c.tooEarly:
  85. result = freshVarForClosureIter(r, owner)
  86. else:
  87. result = newSymNode(r)
  88. proc transform(c: PTransf, n: PNode): PTransNode
  89. proc transformSons(c: PTransf, n: PNode): PTransNode =
  90. result = newTransNode(n)
  91. for i in countup(0, sonsLen(n)-1):
  92. result[i] = transform(c, n.sons[i])
  93. proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
  94. result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
  95. result[0] = PTransNode(le)
  96. result[1] = ri
  97. proc transformSymAux(c: PTransf, n: PNode): PNode =
  98. let s = n.sym
  99. if s.typ != nil and s.typ.callConv == ccClosure:
  100. if s.kind == skIterator:
  101. if c.tooEarly: return n
  102. else: return liftIterSym(n, getCurrOwner(c))
  103. elif s.kind in {skProc, skConverter, skMethod} and not c.tooEarly:
  104. # top level .closure procs are still somewhat supported for 'Nake':
  105. return makeClosure(s, nil, n.info)
  106. #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
  107. # echo n.info, " come heer for ", c.tooEarly
  108. # if not c.tooEarly:
  109. var b: PNode
  110. var tc = c.transCon
  111. if sfBorrow in s.flags and s.kind in routineKinds:
  112. # simply exchange the symbol:
  113. b = s.getBody
  114. if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
  115. b = newSymNode(b.sym, n.info)
  116. else:
  117. b = n
  118. while tc != nil:
  119. result = idNodeTableGet(tc.mapping, b.sym)
  120. if result != nil:
  121. # this slightly convoluted way ensures the line info stays correct:
  122. if result.kind == nkSym:
  123. result = copyNode(result)
  124. result.info = n.info
  125. return
  126. tc = tc.next
  127. result = b
  128. proc transformSym(c: PTransf, n: PNode): PTransNode =
  129. result = PTransNode(transformSymAux(c, n))
  130. proc freshVar(c: PTransf; v: PSym): PNode =
  131. let owner = getCurrOwner(c)
  132. if owner.isIterator and not c.tooEarly:
  133. result = freshVarForClosureIter(v, owner)
  134. else:
  135. var newVar = copySym(v)
  136. incl(newVar.flags, sfFromGeneric)
  137. newVar.owner = owner
  138. result = newSymNode(newVar)
  139. proc transformVarSection(c: PTransf, v: PNode): PTransNode =
  140. result = newTransNode(v)
  141. for i in countup(0, sonsLen(v)-1):
  142. var it = v.sons[i]
  143. if it.kind == nkCommentStmt:
  144. result[i] = PTransNode(it)
  145. elif it.kind == nkIdentDefs:
  146. if it.sons[0].kind == nkSym:
  147. internalAssert(it.len == 3)
  148. let x = freshVar(c, it.sons[0].sym)
  149. idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x)
  150. var defs = newTransNode(nkIdentDefs, it.info, 3)
  151. if importantComments():
  152. # keep documentation information:
  153. PNode(defs).comment = it.comment
  154. defs[0] = x.PTransNode
  155. defs[1] = it.sons[1].PTransNode
  156. defs[2] = transform(c, it.sons[2])
  157. if x.kind == nkSym: x.sym.ast = defs[2].PNode
  158. result[i] = defs
  159. else:
  160. # has been transformed into 'param.x' for closure iterators, so just
  161. # transform it:
  162. result[i] = transform(c, it)
  163. else:
  164. if it.kind != nkVarTuple:
  165. internalError(it.info, "transformVarSection: not nkVarTuple")
  166. var L = sonsLen(it)
  167. var defs = newTransNode(it.kind, it.info, L)
  168. for j in countup(0, L-3):
  169. let x = freshVar(c, it.sons[j].sym)
  170. idNodeTablePut(c.transCon.mapping, it.sons[j].sym, x)
  171. defs[j] = x.PTransNode
  172. assert(it.sons[L-2].kind == nkEmpty)
  173. defs[L-2] = ast.emptyNode.PTransNode
  174. defs[L-1] = transform(c, it.sons[L-1])
  175. result[i] = defs
  176. proc transformConstSection(c: PTransf, v: PNode): PTransNode =
  177. result = newTransNode(v)
  178. for i in countup(0, sonsLen(v)-1):
  179. var it = v.sons[i]
  180. if it.kind == nkCommentStmt:
  181. result[i] = PTransNode(it)
  182. else:
  183. if it.kind != nkConstDef: internalError(it.info, "transformConstSection")
  184. if it.sons[0].kind != nkSym:
  185. internalError(it.info, "transformConstSection")
  186. result[i] = PTransNode(it)
  187. proc hasContinue(n: PNode): bool =
  188. case n.kind
  189. of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
  190. of nkContinueStmt: result = true
  191. else:
  192. for i in countup(0, sonsLen(n) - 1):
  193. if hasContinue(n.sons[i]): return true
  194. proc newLabel(c: PTransf, n: PNode): PSym =
  195. result = newSym(skLabel, nil, getCurrOwner(c), n.info)
  196. result.name = getIdent(genPrefix & $result.id)
  197. proc freshLabels(c: PTransf, n: PNode; symMap: var TIdTable) =
  198. if n.kind in {nkBlockStmt, nkBlockExpr}:
  199. if n.sons[0].kind == nkSym:
  200. let x = newLabel(c, n[0])
  201. idTablePut(symMap, n[0].sym, x)
  202. n.sons[0].sym = x
  203. if n.kind == nkSym and n.sym.kind == skLabel:
  204. let x = PSym(idTableGet(symMap, n.sym))
  205. if x != nil: n.sym = x
  206. else:
  207. for i in 0 .. <safeLen(n): freshLabels(c, n.sons[i], symMap)
  208. proc transformBlock(c: PTransf, n: PNode): PTransNode =
  209. var labl: PSym
  210. if n.sons[0].kind != nkEmpty:
  211. # already named block? -> Push symbol on the stack:
  212. labl = n.sons[0].sym
  213. else:
  214. labl = newLabel(c, n)
  215. c.breakSyms.add(labl)
  216. result = transformSons(c, n)
  217. discard c.breakSyms.pop
  218. result[0] = newSymNode(labl).PTransNode
  219. proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
  220. # What if it contains "continue" and "break"? "break" needs
  221. # an explicit label too, but not the same!
  222. # We fix this here by making every 'break' belong to its enclosing loop
  223. # and changing all breaks that belong to a 'block' by annotating it with
  224. # a label (if it hasn't one already).
  225. if hasContinue(n):
  226. let labl = newLabel(c, n)
  227. c.contSyms.add(labl)
  228. result = newTransNode(nkBlockStmt, n.info, 2)
  229. result[0] = newSymNode(labl).PTransNode
  230. result[1] = transform(c, n)
  231. discard c.contSyms.pop()
  232. else:
  233. result = transform(c, n)
  234. proc transformWhile(c: PTransf; n: PNode): PTransNode =
  235. if c.inlining > 0:
  236. result = transformSons(c, n)
  237. else:
  238. let labl = newLabel(c, n)
  239. c.breakSyms.add(labl)
  240. result = newTransNode(nkBlockStmt, n.info, 2)
  241. result[0] = newSymNode(labl).PTransNode
  242. var body = newTransNode(n)
  243. for i in 0..n.len-2:
  244. body[i] = transform(c, n.sons[i])
  245. body[<n.len] = transformLoopBody(c, n.sons[<n.len])
  246. result[1] = body
  247. discard c.breakSyms.pop
  248. proc transformBreak(c: PTransf, n: PNode): PTransNode =
  249. if n.sons[0].kind != nkEmpty or c.inlining > 0:
  250. result = n.PTransNode
  251. when false:
  252. let lablCopy = idNodeTableGet(c.transCon.mapping, n.sons[0].sym)
  253. if lablCopy.isNil:
  254. result = n.PTransNode
  255. else:
  256. result = newTransNode(n.kind, n.info, 1)
  257. result[0] = lablCopy.PTransNode
  258. elif c.breakSyms.len > 0:
  259. # this check can fail for 'nim check'
  260. let labl = c.breakSyms[c.breakSyms.high]
  261. result = transformSons(c, n)
  262. result[0] = newSymNode(labl).PTransNode
  263. else:
  264. result = n.PTransNode
  265. proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
  266. # XXX: BUG: what if `n` is an expression with side-effects?
  267. for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
  268. add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
  269. transform(c, newTupleAccess(n, i))))
  270. proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
  271. case n.kind
  272. of nkSym:
  273. result = transformSym(c, n)
  274. of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
  275. # nothing to be done for leaves:
  276. result = PTransNode(n)
  277. of nkVarSection, nkLetSection:
  278. result = transformVarSection(c, n)
  279. of nkClosure:
  280. # it can happen that for-loop-inlining produced a fresh
  281. # set of variables, including some computed environment
  282. # (bug #2604). We need to patch this environment here too:
  283. let a = n[1]
  284. if a.kind == nkSym:
  285. n.sons[1] = transformSymAux(c, a)
  286. return PTransNode(n)
  287. else:
  288. result = newTransNode(n)
  289. for i in countup(0, sonsLen(n)-1):
  290. result[i] = introduceNewLocalVars(c, n.sons[i])
  291. proc transformYield(c: PTransf, n: PNode): PTransNode =
  292. result = newTransNode(nkStmtList, n.info, 0)
  293. var e = n.sons[0]
  294. # c.transCon.forStmt.len == 3 means that there is one for loop variable
  295. # and thus no tuple unpacking:
  296. if e.typ.isNil: return result # can happen in nimsuggest for unknown reasons
  297. if skipTypes(e.typ, {tyGenericInst, tyAlias}).kind == tyTuple and
  298. c.transCon.forStmt.len != 3:
  299. e = skipConv(e)
  300. if e.kind == nkPar:
  301. for i in countup(0, sonsLen(e) - 1):
  302. var v = e.sons[i]
  303. if v.kind == nkExprColonExpr: v = v.sons[1]
  304. add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
  305. transform(c, v)))
  306. else:
  307. unpackTuple(c, e, result)
  308. else:
  309. var x = transform(c, e)
  310. add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
  311. inc(c.transCon.yieldStmts)
  312. if c.transCon.yieldStmts <= 1:
  313. # common case
  314. add(result, c.transCon.forLoopBody)
  315. else:
  316. # we need to introduce new local variables:
  317. add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
  318. proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
  319. result = transformSons(c, n)
  320. if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
  321. var n = result.PNode
  322. case n.sons[0].kind
  323. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  324. var m = n.sons[0].sons[0]
  325. if m.kind == a or m.kind == b:
  326. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  327. n.sons[0].sons[0] = m.sons[0]
  328. result = PTransNode(n.sons[0])
  329. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  330. var m = n.sons[0].sons[1]
  331. if m.kind == a or m.kind == b:
  332. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  333. n.sons[0].sons[1] = m.sons[0]
  334. result = PTransNode(n.sons[0])
  335. else:
  336. if n.sons[0].kind == a or n.sons[0].kind == b:
  337. # addr ( deref ( x )) --> x
  338. result = PTransNode(n.sons[0].sons[0])
  339. proc generateThunk(prc: PNode, dest: PType): PNode =
  340. ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
  341. ## a closure.
  342. # we cannot generate a proper thunk here for GC-safety reasons
  343. # (see internal documentation):
  344. if gCmd == cmdCompileToJS: return prc
  345. result = newNodeIT(nkClosure, prc.info, dest)
  346. var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
  347. conv.add(emptyNode)
  348. conv.add(prc)
  349. if prc.kind == nkClosure:
  350. internalError(prc.info, "closure to closure created")
  351. result.add(conv)
  352. result.add(newNodeIT(nkNilLit, prc.info, getSysType(tyNil)))
  353. proc transformConv(c: PTransf, n: PNode): PTransNode =
  354. # numeric types need range checks:
  355. var dest = skipTypes(n.typ, abstractVarRange)
  356. var source = skipTypes(n.sons[1].typ, abstractVarRange)
  357. case dest.kind
  358. of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
  359. # we don't include uint and uint64 here as these are no ordinal types ;-)
  360. if not isOrdinalType(source):
  361. # float -> int conversions. ugh.
  362. result = transformSons(c, n)
  363. elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
  364. lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
  365. # BUGFIX: simply leave n as it is; we need a nkConv node,
  366. # but no range check:
  367. result = transformSons(c, n)
  368. else:
  369. # generate a range check:
  370. if dest.kind == tyInt64 or source.kind == tyInt64:
  371. result = newTransNode(nkChckRange64, n, 3)
  372. else:
  373. result = newTransNode(nkChckRange, n, 3)
  374. dest = skipTypes(n.typ, abstractVar)
  375. result[0] = transform(c, n.sons[1])
  376. result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), dest).PTransNode
  377. result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), dest).PTransNode
  378. of tyFloat..tyFloat128:
  379. # XXX int64 -> float conversion?
  380. if skipTypes(n.typ, abstractVar).kind == tyRange:
  381. result = newTransNode(nkChckRangeF, n, 3)
  382. dest = skipTypes(n.typ, abstractVar)
  383. result[0] = transform(c, n.sons[1])
  384. result[1] = copyTree(dest.n.sons[0]).PTransNode
  385. result[2] = copyTree(dest.n.sons[1]).PTransNode
  386. else:
  387. result = transformSons(c, n)
  388. of tyOpenArray, tyVarargs:
  389. result = transform(c, n.sons[1])
  390. PNode(result).typ = takeType(n.typ, n.sons[1].typ)
  391. #echo n.info, " came here and produced ", typeToString(PNode(result).typ),
  392. # " from ", typeToString(n.typ), " and ", typeToString(n.sons[1].typ)
  393. of tyCString:
  394. if source.kind == tyString:
  395. result = newTransNode(nkStringToCString, n, 1)
  396. result[0] = transform(c, n.sons[1])
  397. else:
  398. result = transformSons(c, n)
  399. of tyString:
  400. if source.kind == tyCString:
  401. result = newTransNode(nkCStringToString, n, 1)
  402. result[0] = transform(c, n.sons[1])
  403. else:
  404. result = transformSons(c, n)
  405. of tyRef, tyPtr:
  406. dest = skipTypes(dest, abstractPtrs)
  407. source = skipTypes(source, abstractPtrs)
  408. if source.kind == tyObject:
  409. var diff = inheritanceDiff(dest, source)
  410. if diff < 0:
  411. result = newTransNode(nkObjUpConv, n, 1)
  412. result[0] = transform(c, n.sons[1])
  413. elif diff > 0 and diff != high(int):
  414. result = newTransNode(nkObjDownConv, n, 1)
  415. result[0] = transform(c, n.sons[1])
  416. else:
  417. result = transform(c, n.sons[1])
  418. else:
  419. result = transformSons(c, n)
  420. of tyObject:
  421. var diff = inheritanceDiff(dest, source)
  422. if diff < 0:
  423. result = newTransNode(nkObjUpConv, n, 1)
  424. result[0] = transform(c, n.sons[1])
  425. elif diff > 0 and diff != high(int):
  426. result = newTransNode(nkObjDownConv, n, 1)
  427. result[0] = transform(c, n.sons[1])
  428. else:
  429. result = transform(c, n.sons[1])
  430. of tyGenericParam, tyOrdinal:
  431. result = transform(c, n.sons[1])
  432. # happens sometimes for generated assignments, etc.
  433. of tyProc:
  434. result = transformSons(c, n)
  435. if dest.callConv == ccClosure and source.callConv == ccDefault:
  436. result = generateThunk(result[1].PNode, dest).PTransNode
  437. else:
  438. result = transformSons(c, n)
  439. type
  440. TPutArgInto = enum
  441. paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray
  442. proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
  443. # This analyses how to treat the mapping "formal <-> arg" in an
  444. # inline context.
  445. if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
  446. if arg.kind == nkStmtListExpr:
  447. return paComplexOpenarray
  448. return paDirectMapping # XXX really correct?
  449. # what if ``arg`` has side-effects?
  450. case arg.kind
  451. of nkEmpty..nkNilLit:
  452. result = paDirectMapping
  453. of nkPar, nkCurly, nkBracket:
  454. result = paFastAsgn
  455. for i in countup(0, sonsLen(arg) - 1):
  456. if putArgInto(arg.sons[i], formal) != paDirectMapping: return
  457. result = paDirectMapping
  458. else:
  459. if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
  460. else: result = paFastAsgn
  461. proc findWrongOwners(c: PTransf, n: PNode) =
  462. if n.kind == nkVarSection:
  463. let x = n.sons[0].sons[0]
  464. if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
  465. internalError(x.info, "bah " & x.sym.name.s & " " &
  466. x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
  467. else:
  468. for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
  469. proc transformFor(c: PTransf, n: PNode): PTransNode =
  470. # generate access statements for the parameters (unless they are constant)
  471. # put mapping from formal parameters to actual parameters
  472. if n.kind != nkForStmt: internalError(n.info, "transformFor")
  473. var length = sonsLen(n)
  474. var call = n.sons[length - 2]
  475. let labl = newLabel(c, n)
  476. result = newTransNode(nkBlockStmt, n.info, 2)
  477. result[0] = newSymNode(labl).PTransNode
  478. if call.typ.isNil:
  479. # see bug #3051
  480. result[1] = newNode(nkEmpty).PTransNode
  481. return result
  482. c.breakSyms.add(labl)
  483. if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
  484. call.sons[0].typ.callConv == ccClosure:
  485. n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
  486. if not c.tooEarly:
  487. n.sons[length-2] = transform(c, n.sons[length-2]).PNode
  488. result[1] = lambdalifting.liftForLoop(n, getCurrOwner(c)).PTransNode
  489. else:
  490. result[1] = newNode(nkEmpty).PTransNode
  491. discard c.breakSyms.pop
  492. return result
  493. #echo "transforming: ", renderTree(n)
  494. var stmtList = newTransNode(nkStmtList, n.info, 0)
  495. result[1] = stmtList
  496. var loopBody = transformLoopBody(c, n.sons[length-1])
  497. discard c.breakSyms.pop
  498. var v = newNodeI(nkVarSection, n.info)
  499. for i in countup(0, length - 3):
  500. addVar(v, copyTree(n.sons[i])) # declare new vars
  501. add(stmtList, v.PTransNode)
  502. # Bugfix: inlined locals belong to the invoking routine, not to the invoked
  503. # iterator!
  504. let iter = call.sons[0].sym
  505. var newC = newTransCon(getCurrOwner(c))
  506. newC.forStmt = n
  507. newC.forLoopBody = loopBody
  508. # this can fail for 'nimsuggest' and 'check':
  509. if iter.kind != skIterator: return result
  510. # generate access statements for the parameters (unless they are constant)
  511. pushTransCon(c, newC)
  512. for i in countup(1, sonsLen(call) - 1):
  513. var arg = transform(c, call.sons[i]).PNode
  514. let ff = skipTypes(iter.typ, abstractInst)
  515. # can happen for 'nim check':
  516. if i >= ff.n.len: return result
  517. var formal = ff.n.sons[i].sym
  518. case putArgInto(arg, formal.typ)
  519. of paDirectMapping:
  520. idNodeTablePut(newC.mapping, formal, arg)
  521. of paFastAsgn:
  522. # generate a temporary and produce an assignment statement:
  523. var temp = newTemp(c, formal.typ, formal.info)
  524. addVar(v, temp)
  525. add(stmtList, newAsgnStmt(c, temp, arg.PTransNode))
  526. idNodeTablePut(newC.mapping, formal, temp)
  527. of paVarAsgn:
  528. assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
  529. idNodeTablePut(newC.mapping, formal, arg)
  530. # XXX BUG still not correct if the arg has a side effect!
  531. of paComplexOpenarray:
  532. let typ = newType(tySequence, formal.owner)
  533. addSonSkipIntLit(typ, formal.typ.sons[0])
  534. var temp = newTemp(c, typ, formal.info)
  535. addVar(v, temp)
  536. add(stmtList, newAsgnStmt(c, temp, arg.PTransNode))
  537. idNodeTablePut(newC.mapping, formal, temp)
  538. var body = iter.getBody.copyTree
  539. pushInfoContext(n.info)
  540. # XXX optimize this somehow. But the check "c.inlining" is not correct:
  541. var symMap: TIdTable
  542. initIdTable symMap
  543. freshLabels(c, body, symMap)
  544. inc(c.inlining)
  545. add(stmtList, transform(c, body))
  546. #findWrongOwners(c, stmtList.pnode)
  547. dec(c.inlining)
  548. popInfoContext()
  549. popTransCon(c)
  550. # echo "transformed: ", stmtList.PNode.renderTree
  551. proc transformCase(c: PTransf, n: PNode): PTransNode =
  552. # removes `elif` branches of a case stmt
  553. # adds ``else: nil`` if needed for the code generator
  554. result = newTransNode(nkCaseStmt, n, 0)
  555. var ifs = PTransNode(nil)
  556. for i in 0 .. sonsLen(n)-1:
  557. var it = n.sons[i]
  558. var e = transform(c, it)
  559. case it.kind
  560. of nkElifBranch:
  561. if ifs.PNode == nil:
  562. ifs = newTransNode(nkIfStmt, it.info, 0)
  563. ifs.add(e)
  564. of nkElse:
  565. if ifs.PNode == nil: result.add(e)
  566. else: ifs.add(e)
  567. else:
  568. result.add(e)
  569. if ifs.PNode != nil:
  570. var elseBranch = newTransNode(nkElse, n.info, 1)
  571. elseBranch[0] = ifs
  572. result.add(elseBranch)
  573. elif result.PNode.lastSon.kind != nkElse and not (
  574. skipTypes(n.sons[0].typ, abstractVarRange).kind in
  575. {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32}):
  576. # fix a stupid code gen bug by normalizing:
  577. var elseBranch = newTransNode(nkElse, n.info, 1)
  578. elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
  579. add(result, elseBranch)
  580. proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
  581. # XXX this is really bad; transf should use a proper AST visitor
  582. if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
  583. result = n.PTransNode
  584. else:
  585. result = newTransNode(n)
  586. for i in 0 .. < n.len:
  587. result[i] = transform(c, skipConv(n.sons[i]))
  588. proc getMergeOp(n: PNode): PSym =
  589. case n.kind
  590. of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
  591. nkCallStrLit:
  592. if n.sons[0].kind == nkSym and n.sons[0].sym.magic == mConStrStr:
  593. result = n.sons[0].sym
  594. else: discard
  595. proc flattenTreeAux(d, a: PNode, op: PSym) =
  596. let op2 = getMergeOp(a)
  597. if op2 != nil and
  598. (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
  599. for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
  600. else:
  601. addSon(d, copyTree(a))
  602. proc flattenTree(root: PNode): PNode =
  603. let op = getMergeOp(root)
  604. if op != nil:
  605. result = copyNode(root)
  606. addSon(result, copyTree(root.sons[0]))
  607. flattenTreeAux(result, root, op)
  608. else:
  609. result = root
  610. proc transformCall(c: PTransf, n: PNode): PTransNode =
  611. var n = flattenTree(n)
  612. let op = getMergeOp(n)
  613. let magic = getMagic(n)
  614. if op != nil and op.magic != mNone and n.len >= 3:
  615. result = newTransNode(nkCall, n, 0)
  616. add(result, transform(c, n.sons[0]))
  617. var j = 1
  618. while j < sonsLen(n):
  619. var a = transform(c, n.sons[j]).PNode
  620. inc(j)
  621. if isConstExpr(a):
  622. while (j < sonsLen(n)):
  623. let b = transform(c, n.sons[j]).PNode
  624. if not isConstExpr(b): break
  625. a = evalOp(op.magic, n, a, b, nil)
  626. inc(j)
  627. add(result, a.PTransNode)
  628. if len(result) == 2: result = result[1]
  629. elif magic in {mNBindSym, mTypeOf}:
  630. # for bindSym(myconst) we MUST NOT perform constant folding:
  631. result = n.PTransNode
  632. elif magic == mProcCall:
  633. # but do not change to its dispatcher:
  634. result = transformSons(c, n[1])
  635. else:
  636. let s = transformSons(c, n).PNode
  637. # bugfix: check after 'transformSons' if it's still a method call:
  638. # use the dispatcher for the call:
  639. if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod:
  640. when false:
  641. let t = lastSon(s.sons[0].sym.ast)
  642. if t.kind != nkSym or sfDispatcher notin t.sym.flags:
  643. methodDef(s.sons[0].sym, false)
  644. result = methodCall(s).PTransNode
  645. else:
  646. result = s.PTransNode
  647. proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
  648. result = transformSons(c, n)
  649. if n[0].isInfixAs():
  650. let excTypeNode = n[0][1]
  651. let actions = newTransNode(nkStmtList, n[1].info, 2)
  652. # Generating `let exc = (excType)(getCurrentException())`
  653. # -> getCurrentException()
  654. let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))
  655. # -> (excType)
  656. let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
  657. convNode[0] = PTransNode(ast.emptyNode)
  658. convNode[1] = excCall
  659. PNode(convNode).typ = excTypeNode.typ.toRef()
  660. # -> let exc = ...
  661. let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
  662. identDefs[0] = PTransNode(n[0][2])
  663. identDefs[1] = PTransNode(ast.emptyNode)
  664. identDefs[2] = convNode
  665. let letSection = newTransNode(nkLetSection, n[1].info, 1)
  666. letSection[0] = identDefs
  667. # Place the let statement and body of the 'except' branch into new stmtList.
  668. actions[0] = letSection
  669. actions[1] = transformSons(c, n[1])
  670. # Overwrite 'except' branch body with our stmtList.
  671. result[1] = actions
  672. # Replace the `Exception as foobar` with just `Exception`.
  673. result[0] = result[0][1]
  674. proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
  675. # symbols that expand to a complex constant (array, etc.) should not be
  676. # inlined, unless it's the empty array:
  677. result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
  678. cnst.len != 0
  679. proc commonOptimizations*(c: PSym, n: PNode): PNode =
  680. result = n
  681. for i in 0 .. < n.safeLen:
  682. result.sons[i] = commonOptimizations(c, n.sons[i])
  683. var op = getMergeOp(n)
  684. if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
  685. result = newNodeIT(nkCall, n.info, n.typ)
  686. add(result, n.sons[0])
  687. var args = newNode(nkArgList)
  688. flattenTreeAux(args, n, op)
  689. var j = 0
  690. while j < sonsLen(args):
  691. var a = args.sons[j]
  692. inc(j)
  693. if isConstExpr(a):
  694. while j < sonsLen(args):
  695. let b = args.sons[j]
  696. if not isConstExpr(b): break
  697. a = evalOp(op.magic, result, a, b, nil)
  698. inc(j)
  699. add(result, a)
  700. if len(result) == 2: result = result[1]
  701. else:
  702. var cnst = getConstExpr(c, n)
  703. # we inline constants if they are not complex constants:
  704. if cnst != nil and not dontInlineConstant(n, cnst):
  705. result = cnst
  706. else:
  707. result = n
  708. proc transform(c: PTransf, n: PNode): PTransNode =
  709. when false:
  710. var oldDeferAnchor: PNode
  711. if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
  712. nkElseExpr, nkElse, nkForStmt, nkWhileStmt, nkFinally,
  713. nkBlockStmt, nkBlockExpr}:
  714. oldDeferAnchor = c.deferAnchor
  715. c.deferAnchor = n
  716. case n.kind
  717. of nkSym:
  718. result = transformSym(c, n)
  719. of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
  720. # nothing to be done for leaves:
  721. result = PTransNode(n)
  722. of nkBracketExpr: result = transformArrayAccess(c, n)
  723. of procDefs:
  724. var s = n.sons[namePos].sym
  725. if n.typ != nil and s.typ.callConv == ccClosure:
  726. result = transformSym(c, n.sons[namePos])
  727. # use the same node as before if still a symbol:
  728. if result.PNode.kind == nkSym: result = PTransNode(n)
  729. else:
  730. result = PTransNode(n)
  731. of nkMacroDef:
  732. # XXX no proper closure support yet:
  733. when false:
  734. if n.sons[genericParamsPos].kind == nkEmpty:
  735. var s = n.sons[namePos].sym
  736. n.sons[bodyPos] = PNode(transform(c, s.getBody))
  737. if n.kind == nkMethodDef: methodDef(s, false)
  738. result = PTransNode(n)
  739. of nkForStmt:
  740. result = transformFor(c, n)
  741. of nkParForStmt:
  742. result = transformSons(c, n)
  743. of nkCaseStmt:
  744. result = transformCase(c, n)
  745. of nkWhileStmt: result = transformWhile(c, n)
  746. of nkBlockStmt, nkBlockExpr:
  747. result = transformBlock(c, n)
  748. of nkDefer:
  749. c.deferDetected = true
  750. result = transformSons(c, n)
  751. when false:
  752. let deferPart = newNodeI(nkFinally, n.info)
  753. deferPart.add n.sons[0]
  754. let tryStmt = newNodeI(nkTryStmt, n.info)
  755. if c.deferAnchor.isNil:
  756. tryStmt.add c.root
  757. c.root = tryStmt
  758. result = PTransNode(tryStmt)
  759. else:
  760. # modify the corresponding *action*, don't rely on nkStmtList:
  761. let L = c.deferAnchor.len-1
  762. tryStmt.add c.deferAnchor.sons[L]
  763. c.deferAnchor.sons[L] = tryStmt
  764. result = newTransNode(nkCommentStmt, n.info, 0)
  765. tryStmt.addSon(deferPart)
  766. # disable the original 'defer' statement:
  767. n.kind = nkEmpty
  768. of nkContinueStmt:
  769. result = PTransNode(newNodeI(nkBreakStmt, n.info))
  770. var labl = c.contSyms[c.contSyms.high]
  771. add(result, PTransNode(newSymNode(labl)))
  772. of nkBreakStmt: result = transformBreak(c, n)
  773. of nkCallKinds:
  774. result = transformCall(c, n)
  775. of nkAddr, nkHiddenAddr:
  776. result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
  777. of nkDerefExpr, nkHiddenDeref:
  778. result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
  779. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  780. result = transformConv(c, n)
  781. of nkDiscardStmt:
  782. result = PTransNode(n)
  783. if n.sons[0].kind != nkEmpty:
  784. result = transformSons(c, n)
  785. if isConstExpr(PNode(result).sons[0]):
  786. # ensure that e.g. discard "some comment" gets optimized away
  787. # completely:
  788. result = PTransNode(newNode(nkCommentStmt))
  789. of nkCommentStmt, nkTemplateDef:
  790. return n.PTransNode
  791. of nkConstSection:
  792. # do not replace ``const c = 3`` with ``const 3 = 3``
  793. return transformConstSection(c, n)
  794. of nkTypeSection, nkTypeOfExpr:
  795. # no need to transform type sections:
  796. return PTransNode(n)
  797. of nkVarSection, nkLetSection:
  798. if c.inlining > 0:
  799. # we need to copy the variables for multiple yield statements:
  800. result = transformVarSection(c, n)
  801. else:
  802. result = transformSons(c, n)
  803. of nkYieldStmt:
  804. if c.inlining > 0:
  805. result = transformYield(c, n)
  806. else:
  807. result = transformSons(c, n)
  808. of nkIdentDefs, nkConstDef:
  809. when true:
  810. result = transformSons(c, n)
  811. else:
  812. result = n.PTransNode
  813. let L = n.len-1
  814. result[L] = transform(c, n.sons[L])
  815. # XXX comment handling really sucks:
  816. if importantComments():
  817. PNode(result).comment = n.comment
  818. of nkClosure:
  819. # it can happen that for-loop-inlining produced a fresh
  820. # set of variables, including some computed environment
  821. # (bug #2604). We need to patch this environment here too:
  822. let a = n[1]
  823. if a.kind == nkSym:
  824. n.sons[1] = transformSymAux(c, a)
  825. return PTransNode(n)
  826. of nkExceptBranch:
  827. result = transformExceptBranch(c, n)
  828. else:
  829. result = transformSons(c, n)
  830. when false:
  831. if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
  832. var cnst = getConstExpr(c.module, PNode(result))
  833. # we inline constants if they are not complex constants:
  834. if cnst != nil and not dontInlineConstant(n, cnst):
  835. result = PTransNode(cnst) # do not miss an optimization
  836. proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
  837. # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
  838. # this step! We have to rely that the semantic pass transforms too errornous
  839. # nodes into an empty node.
  840. if c.fromCache or nfTransf in n.flags: return n
  841. pushTransCon(c, newTransCon(owner))
  842. result = PNode(transform(c, n))
  843. popTransCon(c)
  844. incl(result.flags, nfTransf)
  845. proc openTransf(module: PSym, filename: string): PTransf =
  846. new(result)
  847. result.contSyms = @[]
  848. result.breakSyms = @[]
  849. result.module = module
  850. proc flattenStmts(n: PNode) =
  851. var goOn = true
  852. while goOn:
  853. goOn = false
  854. var i = 0
  855. while i < n.len:
  856. let it = n[i]
  857. if it.kind in {nkStmtList, nkStmtListExpr}:
  858. n.sons[i..i] = it.sons[0..<it.len]
  859. goOn = true
  860. inc i
  861. proc liftDeferAux(n: PNode) =
  862. if n.kind in {nkStmtList, nkStmtListExpr}:
  863. flattenStmts(n)
  864. var goOn = true
  865. while goOn:
  866. goOn = false
  867. let last = n.len-1
  868. for i in 0..last:
  869. if n.sons[i].kind == nkDefer:
  870. let deferPart = newNodeI(nkFinally, n.sons[i].info)
  871. deferPart.add n.sons[i].sons[0]
  872. var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
  873. var body = newNodeI(n.kind, n.sons[i].info)
  874. if i < last:
  875. body.sons = n.sons[(i+1)..last]
  876. tryStmt.addSon(body)
  877. tryStmt.addSon(deferPart)
  878. n.sons[i] = tryStmt
  879. n.sons.setLen(i+1)
  880. n.typ = n.sons[i].typ
  881. goOn = true
  882. break
  883. for i in 0..n.safeLen-1:
  884. liftDeferAux(n.sons[i])
  885. template liftDefer(c, root) =
  886. if c.deferDetected:
  887. liftDeferAux(root)
  888. proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
  889. if nfTransf in n.flags or prc.kind in {skTemplate}:
  890. result = n
  891. else:
  892. var c = openTransf(module, "")
  893. result = liftLambdas(prc, n, c.tooEarly)
  894. #result = n
  895. result = processTransf(c, result, prc)
  896. liftDefer(c, result)
  897. #result = liftLambdas(prc, result)
  898. incl(result.flags, nfTransf)
  899. when useEffectSystem: trackProc(prc, result)
  900. #if prc.name.s == "testbody":
  901. # echo renderTree(result)
  902. proc transformStmt*(module: PSym, n: PNode): PNode =
  903. if nfTransf in n.flags:
  904. result = n
  905. else:
  906. var c = openTransf(module, "")
  907. result = processTransf(c, n, module)
  908. liftDefer(c, result)
  909. #result = liftLambdasForTopLevel(module, result)
  910. incl(result.flags, nfTransf)
  911. when useEffectSystem: trackTopLevelStmt(module, result)
  912. #if n.info ?? "temp.nim":
  913. # echo renderTree(result, {renderIds})
  914. proc transformExpr*(module: PSym, n: PNode): PNode =
  915. if nfTransf in n.flags:
  916. result = n
  917. else:
  918. var c = openTransf(module, "")
  919. result = processTransf(c, n, module)
  920. liftDefer(c, result)
  921. incl(result.flags, nfTransf)