PageRenderTime 59ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/compiler/renderer.nim

https://bitbucket.org/ivanhernandez/nimrod
Nim | 1248 lines | 1205 code | 26 blank | 17 comment | 42 complexity | 3f171949ae7ac4c68c3916418fe573d9 MD5 | raw file
  1. #
  2. #
  3. # The Nimrod Compiler
  4. # (c) Copyright 2012 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 renderer of the standard Nimrod representation.
  10. import
  11. lexer, options, idents, strutils, ast, msgs, lists
  12. type
  13. TRenderFlag* = enum
  14. renderNone, renderNoBody, renderNoComments, renderDocComments,
  15. renderNoPragmas, renderIds
  16. TRenderFlags* = set[TRenderFlag]
  17. TRenderTok*{.final.} = object
  18. kind*: TTokType
  19. length*: int16
  20. TRenderTokSeq* = seq[TRenderTok]
  21. TSrcGen*{.final.} = object
  22. indent*: int
  23. lineLen*: int
  24. pos*: int # current position for iteration over the buffer
  25. idx*: int # current token index for iteration over the buffer
  26. tokens*: TRenderTokSeq
  27. buf*: string
  28. pendingNL*: int # negative if not active; else contains the
  29. # indentation value
  30. comStack*: seq[PNode] # comment stack
  31. flags*: TRenderFlags
  32. proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {})
  33. proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string
  34. proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {})
  35. proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string)
  36. # implementation
  37. # We render the source code in a two phases: The first
  38. # determines how long the subtree will likely be, the second
  39. # phase appends to a buffer that will be the output.
  40. proc isKeyword*(s: string): bool =
  41. var i = getIdent(s)
  42. if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
  43. (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
  44. result = true
  45. proc renderDefinitionName*(s: PSym): string =
  46. let x = s.name.s
  47. if x[0] in SymStartChars and not renderer.isKeyword(x): result = x
  48. else: result = '`' & x & '`'
  49. const
  50. IndentWidth = 2
  51. longIndentWid = 4
  52. MaxLineLen = 80
  53. LineCommentColumn = 30
  54. proc InitSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
  55. g.comStack = @[]
  56. g.tokens = @[]
  57. g.indent = 0
  58. g.lineLen = 0
  59. g.pos = 0
  60. g.idx = 0
  61. g.buf = ""
  62. g.flags = renderFlags
  63. g.pendingNL = - 1
  64. proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
  65. var length = len(g.tokens)
  66. setlen(g.tokens, length + 1)
  67. g.tokens[length].kind = kind
  68. g.tokens[length].length = int16(len(s))
  69. add(g.buf, s)
  70. proc addPendingNL(g: var TSrcGen) =
  71. if g.pendingNL >= 0:
  72. addTok(g, tkInd, "\n" & repeatChar(g.pendingNL))
  73. g.lineLen = g.pendingNL
  74. g.pendingNL = - 1
  75. proc putNL(g: var TSrcGen, indent: int) =
  76. if g.pendingNL >= 0: addPendingNL(g)
  77. else: addTok(g, tkInd, "\n")
  78. g.pendingNL = indent
  79. g.lineLen = indent
  80. proc putNL(g: var TSrcGen) =
  81. putNL(g, g.indent)
  82. proc optNL(g: var TSrcGen, indent: int) =
  83. g.pendingNL = indent
  84. g.lineLen = indent # BUGFIX
  85. proc optNL(g: var TSrcGen) =
  86. optNL(g, g.indent)
  87. proc indentNL(g: var TSrcGen) =
  88. inc(g.indent, indentWidth)
  89. g.pendingNL = g.indent
  90. g.lineLen = g.indent
  91. proc Dedent(g: var TSrcGen) =
  92. dec(g.indent, indentWidth)
  93. assert(g.indent >= 0)
  94. if g.pendingNL > indentWidth:
  95. Dec(g.pendingNL, indentWidth)
  96. Dec(g.lineLen, indentWidth)
  97. proc put(g: var TSrcGen, kind: TTokType, s: string) =
  98. addPendingNL(g)
  99. if len(s) > 0:
  100. addTok(g, kind, s)
  101. inc(g.lineLen, len(s))
  102. proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) =
  103. # use this for tokens over multiple lines.
  104. addPendingNL(g)
  105. addTok(g, kind, s)
  106. g.lineLen = lineLen
  107. proc toNimChar(c: Char): string =
  108. case c
  109. of '\0': result = "\\0"
  110. of '\x01'..'\x1F', '\x80'..'\xFF': result = "\\x" & strutils.toHex(ord(c), 2)
  111. of '\'', '\"', '\\': result = '\\' & c
  112. else: result = c & ""
  113. proc makeNimString(s: string): string =
  114. result = "\""
  115. for i in countup(0, len(s)-1): add(result, toNimChar(s[i]))
  116. add(result, '\"')
  117. proc putComment(g: var TSrcGen, s: string) =
  118. var i = 0
  119. var comIndent = 1
  120. var isCode = (len(s) >= 2) and (s[1] != ' ')
  121. var ind = g.lineLen
  122. var com = ""
  123. while true:
  124. case s[i]
  125. of '\0':
  126. break
  127. of '\x0D':
  128. put(g, tkComment, com)
  129. com = ""
  130. inc(i)
  131. if s[i] == '\x0A': inc(i)
  132. optNL(g, ind)
  133. of '\x0A':
  134. put(g, tkComment, com)
  135. com = ""
  136. inc(i)
  137. optNL(g, ind)
  138. of '#':
  139. add(com, s[i])
  140. inc(i)
  141. comIndent = 0
  142. while s[i] == ' ':
  143. add(com, s[i])
  144. inc(i)
  145. inc(comIndent)
  146. of ' ', '\x09':
  147. add(com, s[i])
  148. inc(i)
  149. else:
  150. # we may break the comment into a multi-line comment if the line
  151. # gets too long:
  152. # compute length of the following word:
  153. var j = i
  154. while s[j] > ' ': inc(j)
  155. if not isCode and (g.lineLen + (j - i) > MaxLineLen):
  156. put(g, tkComment, com)
  157. optNL(g, ind)
  158. com = '#' & repeatChar(comIndent)
  159. while s[i] > ' ':
  160. add(com, s[i])
  161. inc(i)
  162. put(g, tkComment, com)
  163. optNL(g)
  164. proc maxLineLength(s: string): int =
  165. result = 0
  166. var i = 0
  167. var lineLen = 0
  168. while true:
  169. case s[i]
  170. of '\0':
  171. break
  172. of '\x0D':
  173. inc(i)
  174. if s[i] == '\x0A': inc(i)
  175. result = max(result, lineLen)
  176. lineLen = 0
  177. of '\x0A':
  178. inc(i)
  179. result = max(result, lineLen)
  180. lineLen = 0
  181. else:
  182. inc(lineLen)
  183. inc(i)
  184. proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
  185. var i = 0
  186. var hi = len(s) - 1
  187. var str = ""
  188. while i <= hi:
  189. case s[i]
  190. of '\x0D':
  191. put(g, kind, str)
  192. str = ""
  193. inc(i)
  194. if (i <= hi) and (s[i] == '\x0A'): inc(i)
  195. optNL(g, 0)
  196. of '\x0A':
  197. put(g, kind, str)
  198. str = ""
  199. inc(i)
  200. optNL(g, 0)
  201. else:
  202. add(str, s[i])
  203. inc(i)
  204. put(g, kind, str)
  205. proc containsNL(s: string): bool =
  206. for i in countup(0, len(s) - 1):
  207. case s[i]
  208. of '\x0D', '\x0A':
  209. return true
  210. else:
  211. nil
  212. result = false
  213. proc pushCom(g: var TSrcGen, n: PNode) =
  214. var length = len(g.comStack)
  215. setlen(g.comStack, length + 1)
  216. g.comStack[length] = n
  217. proc popAllComs(g: var TSrcGen) =
  218. setlen(g.comStack, 0)
  219. proc popCom(g: var TSrcGen) =
  220. setlen(g.comStack, len(g.comStack) - 1)
  221. const
  222. Space = " "
  223. proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
  224. result = false
  225. if n.comment != nil:
  226. result = (renderNoComments notin g.flags) or
  227. (renderDocComments in g.flags) and startsWith(n.comment, "##")
  228. proc gcom(g: var TSrcGen, n: PNode) =
  229. assert(n != nil)
  230. if shouldRenderComment(g, n):
  231. if (g.pendingNL < 0) and (len(g.buf) > 0) and (g.buf[len(g.buf)-1] != ' '):
  232. put(g, tkSpaces, Space)
  233. # Before long comments we cannot make sure that a newline is generated,
  234. # because this might be wrong. But it is no problem in practice.
  235. if (g.pendingNL < 0) and (len(g.buf) > 0) and
  236. (g.lineLen < LineCommentColumn):
  237. var ml = maxLineLength(n.comment)
  238. if ml + LineCommentColumn <= maxLineLen:
  239. put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen))
  240. putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
  241. proc gcoms(g: var TSrcGen) =
  242. for i in countup(0, high(g.comStack)): gcom(g, g.comStack[i])
  243. popAllComs(g)
  244. proc lsub(n: PNode): int
  245. proc litAux(n: PNode, x: biggestInt, size: int): string =
  246. proc skip(t: PType): PType =
  247. result = t
  248. while result.kind in {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
  249. tyConst, tyMutable}:
  250. result = lastSon(result)
  251. if n.typ != nil and n.typ.skip.kind in {tyBool, tyEnum}:
  252. let enumfields = n.typ.skip.n
  253. # we need a slow linear search because of enums with holes:
  254. for e in items(enumfields):
  255. if e.sym.position == x: return e.sym.name.s
  256. if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
  257. elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
  258. elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
  259. else: result = $x
  260. proc ulitAux(n: PNode, x: biggestInt, size: int): string =
  261. if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
  262. elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
  263. elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
  264. else: result = $x
  265. # XXX proper unsigned output!
  266. proc atom(n: PNode): string =
  267. var f: float32
  268. case n.kind
  269. of nkEmpty: result = ""
  270. of nkIdent: result = n.ident.s
  271. of nkSym: result = n.sym.name.s
  272. of nkStrLit: result = makeNimString(n.strVal)
  273. of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"'
  274. of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\""
  275. of nkCharLit: result = '\'' & toNimChar(chr(int(n.intVal))) & '\''
  276. of nkIntLit: result = litAux(n, n.intVal, 4)
  277. of nkInt8Lit: result = litAux(n, n.intVal, 1) & "\'i8"
  278. of nkInt16Lit: result = litAux(n, n.intVal, 2) & "\'i16"
  279. of nkInt32Lit: result = litAux(n, n.intVal, 4) & "\'i32"
  280. of nkInt64Lit: result = litAux(n, n.intVal, 8) & "\'i64"
  281. of nkUIntLit: result = ulitAux(n, n.intVal, 4) & "\'u"
  282. of nkUInt8Lit: result = ulitAux(n, n.intVal, 1) & "\'u8"
  283. of nkUInt16Lit: result = ulitAux(n, n.intVal, 2) & "\'u16"
  284. of nkUInt32Lit: result = ulitAux(n, n.intVal, 4) & "\'u32"
  285. of nkUInt64Lit: result = ulitAux(n, n.intVal, 8) & "\'u64"
  286. of nkFloatLit:
  287. if n.flags * {nfBase2, nfBase8, nfBase16} == {}: result = $(n.floatVal)
  288. else: result = litAux(n, (cast[PInt64](addr(n.floatVal)))[] , 8)
  289. of nkFloat32Lit:
  290. if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
  291. result = $n.floatVal & "\'f32"
  292. else:
  293. f = n.floatVal
  294. result = litAux(n, (cast[PInt32](addr(f)))[], 4) & "\'f32"
  295. of nkFloat64Lit:
  296. if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
  297. result = $n.floatVal & "\'f64"
  298. else:
  299. result = litAux(n, (cast[PInt64](addr(n.floatVal)))[], 8) & "\'f64"
  300. of nkNilLit: result = "nil"
  301. of nkType:
  302. if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
  303. else: result = "[type node]"
  304. else:
  305. InternalError("rnimsyn.atom " & $n.kind)
  306. result = ""
  307. proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int =
  308. assert(theEnd < 0)
  309. result = 0
  310. for i in countup(start, sonsLen(n) + theEnd):
  311. inc(result, lsub(n.sons[i]))
  312. inc(result, 2) # for ``, ``
  313. if result > 0:
  314. dec(result, 2) # last does not get a comma!
  315. proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int =
  316. assert(theEnd < 0)
  317. result = 0
  318. for i in countup(start, sonsLen(n) + theEnd): inc(result, lsub(n.sons[i]))
  319. proc lsub(n: PNode): int =
  320. # computes the length of a tree
  321. if isNil(n): return 0
  322. if n.comment != nil: return maxLineLen + 1
  323. case n.kind
  324. of nkEmpty: result = 0
  325. of nkTripleStrLit:
  326. if containsNL(n.strVal): result = maxLineLen + 1
  327. else: result = len(atom(n))
  328. of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
  329. result = len(atom(n))
  330. of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern:
  331. result = lsub(n.sons[0]) + lcomma(n, 1) + 2
  332. of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1])
  333. of nkCast: result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()")
  334. of nkAddr: result = lsub(n.sons[0]) + len("addr()")
  335. of nkStaticExpr: result = lsub(n.sons[0]) + len("static_")
  336. of nkHiddenAddr, nkHiddenDeref: result = lsub(n.sons[0])
  337. of nkCommand: result = lsub(n.sons[0]) + lcomma(n, 1) + 1
  338. of nkExprEqExpr, nkAsgn, nkFastAsgn: result = lsons(n) + 3
  339. of nkPar, nkCurly, nkBracket, nkClosure: result = lcomma(n) + 2
  340. of nkArgList: result = lcomma(n)
  341. of nkTableConstr:
  342. result = if n.len > 0: lcomma(n) + 2 else: len("{:}")
  343. of nkClosedSymChoice, nkOpenSymChoice:
  344. result = lsons(n) + len("()") + sonsLen(n) - 1
  345. of nkTupleTy: result = lcomma(n) + len("tuple[]")
  346. of nkDotExpr: result = lsons(n) + 1
  347. of nkBind: result = lsons(n) + len("bind_")
  348. of nkBindStmt: result = lcomma(n) + len("bind_")
  349. of nkMixinStmt: result = lcomma(n) + len("mixin_")
  350. of nkCheckedFieldExpr: result = lsub(n.sons[0])
  351. of nkLambda: result = lsons(n) + len("proc__=_")
  352. of nkDo: result = lsons(n) + len("do__:_")
  353. of nkConstDef, nkIdentDefs:
  354. result = lcomma(n, 0, - 3)
  355. var L = sonsLen(n)
  356. if n.sons[L - 2].kind != nkEmpty: result = result + lsub(n.sons[L - 2]) + 2
  357. if n.sons[L - 1].kind != nkEmpty: result = result + lsub(n.sons[L - 1]) + 3
  358. of nkVarTuple: result = lcomma(n, 0, - 3) + len("() = ") + lsub(lastSon(n))
  359. of nkChckRangeF: result = len("chckRangeF") + 2 + lcomma(n)
  360. of nkChckRange64: result = len("chckRange64") + 2 + lcomma(n)
  361. of nkChckRange: result = len("chckRange") + 2 + lcomma(n)
  362. of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
  363. result = 2
  364. if sonsLen(n) >= 1: result = result + lsub(n.sons[0])
  365. result = result + lcomma(n, 1)
  366. of nkExprColonExpr: result = lsons(n) + 2
  367. of nkInfix: result = lsons(n) + 2
  368. of nkPrefix: result = lsons(n) + 1
  369. of nkPostfix: result = lsons(n)
  370. of nkCallStrLit: result = lsons(n)
  371. of nkPragmaExpr: result = lsub(n.sons[0]) + lcomma(n, 1)
  372. of nkRange: result = lsons(n) + 2
  373. of nkDerefExpr: result = lsub(n.sons[0]) + 2
  374. of nkAccQuoted: result = lsons(n) + 2
  375. of nkIfExpr:
  376. result = lsub(n.sons[0].sons[0]) + lsub(n.sons[0].sons[1]) + lsons(n, 1) +
  377. len("if_:_")
  378. of nkElifExpr: result = lsons(n) + len("_elif_:_")
  379. of nkElseExpr: result = lsub(n.sons[0]) + len("_else:_") # type descriptions
  380. of nkTypeOfExpr: result = lsub(n.sons[0]) + len("type_")
  381. of nkRefTy: result = lsub(n.sons[0]) + len("ref_")
  382. of nkPtrTy: result = lsub(n.sons[0]) + len("ptr_")
  383. of nkVarTy: result = lsub(n.sons[0]) + len("var_")
  384. of nkDistinctTy: result = lsub(n.sons[0]) + len("Distinct_")
  385. of nkTypeDef: result = lsons(n) + 3
  386. of nkOfInherit: result = lsub(n.sons[0]) + len("of_")
  387. of nkProcTy: result = lsons(n) + len("proc_")
  388. of nkEnumTy:
  389. if sonsLen(n) > 0:
  390. result = lsub(n.sons[0]) + lcomma(n, 1) + len("enum_")
  391. else:
  392. result = len("enum")
  393. of nkEnumFieldDef: result = lsons(n) + 3
  394. of nkVarSection, nkLetSection:
  395. if sonsLen(n) > 1: result = maxLineLen + 1
  396. else: result = lsons(n) + len("var_")
  397. of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
  398. of nkRaiseStmt: result = lsub(n.sons[0]) + len("raise_")
  399. of nkYieldStmt: result = lsub(n.sons[0]) + len("yield_")
  400. of nkDiscardStmt: result = lsub(n.sons[0]) + len("discard_")
  401. of nkBreakStmt: result = lsub(n.sons[0]) + len("break_")
  402. of nkContinueStmt: result = lsub(n.sons[0]) + len("continue_")
  403. of nkPragma: result = lcomma(n) + 4
  404. of nkCommentStmt: result = len(n.comment)
  405. of nkOfBranch: result = lcomma(n, 0, - 2) + lsub(lastSon(n)) + len("of_:_")
  406. of nkElifBranch: result = lsons(n) + len("elif_:_")
  407. of nkElse: result = lsub(n.sons[0]) + len("else:_")
  408. of nkFinally: result = lsub(n.sons[0]) + len("finally:_")
  409. of nkGenericParams: result = lcomma(n) + 2
  410. of nkFormalParams:
  411. result = lcomma(n, 1) + 2
  412. if n.sons[0].kind != nkEmpty: result = result + lsub(n.sons[0]) + 2
  413. of nkExceptBranch:
  414. result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_")
  415. else: result = maxLineLen + 1
  416. proc fits(g: TSrcGen, x: int): bool =
  417. result = x + g.lineLen <= maxLineLen
  418. type
  419. TSubFlag = enum
  420. rfLongMode, rfNoIndent, rfInConstExpr
  421. TSubFlags = set[TSubFlag]
  422. TContext = tuple[spacing: int, flags: TSubFlags]
  423. const
  424. emptyContext: TContext = (spacing: 0, flags: {})
  425. proc initContext(c: var TContext) =
  426. c.spacing = 0
  427. c.flags = {}
  428. proc gsub(g: var TSrcGen, n: PNode, c: TContext)
  429. proc gsub(g: var TSrcGen, n: PNode) =
  430. var c: TContext
  431. initContext(c)
  432. gsub(g, n, c)
  433. proc hasCom(n: PNode): bool =
  434. result = false
  435. if n.comment != nil: return true
  436. case n.kind
  437. of nkEmpty..nkNilLit: nil
  438. else:
  439. for i in countup(0, sonsLen(n) - 1):
  440. if hasCom(n.sons[i]): return true
  441. proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
  442. put(g, kind, s)
  443. put(g, tkSpaces, Space)
  444. proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
  445. theEnd: int = - 1, separator = tkComma) =
  446. for i in countup(start, sonsLen(n) + theEnd):
  447. var c = i < sonsLen(n) + theEnd
  448. var sublen = lsub(n.sons[i]) + ord(c)
  449. if not fits(g, sublen) and (ind + sublen < maxLineLen): optNL(g, ind)
  450. gsub(g, n.sons[i])
  451. if c:
  452. putWithSpace(g, separator, TokTypeToStr[separator])
  453. if hasCom(n.sons[i]):
  454. gcoms(g)
  455. optNL(g, ind)
  456. proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
  457. theEnd: int = - 1) =
  458. var ind: int
  459. if rfInConstExpr in c.flags:
  460. ind = g.indent + indentWidth
  461. else:
  462. ind = g.lineLen
  463. if ind > maxLineLen div 2: ind = g.indent + longIndentWid
  464. gcommaAux(g, n, ind, start, theEnd)
  465. proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
  466. var ind = g.lineLen
  467. if ind > maxLineLen div 2: ind = g.indent + longIndentWid
  468. gcommaAux(g, n, ind, start, theEnd)
  469. proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
  470. var ind = g.lineLen
  471. if ind > maxLineLen div 2: ind = g.indent + longIndentWid
  472. gcommaAux(g, n, ind, start, theEnd, tkSemicolon)
  473. proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
  474. theEnd: int = - 1) =
  475. for i in countup(start, sonsLen(n) + theEnd): gsub(g, n.sons[i], c)
  476. proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
  477. k: string) =
  478. if sonsLen(n) == 0: return # empty var sections are possible
  479. putWithSpace(g, kind, k)
  480. gcoms(g)
  481. indentNL(g)
  482. for i in countup(0, sonsLen(n) - 1):
  483. optNL(g)
  484. gsub(g, n.sons[i], c)
  485. gcoms(g)
  486. dedent(g)
  487. proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool =
  488. result = n.comment != nil
  489. if not result:
  490. # check further
  491. for i in countup(start, sonsLen(n) + theEnd):
  492. if (lsub(n.sons[i]) > maxLineLen):
  493. result = true
  494. break
  495. proc gstmts(g: var TSrcGen, n: PNode, c: TContext) =
  496. if n.kind == nkEmpty: return
  497. if (n.kind == nkStmtList) or (n.kind == nkStmtListExpr):
  498. indentNL(g)
  499. for i in countup(0, sonsLen(n) - 1):
  500. optNL(g)
  501. gsub(g, n.sons[i])
  502. gcoms(g)
  503. dedent(g)
  504. else:
  505. if rfLongMode in c.flags: indentNL(g)
  506. gsub(g, n)
  507. gcoms(g)
  508. optNL(g)
  509. if rfLongMode in c.flags: dedent(g)
  510. proc gif(g: var TSrcGen, n: PNode) =
  511. var c: TContext
  512. gsub(g, n.sons[0].sons[0])
  513. initContext(c)
  514. putWithSpace(g, tkColon, ":")
  515. if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > maxLineLen):
  516. incl(c.flags, rfLongMode)
  517. gcoms(g) # a good place for comments
  518. gstmts(g, n.sons[0].sons[1], c)
  519. var length = sonsLen(n)
  520. for i in countup(1, length - 1):
  521. optNL(g)
  522. gsub(g, n.sons[i], c)
  523. proc gwhile(g: var TSrcGen, n: PNode) =
  524. var c: TContext
  525. putWithSpace(g, tkWhile, "while")
  526. gsub(g, n.sons[0])
  527. putWithSpace(g, tkColon, ":")
  528. initContext(c)
  529. if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
  530. incl(c.flags, rfLongMode)
  531. gcoms(g) # a good place for comments
  532. gstmts(g, n.sons[1], c)
  533. proc gpattern(g: var TSrcGen, n: PNode) =
  534. var c: TContext
  535. put(g, tkCurlyLe, "{")
  536. initContext(c)
  537. if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
  538. incl(c.flags, rfLongMode)
  539. gcoms(g) # a good place for comments
  540. gstmts(g, n.sons[0], c)
  541. put(g, tkCurlyRi, "}")
  542. proc gpragmaBlock(g: var TSrcGen, n: PNode) =
  543. var c: TContext
  544. gsub(g, n.sons[0])
  545. putWithSpace(g, tkColon, ":")
  546. initContext(c)
  547. if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
  548. incl(c.flags, rfLongMode)
  549. gcoms(g) # a good place for comments
  550. gstmts(g, n.sons[1], c)
  551. proc gtry(g: var TSrcGen, n: PNode) =
  552. var c: TContext
  553. put(g, tkTry, "try")
  554. putWithSpace(g, tkColon, ":")
  555. initContext(c)
  556. if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
  557. incl(c.flags, rfLongMode)
  558. gcoms(g) # a good place for comments
  559. gstmts(g, n.sons[0], c)
  560. gsons(g, n, c, 1)
  561. proc gfor(g: var TSrcGen, n: PNode) =
  562. var c: TContext
  563. var length = sonsLen(n)
  564. putWithSpace(g, tkFor, "for")
  565. initContext(c)
  566. if longMode(n) or
  567. (lsub(n.sons[length - 1]) + lsub(n.sons[length - 2]) + 6 + g.lineLen >
  568. maxLineLen):
  569. incl(c.flags, rfLongMode)
  570. gcomma(g, n, c, 0, - 3)
  571. put(g, tkSpaces, Space)
  572. putWithSpace(g, tkIn, "in")
  573. gsub(g, n.sons[length - 2], c)
  574. putWithSpace(g, tkColon, ":")
  575. gcoms(g)
  576. gstmts(g, n.sons[length - 1], c)
  577. proc gmacro(g: var TSrcGen, n: PNode) =
  578. var c: TContext
  579. initContext(c)
  580. gsub(g, n.sons[0])
  581. putWithSpace(g, tkColon, ":")
  582. if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
  583. incl(c.flags, rfLongMode)
  584. gcoms(g)
  585. gsons(g, n, c, 1)
  586. proc gcase(g: var TSrcGen, n: PNode) =
  587. var c: TContext
  588. initContext(c)
  589. var length = sonsLen(n)
  590. var last = if n.sons[length-1].kind == nkElse: -2 else: -1
  591. if longMode(n, 0, last): incl(c.flags, rfLongMode)
  592. putWithSpace(g, tkCase, "case")
  593. gsub(g, n.sons[0])
  594. gcoms(g)
  595. optNL(g)
  596. gsons(g, n, c, 1, last)
  597. if last == - 2:
  598. initContext(c)
  599. if longMode(n.sons[length - 1]): incl(c.flags, rfLongMode)
  600. gsub(g, n.sons[length - 1], c)
  601. proc gproc(g: var TSrcGen, n: PNode) =
  602. var c: TContext
  603. if n.sons[namePos].kind == nkSym:
  604. put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym))
  605. else:
  606. gsub(g, n.sons[namePos])
  607. if n.sons[patternPos].kind != nkEmpty:
  608. gpattern(g, n.sons[patternPos])
  609. gsub(g, n.sons[genericParamsPos])
  610. gsub(g, n.sons[paramsPos])
  611. gsub(g, n.sons[pragmasPos])
  612. if renderNoBody notin g.flags:
  613. if n.sons[bodyPos].kind != nkEmpty:
  614. put(g, tkSpaces, Space)
  615. putWithSpace(g, tkEquals, "=")
  616. indentNL(g)
  617. gcoms(g)
  618. dedent(g)
  619. initContext(c)
  620. gstmts(g, n.sons[bodyPos], c)
  621. putNL(g)
  622. else:
  623. indentNL(g)
  624. gcoms(g)
  625. dedent(g)
  626. proc gblock(g: var TSrcGen, n: PNode) =
  627. var c: TContext
  628. initContext(c)
  629. if n.sons[0].kind != nkEmpty:
  630. putWithSpace(g, tkBlock, "block")
  631. gsub(g, n.sons[0])
  632. else:
  633. put(g, tkBlock, "block")
  634. putWithSpace(g, tkColon, ":")
  635. if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
  636. incl(c.flags, rfLongMode)
  637. gcoms(g)
  638. # XXX I don't get why this is needed here! gstmts should already handle this!
  639. indentNL(g)
  640. gstmts(g, n.sons[1], c)
  641. dedent(g)
  642. proc gstaticStmt(g: var TSrcGen, n: PNode) =
  643. var c: TContext
  644. putWithSpace(g, tkStatic, "static")
  645. putWithSpace(g, tkColon, ":")
  646. initContext(c)
  647. if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
  648. incl(c.flags, rfLongMode)
  649. gcoms(g) # a good place for comments
  650. gstmts(g, n.sons[0], c)
  651. proc gasm(g: var TSrcGen, n: PNode) =
  652. putWithSpace(g, tkAsm, "asm")
  653. gsub(g, n.sons[0])
  654. gcoms(g)
  655. gsub(g, n.sons[1])
  656. proc gident(g: var TSrcGen, n: PNode) =
  657. var t: TTokType
  658. var s = atom(n)
  659. if (s[0] in lexer.SymChars):
  660. if (n.kind == nkIdent):
  661. if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
  662. (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
  663. t = tkSymbol
  664. else:
  665. t = TTokType(n.ident.id + ord(tkSymbol))
  666. else:
  667. t = tkSymbol
  668. else:
  669. t = tkOpr
  670. put(g, t, s)
  671. if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
  672. proc doParamsAux(g: var TSrcGen, params: PNode) =
  673. if params.len > 1:
  674. put(g, tkParLe, "(")
  675. gsemicolon(g, params, 1)
  676. put(g, tkParRi, ")")
  677. if params.sons[0].kind != nkEmpty:
  678. putWithSpace(g, tkOpr, "->")
  679. gsub(g, params.sons[0])
  680. proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
  681. if isNil(n): return
  682. var
  683. L: int
  684. a: TContext
  685. if n.comment != nil: pushCom(g, n)
  686. case n.kind # atoms:
  687. of nkTripleStrLit: putRawStr(g, tkTripleStrLit, n.strVal)
  688. of nkEmpty: nil
  689. of nkType: put(g, tkInvalid, atom(n))
  690. of nkSym, nkIdent: gident(g, n)
  691. of nkIntLit: put(g, tkIntLit, atom(n))
  692. of nkInt8Lit: put(g, tkInt8Lit, atom(n))
  693. of nkInt16Lit: put(g, tkInt16Lit, atom(n))
  694. of nkInt32Lit: put(g, tkInt32Lit, atom(n))
  695. of nkInt64Lit: put(g, tkInt64Lit, atom(n))
  696. of nkUIntLit: put(g, tkUIntLit, atom(n))
  697. of nkUInt8Lit: put(g, tkUInt8Lit, atom(n))
  698. of nkUInt16Lit: put(g, tkUInt16Lit, atom(n))
  699. of nkUInt32Lit: put(g, tkUInt32Lit, atom(n))
  700. of nkUInt64Lit: put(g, tkUInt64Lit, atom(n))
  701. of nkFloatLit: put(g, tkFloatLit, atom(n))
  702. of nkFloat32Lit: put(g, tkFloat32Lit, atom(n))
  703. of nkFloat64Lit: put(g, tkFloat64Lit, atom(n))
  704. of nkFloat128Lit: put(g, tkFloat128Lit, atom(n))
  705. of nkStrLit: put(g, tkStrLit, atom(n))
  706. of nkRStrLit: put(g, tkRStrLit, atom(n))
  707. of nkCharLit: put(g, tkCharLit, atom(n))
  708. of nkNilLit: put(g, tkNil, atom(n)) # complex expressions
  709. of nkCall, nkConv, nkDotCall, nkPattern:
  710. if sonsLen(n) >= 1: gsub(g, n.sons[0])
  711. put(g, tkParLe, "(")
  712. gcomma(g, n, 1)
  713. put(g, tkParRi, ")")
  714. of nkCallStrLit:
  715. gsub(g, n.sons[0])
  716. if n.sons[1].kind == nkRStrLit:
  717. put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
  718. else:
  719. gsub(g, n.sons[1])
  720. of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: gsub(g, n.sons[1])
  721. of nkCast:
  722. put(g, tkCast, "cast")
  723. put(g, tkBracketLe, "[")
  724. gsub(g, n.sons[0])
  725. put(g, tkBracketRi, "]")
  726. put(g, tkParLe, "(")
  727. gsub(g, n.sons[1])
  728. put(g, tkParRi, ")")
  729. of nkAddr:
  730. put(g, tkAddr, "addr")
  731. put(g, tkParLe, "(")
  732. gsub(g, n.sons[0])
  733. put(g, tkParRi, ")")
  734. of nkStaticExpr:
  735. put(g, tkStatic, "static")
  736. put(g, tkSpaces, space)
  737. gsub(g, n.sons[0])
  738. of nkBracketExpr:
  739. gsub(g, n.sons[0])
  740. put(g, tkBracketLe, "[")
  741. gcomma(g, n, 1)
  742. put(g, tkBracketRi, "]")
  743. of nkCurlyExpr:
  744. gsub(g, n.sons[0])
  745. put(g, tkCurlyLe, "{")
  746. gcomma(g, n, 1)
  747. put(g, tkCurlyRi, "}")
  748. of nkPragmaExpr:
  749. gsub(g, n.sons[0])
  750. gcomma(g, n, 1)
  751. of nkCommand:
  752. gsub(g, n.sons[0])
  753. put(g, tkSpaces, space)
  754. gcomma(g, n, 1)
  755. of nkExprEqExpr, nkAsgn, nkFastAsgn:
  756. gsub(g, n.sons[0])
  757. put(g, tkSpaces, Space)
  758. putWithSpace(g, tkEquals, "=")
  759. gsub(g, n.sons[1])
  760. of nkChckRangeF:
  761. put(g, tkSymbol, "chckRangeF")
  762. put(g, tkParLe, "(")
  763. gcomma(g, n)
  764. put(g, tkParRi, ")")
  765. of nkChckRange64:
  766. put(g, tkSymbol, "chckRange64")
  767. put(g, tkParLe, "(")
  768. gcomma(g, n)
  769. put(g, tkParRi, ")")
  770. of nkChckRange:
  771. put(g, tkSymbol, "chckRange")
  772. put(g, tkParLe, "(")
  773. gcomma(g, n)
  774. put(g, tkParRi, ")")
  775. of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
  776. if sonsLen(n) >= 1: gsub(g, n.sons[0])
  777. put(g, tkParLe, "(")
  778. gcomma(g, n, 1)
  779. put(g, tkParRi, ")")
  780. of nkClosedSymChoice, nkOpenSymChoice:
  781. put(g, tkParLe, "(")
  782. for i in countup(0, sonsLen(n) - 1):
  783. if i > 0: put(g, tkOpr, "|")
  784. gsub(g, n.sons[i], c)
  785. put(g, tkParRi, ")")
  786. of nkPar, nkClosure:
  787. put(g, tkParLe, "(")
  788. gcomma(g, n, c)
  789. put(g, tkParRi, ")")
  790. of nkCurly:
  791. put(g, tkCurlyLe, "{")
  792. gcomma(g, n, c)
  793. put(g, tkCurlyRi, "}")
  794. of nkArgList:
  795. gcomma(g, n, c)
  796. of nkTableConstr:
  797. put(g, tkCurlyLe, "{")
  798. if n.len > 0: gcomma(g, n, c)
  799. else: put(g, tkColon, ":")
  800. put(g, tkCurlyRi, "}")
  801. of nkBracket:
  802. put(g, tkBracketLe, "[")
  803. gcomma(g, n, c)
  804. put(g, tkBracketRi, "]")
  805. of nkDotExpr:
  806. gsub(g, n.sons[0])
  807. put(g, tkDot, ".")
  808. gsub(g, n.sons[1])
  809. of nkBind:
  810. putWithSpace(g, tkBind, "bind")
  811. gsub(g, n.sons[0])
  812. of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
  813. gsub(g, n.sons[0])
  814. of nkLambda:
  815. putWithSpace(g, tkLambda, "proc")
  816. gsub(g, n.sons[paramsPos])
  817. gsub(g, n.sons[pragmasPos])
  818. put(g, tkSpaces, Space)
  819. putWithSpace(g, tkEquals, "=")
  820. gsub(g, n.sons[bodyPos])
  821. of nkDo:
  822. putWithSpace(g, tkDo, "do")
  823. doParamsAux(g, n.sons[paramsPos])
  824. gsub(g, n.sons[pragmasPos])
  825. put(g, tkColon, ":")
  826. gsub(g, n.sons[bodyPos])
  827. of nkConstDef, nkIdentDefs:
  828. gcomma(g, n, 0, - 3)
  829. var L = sonsLen(n)
  830. if n.sons[L - 2].kind != nkEmpty:
  831. putWithSpace(g, tkColon, ":")
  832. gsub(g, n.sons[L - 2])
  833. if n.sons[L - 1].kind != nkEmpty:
  834. put(g, tkSpaces, Space)
  835. putWithSpace(g, tkEquals, "=")
  836. gsub(g, n.sons[L - 1], c)
  837. of nkVarTuple:
  838. put(g, tkParLe, "(")
  839. gcomma(g, n, 0, - 3)
  840. put(g, tkParRi, ")")
  841. put(g, tkSpaces, Space)
  842. putWithSpace(g, tkEquals, "=")
  843. gsub(g, lastSon(n), c)
  844. of nkExprColonExpr:
  845. gsub(g, n.sons[0])
  846. putWithSpace(g, tkColon, ":")
  847. gsub(g, n.sons[1])
  848. of nkInfix:
  849. gsub(g, n.sons[1])
  850. put(g, tkSpaces, Space)
  851. gsub(g, n.sons[0]) # binary operator
  852. if not fits(g, lsub(n.sons[2]) + lsub(n.sons[0]) + 1):
  853. optNL(g, g.indent + longIndentWid)
  854. else:
  855. put(g, tkSpaces, Space)
  856. gsub(g, n.sons[2])
  857. of nkPrefix:
  858. gsub(g, n.sons[0])
  859. if n.len > 1:
  860. put(g, tkSpaces, space)
  861. gsub(g, n.sons[1])
  862. of nkPostfix:
  863. gsub(g, n.sons[1])
  864. gsub(g, n.sons[0])
  865. of nkRange:
  866. gsub(g, n.sons[0])
  867. put(g, tkDotDot, "..")
  868. gsub(g, n.sons[1])
  869. of nkDerefExpr:
  870. gsub(g, n.sons[0])
  871. putWithSpace(g, tkOpr, "^")
  872. # unfortunately this requires a space, because ^. would be only one opr
  873. of nkAccQuoted:
  874. put(g, tkAccent, "`")
  875. if n.len > 0: gsub(g, n.sons[0])
  876. for i in 1 .. <n.len:
  877. put(g, tkSpaces, Space)
  878. gsub(g, n.sons[i])
  879. put(g, tkAccent, "`")
  880. of nkIfExpr:
  881. putWithSpace(g, tkIf, "if")
  882. gsub(g, n.sons[0].sons[0])
  883. putWithSpace(g, tkColon, ":")
  884. gsub(g, n.sons[0].sons[1])
  885. gsons(g, n, emptyContext, 1)
  886. of nkElifExpr:
  887. putWithSpace(g, tkElif, " elif")
  888. gsub(g, n.sons[0])
  889. putWithSpace(g, tkColon, ":")
  890. gsub(g, n.sons[1])
  891. of nkElseExpr:
  892. put(g, tkElse, " else")
  893. putWithSpace(g, tkColon, ":")
  894. gsub(g, n.sons[0])
  895. of nkTypeOfExpr:
  896. putWithSpace(g, tkType, "type")
  897. gsub(g, n.sons[0])
  898. of nkRefTy:
  899. if sonsLen(n) > 0:
  900. putWithSpace(g, tkRef, "ref")
  901. gsub(g, n.sons[0])
  902. else:
  903. put(g, tkRef, "ref")
  904. of nkPtrTy:
  905. if sonsLen(n) > 0:
  906. putWithSpace(g, tkPtr, "ptr")
  907. gsub(g, n.sons[0])
  908. else:
  909. put(g, tkPtr, "ptr")
  910. of nkVarTy:
  911. if sonsLen(n) > 0:
  912. putWithSpace(g, tkVar, "var")
  913. gsub(g, n.sons[0])
  914. else:
  915. put(g, tkVar, "var")
  916. of nkDistinctTy:
  917. if sonsLen(n) > 0:
  918. putWithSpace(g, tkDistinct, "distinct")
  919. gsub(g, n.sons[0])
  920. else:
  921. put(g, tkDistinct, "distinct")
  922. of nkTypeDef:
  923. gsub(g, n.sons[0])
  924. gsub(g, n.sons[1])
  925. put(g, tkSpaces, Space)
  926. if n.sons[2].kind != nkEmpty:
  927. putWithSpace(g, tkEquals, "=")
  928. gsub(g, n.sons[2])
  929. of nkObjectTy:
  930. if sonsLen(n) > 0:
  931. putWithSpace(g, tkObject, "object")
  932. gsub(g, n.sons[0])
  933. gsub(g, n.sons[1])
  934. gcoms(g)
  935. gsub(g, n.sons[2])
  936. else:
  937. put(g, tkObject, "object")
  938. of nkRecList:
  939. indentNL(g)
  940. for i in countup(0, sonsLen(n) - 1):
  941. optNL(g)
  942. gsub(g, n.sons[i], c)
  943. gcoms(g)
  944. dedent(g)
  945. putNL(g)
  946. of nkOfInherit:
  947. putWithSpace(g, tkOf, "of")
  948. gsub(g, n.sons[0])
  949. of nkProcTy:
  950. if sonsLen(n) > 0:
  951. putWithSpace(g, tkProc, "proc")
  952. gsub(g, n.sons[0])
  953. gsub(g, n.sons[1])
  954. else:
  955. put(g, tkProc, "proc")
  956. of nkEnumTy:
  957. if sonsLen(n) > 0:
  958. putWithSpace(g, tkEnum, "enum")
  959. gsub(g, n.sons[0])
  960. gcoms(g)
  961. indentNL(g)
  962. gcommaAux(g, n, g.indent, 1)
  963. gcoms(g) # BUGFIX: comment for the last enum field
  964. dedent(g)
  965. else:
  966. put(g, tkEnum, "enum")
  967. of nkEnumFieldDef:
  968. gsub(g, n.sons[0])
  969. put(g, tkSpaces, Space)
  970. putWithSpace(g, tkEquals, "=")
  971. gsub(g, n.sons[1])
  972. of nkStmtList, nkStmtListExpr: gstmts(g, n, emptyContext)
  973. of nkIfStmt:
  974. putWithSpace(g, tkIf, "if")
  975. gif(g, n)
  976. of nkWhen, nkRecWhen:
  977. putWithSpace(g, tkWhen, "when")
  978. gif(g, n)
  979. of nkWhileStmt: gwhile(g, n)
  980. of nkPragmaBlock: gpragmaBlock(g, n)
  981. of nkCaseStmt, nkRecCase: gcase(g, n)
  982. of nkMacroStmt: gmacro(g, n)
  983. of nkTryStmt: gtry(g, n)
  984. of nkForStmt, nkParForStmt: gfor(g, n)
  985. of nkBlockStmt, nkBlockExpr: gblock(g, n)
  986. of nkStaticStmt: gstaticStmt(g, n)
  987. of nkAsmStmt: gasm(g, n)
  988. of nkProcDef:
  989. putWithSpace(g, tkProc, "proc")
  990. gproc(g, n)
  991. of nkConverterDef:
  992. putWithSpace(g, tkConverter, "converter")
  993. gproc(g, n)
  994. of nkMethodDef:
  995. putWithSpace(g, tkMethod, "method")
  996. gproc(g, n)
  997. of nkIteratorDef:
  998. putWithSpace(g, tkIterator, "iterator")
  999. gproc(g, n)
  1000. of nkMacroDef:
  1001. putWithSpace(g, tkMacro, "macro")
  1002. gproc(g, n)
  1003. of nkTemplateDef:
  1004. putWithSpace(g, tkTemplate, "template")
  1005. gproc(g, n)
  1006. of nkTypeSection:
  1007. gsection(g, n, emptyContext, tkType, "type")
  1008. of nkConstSection:
  1009. initContext(a)
  1010. incl(a.flags, rfInConstExpr)
  1011. gsection(g, n, a, tkConst, "const")
  1012. of nkVarSection, nkLetSection:
  1013. L = sonsLen(n)
  1014. if L == 0: return
  1015. if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
  1016. else: putWithSpace(g, tkLet, "let")
  1017. if L > 1:
  1018. gcoms(g)
  1019. indentNL(g)
  1020. for i in countup(0, L - 1):
  1021. optNL(g)
  1022. gsub(g, n.sons[i])
  1023. gcoms(g)
  1024. dedent(g)
  1025. else:
  1026. gsub(g, n.sons[0])
  1027. of nkReturnStmt:
  1028. putWithSpace(g, tkReturn, "return")
  1029. gsub(g, n.sons[0])
  1030. of nkRaiseStmt:
  1031. putWithSpace(g, tkRaise, "raise")
  1032. gsub(g, n.sons[0])
  1033. of nkYieldStmt:
  1034. putWithSpace(g, tkYield, "yield")
  1035. gsub(g, n.sons[0])
  1036. of nkDiscardStmt:
  1037. putWithSpace(g, tkDiscard, "discard")
  1038. gsub(g, n.sons[0])
  1039. of nkBreakStmt:
  1040. putWithSpace(g, tkBreak, "break")
  1041. gsub(g, n.sons[0])
  1042. of nkContinueStmt:
  1043. putWithSpace(g, tkContinue, "continue")
  1044. gsub(g, n.sons[0])
  1045. of nkPragma:
  1046. if renderNoPragmas notin g.flags:
  1047. put(g, tkSpaces, Space)
  1048. put(g, tkCurlyDotLe, "{.")
  1049. gcomma(g, n, emptyContext)
  1050. put(g, tkCurlyDotRi, ".}")
  1051. of nkImportStmt:
  1052. putWithSpace(g, tkImport, "import")
  1053. gcoms(g)
  1054. indentNL(g)
  1055. gcommaAux(g, n, g.indent)
  1056. dedent(g)
  1057. putNL(g)
  1058. of nkFromStmt:
  1059. putWithSpace(g, tkFrom, "from")
  1060. gsub(g, n.sons[0])
  1061. put(g, tkSpaces, Space)
  1062. putWithSpace(g, tkImport, "import")
  1063. gcomma(g, n, emptyContext, 1)
  1064. putNL(g)
  1065. of nkIncludeStmt:
  1066. putWithSpace(g, tkInclude, "include")
  1067. gcoms(g)
  1068. indentNL(g)
  1069. gcommaAux(g, n, g.indent)
  1070. dedent(g)
  1071. putNL(g)
  1072. of nkCommentStmt:
  1073. gcoms(g)
  1074. optNL(g)
  1075. of nkOfBranch:
  1076. optNL(g)
  1077. putWithSpace(g, tkOf, "of")
  1078. gcomma(g, n, c, 0, - 2)
  1079. putWithSpace(g, tkColon, ":")
  1080. gcoms(g)
  1081. gstmts(g, lastSon(n), c)
  1082. of nkBindStmt:
  1083. putWithSpace(g, tkBind, "bind")
  1084. gcomma(g, n, c)
  1085. of nkMixinStmt:
  1086. putWithSpace(g, tkMixin, "mixin")
  1087. gcomma(g, n, c)
  1088. of nkElifBranch:
  1089. optNL(g)
  1090. putWithSpace(g, tkElif, "elif")
  1091. gsub(g, n.sons[0])
  1092. putWithSpace(g, tkColon, ":")
  1093. gcoms(g)
  1094. gstmts(g, n.sons[1], c)
  1095. of nkElse:
  1096. optNL(g)
  1097. put(g, tkElse, "else")
  1098. putWithSpace(g, tkColon, ":")
  1099. gcoms(g)
  1100. gstmts(g, n.sons[0], c)
  1101. of nkFinally:
  1102. optNL(g)
  1103. put(g, tkFinally, "finally")
  1104. putWithSpace(g, tkColon, ":")
  1105. gcoms(g)
  1106. gstmts(g, n.sons[0], c)
  1107. of nkExceptBranch:
  1108. optNL(g)
  1109. putWithSpace(g, tkExcept, "except")
  1110. gcomma(g, n, 0, - 2)
  1111. putWithSpace(g, tkColon, ":")
  1112. gcoms(g)
  1113. gstmts(g, lastSon(n), c)
  1114. of nkGenericParams:
  1115. put(g, tkBracketLe, "[")
  1116. gcomma(g, n)
  1117. put(g, tkBracketRi, "]")
  1118. of nkFormalParams:
  1119. put(g, tkParLe, "(")
  1120. gsemicolon(g, n, 1)
  1121. put(g, tkParRi, ")")
  1122. if n.sons[0].kind != nkEmpty:
  1123. putWithSpace(g, tkColon, ":")
  1124. gsub(g, n.sons[0])
  1125. of nkTupleTy:
  1126. put(g, tkTuple, "tuple")
  1127. if sonsLen(n) > 0:
  1128. put(g, tkBracketLe, "[")
  1129. gcomma(g, n)
  1130. put(g, tkBracketRi, "]")
  1131. else:
  1132. #nkNone, nkMetaNode, nkExplicitTypeListCall:
  1133. InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
  1134. proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
  1135. var g: TSrcGen
  1136. initSrcGen(g, renderFlags)
  1137. gsub(g, n)
  1138. result = g.buf
  1139. proc renderModule(n: PNode, filename: string,
  1140. renderFlags: TRenderFlags = {}) =
  1141. var
  1142. f: tfile
  1143. g: TSrcGen
  1144. initSrcGen(g, renderFlags)
  1145. for i in countup(0, sonsLen(n) - 1):
  1146. gsub(g, n.sons[i])
  1147. optNL(g)
  1148. case n.sons[i].kind
  1149. of nkTypeSection, nkConstSection, nkVarSection, nkLetSection,
  1150. nkCommentStmt: putNL(g)
  1151. else: nil
  1152. gcoms(g)
  1153. if optStdout in gGlobalOptions:
  1154. write(stdout, g.buf)
  1155. elif open(f, filename, fmWrite):
  1156. write(f, g.buf)
  1157. close(f)
  1158. else:
  1159. rawMessage(errCannotOpenFile, filename)
  1160. proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
  1161. initSrcGen(r, renderFlags)
  1162. gsub(r, n)
  1163. proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) =
  1164. if r.idx < len(r.tokens):
  1165. kind = r.tokens[r.idx].kind
  1166. var length = r.tokens[r.idx].length.int
  1167. literal = substr(r.buf, r.pos, r.pos + length - 1)
  1168. inc(r.pos, length)
  1169. inc(r.idx)
  1170. else:
  1171. kind = tkEof