renderer.nim 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2013 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 Nim representation.
  10. when defined(nimHasUsed):
  11. # 'import renderer' is so useful for debugging
  12. # that Nim shouldn't produce a warning for that:
  13. {.used.}
  14. import
  15. lexer, options, idents, strutils, ast, msgs, lineinfos
  16. type
  17. TRenderFlag* = enum
  18. renderNone, renderNoBody, renderNoComments, renderDocComments,
  19. renderNoPragmas, renderIds, renderNoProcDefs, renderSyms, renderRunnableExamples
  20. TRenderFlags* = set[TRenderFlag]
  21. TRenderTok* = object
  22. kind*: TTokType
  23. length*: int16
  24. sym*: PSym
  25. TRenderTokSeq* = seq[TRenderTok]
  26. TSrcGen* = object
  27. indent*: int
  28. lineLen*: int
  29. pos*: int # current position for iteration over the buffer
  30. idx*: int # current token index for iteration over the buffer
  31. tokens*: TRenderTokSeq
  32. buf*: string
  33. pendingNL*: int # negative if not active; else contains the
  34. # indentation value
  35. pendingWhitespace: int
  36. comStack*: seq[PNode] # comment stack
  37. flags*: TRenderFlags
  38. inGenericParams: bool
  39. checkAnon: bool # we're in a context that can contain sfAnon
  40. inPragma: int
  41. when defined(nimpretty):
  42. pendingNewlineCount: int
  43. fid*: FileIndex
  44. config*: ConfigRef
  45. # We render the source code in a two phases: The first
  46. # determines how long the subtree will likely be, the second
  47. # phase appends to a buffer that will be the output.
  48. proc isKeyword*(i: PIdent): bool =
  49. if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
  50. (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
  51. result = true
  52. proc renderDefinitionName*(s: PSym, noQuotes = false): string =
  53. ## Returns the definition name of the symbol.
  54. ##
  55. ## If noQuotes is false the symbol may be returned in backticks. This will
  56. ## happen if the name happens to be a keyword or the first character is not
  57. ## part of the SymStartChars set.
  58. let x = s.name.s
  59. if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(s.name)):
  60. result = x
  61. else:
  62. result = '`' & x & '`'
  63. const
  64. IndentWidth = 2
  65. longIndentWid = IndentWidth * 2
  66. when defined(nimpretty):
  67. proc minmaxLine(n: PNode): (int, int) =
  68. case n.kind
  69. of nkTripleStrLit:
  70. result = (n.info.line.int, n.info.line.int + countLines(n.strVal))
  71. of nkCommentStmt:
  72. result = (n.info.line.int, n.info.line.int + countLines(n.comment))
  73. else:
  74. result = (n.info.line.int, n.info.line.int)
  75. for i in 0..<n.safeLen:
  76. let (currMin, currMax) = minmaxLine(n[i])
  77. if currMin < result[0]: result[0] = currMin
  78. if currMax > result[1]: result[1] = currMax
  79. proc lineDiff(a, b: PNode): int =
  80. result = minmaxLine(b)[0] - minmaxLine(a)[1]
  81. const
  82. MaxLineLen = 80
  83. LineCommentColumn = 30
  84. proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
  85. g.comStack = @[]
  86. g.tokens = @[]
  87. g.indent = 0
  88. g.lineLen = 0
  89. g.pos = 0
  90. g.idx = 0
  91. g.buf = ""
  92. g.flags = renderFlags
  93. g.pendingNL = -1
  94. g.pendingWhitespace = -1
  95. g.inGenericParams = false
  96. g.config = config
  97. proc addTok(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
  98. setLen(g.tokens, g.tokens.len + 1)
  99. g.tokens[^1].kind = kind
  100. g.tokens[^1].length = int16(s.len)
  101. g.tokens[^1].sym = sym
  102. g.buf.add(s)
  103. proc addPendingNL(g: var TSrcGen) =
  104. if g.pendingNL >= 0:
  105. when defined(nimpretty):
  106. let newlines = repeat("\n", clamp(g.pendingNewlineCount, 1, 3))
  107. else:
  108. const newlines = "\n"
  109. addTok(g, tkSpaces, newlines & spaces(g.pendingNL))
  110. g.lineLen = g.pendingNL
  111. g.pendingNL = - 1
  112. g.pendingWhitespace = -1
  113. elif g.pendingWhitespace >= 0:
  114. addTok(g, tkSpaces, spaces(g.pendingWhitespace))
  115. g.pendingWhitespace = -1
  116. proc putNL(g: var TSrcGen, indent: int) =
  117. if g.pendingNL >= 0: addPendingNL(g)
  118. else: addTok(g, tkSpaces, "\n")
  119. g.pendingNL = indent
  120. g.lineLen = indent
  121. g.pendingWhitespace = -1
  122. proc previousNL(g: TSrcGen): bool =
  123. result = g.pendingNL >= 0 or (g.tokens.len > 0 and
  124. g.tokens[^1].kind == tkSpaces)
  125. proc putNL(g: var TSrcGen) =
  126. putNL(g, g.indent)
  127. proc optNL(g: var TSrcGen, indent: int) =
  128. g.pendingNL = indent
  129. g.lineLen = indent
  130. when defined(nimpretty): g.pendingNewlineCount = 0
  131. proc optNL(g: var TSrcGen) =
  132. optNL(g, g.indent)
  133. proc optNL(g: var TSrcGen; a, b: PNode) =
  134. g.pendingNL = g.indent
  135. g.lineLen = g.indent
  136. when defined(nimpretty): g.pendingNewlineCount = lineDiff(a, b)
  137. proc indentNL(g: var TSrcGen) =
  138. inc(g.indent, IndentWidth)
  139. g.pendingNL = g.indent
  140. g.lineLen = g.indent
  141. proc dedent(g: var TSrcGen) =
  142. dec(g.indent, IndentWidth)
  143. assert(g.indent >= 0)
  144. if g.pendingNL > IndentWidth:
  145. dec(g.pendingNL, IndentWidth)
  146. dec(g.lineLen, IndentWidth)
  147. proc put(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
  148. if kind != tkSpaces:
  149. addPendingNL(g)
  150. if s.len > 0:
  151. addTok(g, kind, s, sym)
  152. inc(g.lineLen, s.len)
  153. else:
  154. g.pendingWhitespace = s.len
  155. proc putComment(g: var TSrcGen, s: string) =
  156. if s.len == 0: return
  157. var i = 0
  158. let hi = s.len - 1
  159. var isCode = (s.len >= 2) and (s[1] != ' ')
  160. var ind = g.lineLen
  161. var com = "## "
  162. while i <= hi:
  163. case s[i]
  164. of '\0':
  165. break
  166. of '\x0D':
  167. put(g, tkComment, com)
  168. com = "## "
  169. inc(i)
  170. if i <= hi and s[i] == '\x0A': inc(i)
  171. optNL(g, ind)
  172. of '\x0A':
  173. put(g, tkComment, com)
  174. com = "## "
  175. inc(i)
  176. optNL(g, ind)
  177. of ' ', '\x09':
  178. com.add(s[i])
  179. inc(i)
  180. else:
  181. # we may break the comment into a multi-line comment if the line
  182. # gets too long:
  183. # compute length of the following word:
  184. var j = i
  185. while j <= hi and s[j] > ' ': inc(j)
  186. if not isCode and (g.lineLen + (j - i) > MaxLineLen):
  187. put(g, tkComment, com)
  188. optNL(g, ind)
  189. com = "## "
  190. while i <= hi and s[i] > ' ':
  191. com.add(s[i])
  192. inc(i)
  193. put(g, tkComment, com)
  194. optNL(g)
  195. proc maxLineLength(s: string): int =
  196. if s.len == 0: return 0
  197. var i = 0
  198. let hi = s.len - 1
  199. var lineLen = 0
  200. while i <= hi:
  201. case s[i]
  202. of '\0':
  203. break
  204. of '\x0D':
  205. inc(i)
  206. if i <= hi and s[i] == '\x0A': inc(i)
  207. result = max(result, lineLen)
  208. lineLen = 0
  209. of '\x0A':
  210. inc(i)
  211. result = max(result, lineLen)
  212. lineLen = 0
  213. else:
  214. inc(lineLen)
  215. inc(i)
  216. proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
  217. var i = 0
  218. let hi = s.len - 1
  219. var str = ""
  220. while i <= hi:
  221. case s[i]
  222. of '\x0D':
  223. put(g, kind, str)
  224. str = ""
  225. inc(i)
  226. if i <= hi and s[i] == '\x0A': inc(i)
  227. optNL(g, 0)
  228. of '\x0A':
  229. put(g, kind, str)
  230. str = ""
  231. inc(i)
  232. optNL(g, 0)
  233. else:
  234. str.add(s[i])
  235. inc(i)
  236. put(g, kind, str)
  237. proc containsNL(s: string): bool =
  238. for i in 0..<s.len:
  239. case s[i]
  240. of '\x0D', '\x0A':
  241. return true
  242. else:
  243. discard
  244. result = false
  245. proc pushCom(g: var TSrcGen, n: PNode) =
  246. setLen(g.comStack, g.comStack.len + 1)
  247. g.comStack[^1] = n
  248. proc popAllComs(g: var TSrcGen) =
  249. setLen(g.comStack, 0)
  250. const
  251. Space = " "
  252. proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
  253. result = false
  254. if n.comment.len > 0:
  255. result = (renderNoComments notin g.flags) or
  256. (renderDocComments in g.flags)
  257. proc gcom(g: var TSrcGen, n: PNode) =
  258. assert(n != nil)
  259. if shouldRenderComment(g, n):
  260. if (g.pendingNL < 0) and (g.buf.len > 0) and (g.buf[^1] != ' '):
  261. put(g, tkSpaces, Space)
  262. # Before long comments we cannot make sure that a newline is generated,
  263. # because this might be wrong. But it is no problem in practice.
  264. if (g.pendingNL < 0) and (g.buf.len > 0) and
  265. (g.lineLen < LineCommentColumn):
  266. var ml = maxLineLength(n.comment)
  267. if ml + LineCommentColumn <= MaxLineLen:
  268. put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen))
  269. putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
  270. proc gcoms(g: var TSrcGen) =
  271. for i in 0..high(g.comStack): gcom(g, g.comStack[i])
  272. popAllComs(g)
  273. proc lsub(g: TSrcGen; n: PNode): int
  274. proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
  275. proc skip(t: PType): PType =
  276. result = t
  277. while result != nil and result.kind in {tyGenericInst, tyRange, tyVar,
  278. tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}:
  279. result = lastSon(result)
  280. let typ = n.typ.skip
  281. if typ != nil and typ.kind in {tyBool, tyEnum}:
  282. if sfPure in typ.sym.flags:
  283. result = typ.sym.name.s & '.'
  284. let enumfields = typ.n
  285. # we need a slow linear search because of enums with holes:
  286. for e in items(enumfields):
  287. if e.sym.position == x:
  288. result &= e.sym.name.s
  289. return
  290. if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
  291. elif nfBase8 in n.flags:
  292. var y = if size < sizeof(BiggestInt): x and ((1 shl (size*8)) - 1)
  293. else: x
  294. result = "0o" & toOct(y, size * 3)
  295. elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
  296. else: result = $x
  297. proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
  298. if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
  299. elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
  300. elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
  301. else: result = $cast[BiggestUInt](x)
  302. proc atom(g: TSrcGen; n: PNode): string =
  303. when defined(nimpretty):
  304. doAssert g.config != nil, "g.config not initialized!"
  305. let comment = if n.info.commentOffsetA < n.info.commentOffsetB:
  306. " " & fileSection(g.config, g.fid, n.info.commentOffsetA, n.info.commentOffsetB)
  307. else:
  308. ""
  309. if n.info.offsetA <= n.info.offsetB:
  310. # for some constructed tokens this can not be the case and we're better
  311. # off to not mess with the offset then.
  312. return fileSection(g.config, g.fid, n.info.offsetA, n.info.offsetB) & comment
  313. var f: float32
  314. case n.kind
  315. of nkEmpty: result = ""
  316. of nkIdent: result = n.ident.s
  317. of nkSym: result = n.sym.name.s
  318. of nkStrLit: result = ""; result.addQuoted(n.strVal)
  319. of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"'
  320. of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\""
  321. of nkCharLit:
  322. result = "\'"
  323. result.addEscapedChar(chr(int(n.intVal)));
  324. result.add '\''
  325. of nkIntLit: result = litAux(g, n, n.intVal, 4)
  326. of nkInt8Lit: result = litAux(g, n, n.intVal, 1) & "\'i8"
  327. of nkInt16Lit: result = litAux(g, n, n.intVal, 2) & "\'i16"
  328. of nkInt32Lit: result = litAux(g, n, n.intVal, 4) & "\'i32"
  329. of nkInt64Lit: result = litAux(g, n, n.intVal, 8) & "\'i64"
  330. of nkUIntLit: result = ulitAux(g, n, n.intVal, 4) & "\'u"
  331. of nkUInt8Lit: result = ulitAux(g, n, n.intVal, 1) & "\'u8"
  332. of nkUInt16Lit: result = ulitAux(g, n, n.intVal, 2) & "\'u16"
  333. of nkUInt32Lit: result = ulitAux(g, n, n.intVal, 4) & "\'u32"
  334. of nkUInt64Lit: result = ulitAux(g, n, n.intVal, 8) & "\'u64"
  335. of nkFloatLit:
  336. if n.flags * {nfBase2, nfBase8, nfBase16} == {}: result = $(n.floatVal)
  337. else: result = litAux(g, n, (cast[PInt64](addr(n.floatVal)))[] , 8)
  338. of nkFloat32Lit:
  339. if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
  340. result = $n.floatVal & "\'f32"
  341. else:
  342. f = n.floatVal.float32
  343. result = litAux(g, n, (cast[PInt32](addr(f)))[], 4) & "\'f32"
  344. of nkFloat64Lit:
  345. if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
  346. result = $n.floatVal & "\'f64"
  347. else:
  348. result = litAux(g, n, (cast[PInt64](addr(n.floatVal)))[], 8) & "\'f64"
  349. of nkNilLit: result = "nil"
  350. of nkType:
  351. if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
  352. else: result = "[type node]"
  353. else:
  354. internalError(g.config, "rnimsyn.atom " & $n.kind)
  355. result = ""
  356. proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
  357. assert(theEnd < 0)
  358. result = 0
  359. for i in start..n.len + theEnd:
  360. let param = n[i]
  361. if nfDefaultParam notin param.flags:
  362. inc(result, lsub(g, param))
  363. inc(result, 2) # for ``, ``
  364. if result > 0:
  365. dec(result, 2) # last does not get a comma!
  366. proc lsons(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
  367. assert(theEnd < 0)
  368. result = 0
  369. for i in start..n.len + theEnd: inc(result, lsub(g, n[i]))
  370. proc lsub(g: TSrcGen; n: PNode): int =
  371. # computes the length of a tree
  372. if isNil(n): return 0
  373. if n.comment.len > 0: return MaxLineLen + 1
  374. case n.kind
  375. of nkEmpty: result = 0
  376. of nkTripleStrLit:
  377. if containsNL(n.strVal): result = MaxLineLen + 1
  378. else: result = atom(g, n).len
  379. of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
  380. result = atom(g, n).len
  381. of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr:
  382. result = lsub(g, n[0]) + lcomma(g, n, 1) + 2
  383. of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(g, n[1])
  384. of nkCast: result = lsub(g, n[0]) + lsub(g, n[1]) + len("cast[]()")
  385. of nkAddr: result = (if n.len>0: lsub(g, n[0]) + len("addr()") else: 4)
  386. of nkStaticExpr: result = lsub(g, n[0]) + len("static_")
  387. of nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString: result = lsub(g, n[0])
  388. of nkCommand: result = lsub(g, n[0]) + lcomma(g, n, 1) + 1
  389. of nkExprEqExpr, nkAsgn, nkFastAsgn: result = lsons(g, n) + 3
  390. of nkPar, nkCurly, nkBracket, nkClosure: result = lcomma(g, n) + 2
  391. of nkTupleConstr:
  392. # assume the trailing comma:
  393. result = lcomma(g, n) + 3
  394. of nkArgList: result = lcomma(g, n)
  395. of nkTableConstr:
  396. result = if n.len > 0: lcomma(g, n) + 2 else: len("{:}")
  397. of nkClosedSymChoice, nkOpenSymChoice:
  398. if n.len > 0: result += lsub(g, n[0])
  399. of nkTupleTy: result = lcomma(g, n) + len("tuple[]")
  400. of nkTupleClassTy: result = len("tuple")
  401. of nkDotExpr: result = lsons(g, n) + 1
  402. of nkBind: result = lsons(g, n) + len("bind_")
  403. of nkBindStmt: result = lcomma(g, n) + len("bind_")
  404. of nkMixinStmt: result = lcomma(g, n) + len("mixin_")
  405. of nkCheckedFieldExpr: result = lsub(g, n[0])
  406. of nkLambda: result = lsons(g, n) + len("proc__=_")
  407. of nkDo: result = lsons(g, n) + len("do__:_")
  408. of nkConstDef, nkIdentDefs:
  409. result = lcomma(g, n, 0, - 3)
  410. if n[^2].kind != nkEmpty: result = result + lsub(g, n[^2]) + 2
  411. if n[^1].kind != nkEmpty: result = result + lsub(g, n[^1]) + 3
  412. of nkVarTuple:
  413. if n[^1].kind == nkEmpty:
  414. result = lcomma(g, n, 0, - 2) + len("()")
  415. else:
  416. result = lcomma(g, n, 0, - 3) + len("() = ") + lsub(g, lastSon(n))
  417. of nkChckRangeF: result = len("chckRangeF") + 2 + lcomma(g, n)
  418. of nkChckRange64: result = len("chckRange64") + 2 + lcomma(g, n)
  419. of nkChckRange: result = len("chckRange") + 2 + lcomma(g, n)
  420. of nkObjDownConv, nkObjUpConv:
  421. result = 2
  422. if n.len >= 1: result = result + lsub(g, n[0])
  423. result = result + lcomma(g, n, 1)
  424. of nkExprColonExpr: result = lsons(g, n) + 2
  425. of nkInfix: result = lsons(g, n) + 2
  426. of nkPrefix:
  427. result = lsons(g, n)+1+(if n.len > 0 and n[1].kind == nkInfix: 2 else: 0)
  428. of nkPostfix: result = lsons(g, n)
  429. of nkCallStrLit: result = lsons(g, n)
  430. of nkPragmaExpr: result = lsub(g, n[0]) + lcomma(g, n, 1)
  431. of nkRange: result = lsons(g, n) + 2
  432. of nkDerefExpr: result = lsub(g, n[0]) + 2
  433. of nkAccQuoted: result = lsons(g, n) + 2
  434. of nkIfExpr:
  435. result = lsub(g, n[0][0]) + lsub(g, n[0][1]) + lsons(g, n, 1) +
  436. len("if_:_")
  437. of nkElifExpr: result = lsons(g, n) + len("_elif_:_")
  438. of nkElseExpr: result = lsub(g, n[0]) + len("_else:_") # type descriptions
  439. of nkTypeOfExpr: result = (if n.len > 0: lsub(g, n[0]) else: 0)+len("typeof()")
  440. of nkRefTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ref")
  441. of nkPtrTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ptr")
  442. of nkVarTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("var")
  443. of nkDistinctTy:
  444. result = len("distinct") + (if n.len > 0: lsub(g, n[0])+1 else: 0)
  445. if n.len > 1:
  446. result += (if n[1].kind == nkWith: len("_with_") else: len("_without_"))
  447. result += lcomma(g, n[1])
  448. of nkStaticTy: result = (if n.len > 0: lsub(g, n[0]) else: 0) +
  449. len("static[]")
  450. of nkTypeDef: result = lsons(g, n) + 3
  451. of nkOfInherit: result = lsub(g, n[0]) + len("of_")
  452. of nkProcTy: result = lsons(g, n) + len("proc_")
  453. of nkIteratorTy: result = lsons(g, n) + len("iterator_")
  454. of nkSharedTy: result = lsons(g, n) + len("shared_")
  455. of nkEnumTy:
  456. if n.len > 0:
  457. result = lsub(g, n[0]) + lcomma(g, n, 1) + len("enum_")
  458. else:
  459. result = len("enum")
  460. of nkEnumFieldDef: result = lsons(g, n) + 3
  461. of nkVarSection, nkLetSection:
  462. if n.len > 1: result = MaxLineLen + 1
  463. else: result = lsons(g, n) + len("var_")
  464. of nkUsingStmt:
  465. if n.len > 1: result = MaxLineLen + 1
  466. else: result = lsons(g, n) + len("using_")
  467. of nkReturnStmt:
  468. if n.len > 0 and n[0].kind == nkAsgn:
  469. result = len("return_") + lsub(g, n[0][1])
  470. else:
  471. result = len("return_") + lsub(g, n[0])
  472. of nkRaiseStmt: result = lsub(g, n[0]) + len("raise_")
  473. of nkYieldStmt: result = lsub(g, n[0]) + len("yield_")
  474. of nkDiscardStmt: result = lsub(g, n[0]) + len("discard_")
  475. of nkBreakStmt: result = lsub(g, n[0]) + len("break_")
  476. of nkContinueStmt: result = lsub(g, n[0]) + len("continue_")
  477. of nkPragma: result = lcomma(g, n) + 4
  478. of nkCommentStmt: result = n.comment.len
  479. of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
  480. of nkImportAs: result = lsub(g, n[0]) + len("_as_") + lsub(g, n[1])
  481. of nkElifBranch: result = lsons(g, n) + len("elif_:_")
  482. of nkElse: result = lsub(g, n[0]) + len("else:_")
  483. of nkFinally: result = lsub(g, n[0]) + len("finally:_")
  484. of nkGenericParams: result = lcomma(g, n) + 2
  485. of nkFormalParams:
  486. result = lcomma(g, n, 1) + 2
  487. if n[0].kind != nkEmpty: result = result + lsub(g, n[0]) + 2
  488. of nkExceptBranch:
  489. result = lcomma(g, n, 0, -2) + lsub(g, lastSon(n)) + len("except_:_")
  490. of nkObjectTy:
  491. result = len("object_")
  492. else: result = MaxLineLen + 1
  493. proc fits(g: TSrcGen, x: int): bool =
  494. result = x <= MaxLineLen
  495. type
  496. TSubFlag = enum
  497. rfLongMode, rfInConstExpr
  498. TSubFlags = set[TSubFlag]
  499. TContext = tuple[spacing: int, flags: TSubFlags]
  500. const
  501. emptyContext: TContext = (spacing: 0, flags: {})
  502. proc initContext(c: var TContext) =
  503. c.spacing = 0
  504. c.flags = {}
  505. proc gsub(g: var TSrcGen, n: PNode, c: TContext)
  506. proc gsub(g: var TSrcGen, n: PNode) =
  507. var c: TContext
  508. initContext(c)
  509. gsub(g, n, c)
  510. proc hasCom(n: PNode): bool =
  511. result = false
  512. if n.isNil: return false
  513. if n.comment.len > 0: return true
  514. case n.kind
  515. of nkEmpty..nkNilLit: discard
  516. else:
  517. for i in 0..<n.len:
  518. if hasCom(n[i]): return true
  519. proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
  520. put(g, kind, s)
  521. put(g, tkSpaces, Space)
  522. proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
  523. theEnd: int = - 1, separator = tkComma) =
  524. for i in start..n.len + theEnd:
  525. var c = i < n.len + theEnd
  526. var sublen = lsub(g, n[i]) + ord(c)
  527. if not fits(g, g.lineLen + sublen) and (ind + sublen < MaxLineLen): optNL(g, ind)
  528. let oldLen = g.tokens.len
  529. gsub(g, n[i])
  530. if c:
  531. if g.tokens.len > oldLen:
  532. putWithSpace(g, separator, TokTypeToStr[separator])
  533. if hasCom(n[i]):
  534. gcoms(g)
  535. optNL(g, ind)
  536. proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
  537. theEnd: int = - 1) =
  538. var ind: int
  539. if rfInConstExpr in c.flags:
  540. ind = g.indent + IndentWidth
  541. else:
  542. ind = g.lineLen
  543. if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
  544. gcommaAux(g, n, ind, start, theEnd)
  545. proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
  546. var ind = g.lineLen
  547. if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
  548. gcommaAux(g, n, ind, start, theEnd)
  549. proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
  550. var ind = g.lineLen
  551. if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
  552. gcommaAux(g, n, ind, start, theEnd, tkSemiColon)
  553. proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
  554. theEnd: int = - 1) =
  555. for i in start..n.len + theEnd: gsub(g, n[i], c)
  556. proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
  557. k: string) =
  558. if n.len == 0: return # empty var sections are possible
  559. putWithSpace(g, kind, k)
  560. gcoms(g)
  561. indentNL(g)
  562. for i in 0..<n.len:
  563. optNL(g)
  564. gsub(g, n[i], c)
  565. gcoms(g)
  566. dedent(g)
  567. proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool =
  568. result = n.comment.len > 0
  569. if not result:
  570. # check further
  571. for i in start..n.len + theEnd:
  572. if (lsub(g, n[i]) > MaxLineLen):
  573. result = true
  574. break
  575. proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
  576. if n.kind == nkEmpty: return
  577. if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
  578. if doIndent: indentNL(g)
  579. for i in 0..<n.len:
  580. if i > 0:
  581. optNL(g, n[i-1], n[i])
  582. else:
  583. optNL(g)
  584. if n[i].kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
  585. gstmts(g, n[i], c, doIndent=false)
  586. else:
  587. gsub(g, n[i])
  588. gcoms(g)
  589. if doIndent: dedent(g)
  590. else:
  591. indentNL(g)
  592. gsub(g, n)
  593. gcoms(g)
  594. dedent(g)
  595. optNL(g)
  596. proc gcond(g: var TSrcGen, n: PNode) =
  597. if n.kind == nkStmtListExpr:
  598. put(g, tkParLe, "(")
  599. gsub(g, n)
  600. if n.kind == nkStmtListExpr:
  601. put(g, tkParRi, ")")
  602. proc gif(g: var TSrcGen, n: PNode) =
  603. var c: TContext
  604. gcond(g, n[0][0])
  605. initContext(c)
  606. putWithSpace(g, tkColon, ":")
  607. if longMode(g, n) or (lsub(g, n[0][1]) + g.lineLen > MaxLineLen):
  608. incl(c.flags, rfLongMode)
  609. gcoms(g) # a good place for comments
  610. gstmts(g, n[0][1], c)
  611. for i in 1..<n.len:
  612. optNL(g)
  613. gsub(g, n[i], c)
  614. proc gwhile(g: var TSrcGen, n: PNode) =
  615. var c: TContext
  616. putWithSpace(g, tkWhile, "while")
  617. gcond(g, n[0])
  618. putWithSpace(g, tkColon, ":")
  619. initContext(c)
  620. if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
  621. incl(c.flags, rfLongMode)
  622. gcoms(g) # a good place for comments
  623. gstmts(g, n[1], c)
  624. proc gpattern(g: var TSrcGen, n: PNode) =
  625. var c: TContext
  626. put(g, tkCurlyLe, "{")
  627. initContext(c)
  628. if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
  629. incl(c.flags, rfLongMode)
  630. gcoms(g) # a good place for comments
  631. gstmts(g, n, c)
  632. put(g, tkCurlyRi, "}")
  633. proc gpragmaBlock(g: var TSrcGen, n: PNode) =
  634. var c: TContext
  635. gsub(g, n[0])
  636. putWithSpace(g, tkColon, ":")
  637. initContext(c)
  638. if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
  639. incl(c.flags, rfLongMode)
  640. gcoms(g) # a good place for comments
  641. gstmts(g, n[1], c)
  642. proc gtry(g: var TSrcGen, n: PNode) =
  643. var c: TContext
  644. put(g, tkTry, "try")
  645. putWithSpace(g, tkColon, ":")
  646. initContext(c)
  647. if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
  648. incl(c.flags, rfLongMode)
  649. gcoms(g) # a good place for comments
  650. gstmts(g, n[0], c)
  651. gsons(g, n, c, 1)
  652. proc gfor(g: var TSrcGen, n: PNode) =
  653. var c: TContext
  654. putWithSpace(g, tkFor, "for")
  655. initContext(c)
  656. if longMode(g, n) or
  657. (lsub(g, n[^1]) + lsub(g, n[^2]) + 6 + g.lineLen > MaxLineLen):
  658. incl(c.flags, rfLongMode)
  659. gcomma(g, n, c, 0, - 3)
  660. put(g, tkSpaces, Space)
  661. putWithSpace(g, tkIn, "in")
  662. gsub(g, n[^2], c)
  663. putWithSpace(g, tkColon, ":")
  664. gcoms(g)
  665. gstmts(g, n[^1], c)
  666. proc gcase(g: var TSrcGen, n: PNode) =
  667. var c: TContext
  668. initContext(c)
  669. if n.len == 0: return
  670. var last = if n[^1].kind == nkElse: -2 else: -1
  671. if longMode(g, n, 0, last): incl(c.flags, rfLongMode)
  672. putWithSpace(g, tkCase, "case")
  673. gcond(g, n[0])
  674. gcoms(g)
  675. optNL(g)
  676. gsons(g, n, c, 1, last)
  677. if last == - 2:
  678. initContext(c)
  679. if longMode(g, n[^1]): incl(c.flags, rfLongMode)
  680. gsub(g, n[^1], c)
  681. proc genSymSuffix(result: var string, s: PSym) {.inline.} =
  682. if sfGenSym in s.flags:
  683. result.add '_'
  684. result.addInt s.id
  685. proc gproc(g: var TSrcGen, n: PNode) =
  686. var c: TContext
  687. if n[namePos].kind == nkSym:
  688. let s = n[namePos].sym
  689. var ret = renderDefinitionName(s)
  690. ret.genSymSuffix(s)
  691. put(g, tkSymbol, ret)
  692. else:
  693. gsub(g, n[namePos])
  694. if n[patternPos].kind != nkEmpty:
  695. gpattern(g, n[patternPos])
  696. let oldInGenericParams = g.inGenericParams
  697. g.inGenericParams = true
  698. if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
  699. n[miscPos][1].kind != nkEmpty:
  700. gsub(g, n[miscPos][1])
  701. else:
  702. gsub(g, n[genericParamsPos])
  703. g.inGenericParams = oldInGenericParams
  704. gsub(g, n[paramsPos])
  705. if renderNoPragmas notin g.flags:
  706. gsub(g, n[pragmasPos])
  707. if renderNoBody notin g.flags:
  708. if n[bodyPos].kind != nkEmpty:
  709. put(g, tkSpaces, Space)
  710. putWithSpace(g, tkEquals, "=")
  711. indentNL(g)
  712. gcoms(g)
  713. dedent(g)
  714. initContext(c)
  715. gstmts(g, n[bodyPos], c)
  716. putNL(g)
  717. else:
  718. indentNL(g)
  719. gcoms(g)
  720. dedent(g)
  721. proc gTypeClassTy(g: var TSrcGen, n: PNode) =
  722. var c: TContext
  723. initContext(c)
  724. putWithSpace(g, tkConcept, "concept")
  725. gsons(g, n[0], c) # arglist
  726. gsub(g, n[1]) # pragmas
  727. gsub(g, n[2]) # of
  728. gcoms(g)
  729. indentNL(g)
  730. gcoms(g)
  731. gstmts(g, n[3], c)
  732. dedent(g)
  733. proc gblock(g: var TSrcGen, n: PNode) =
  734. var c: TContext
  735. initContext(c)
  736. if n[0].kind != nkEmpty:
  737. putWithSpace(g, tkBlock, "block")
  738. gsub(g, n[0])
  739. else:
  740. put(g, tkBlock, "block")
  741. putWithSpace(g, tkColon, ":")
  742. if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
  743. incl(c.flags, rfLongMode)
  744. gcoms(g)
  745. gstmts(g, n[1], c)
  746. proc gstaticStmt(g: var TSrcGen, n: PNode) =
  747. var c: TContext
  748. putWithSpace(g, tkStatic, "static")
  749. putWithSpace(g, tkColon, ":")
  750. initContext(c)
  751. if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
  752. incl(c.flags, rfLongMode)
  753. gcoms(g) # a good place for comments
  754. gstmts(g, n[0], c)
  755. proc gasm(g: var TSrcGen, n: PNode) =
  756. putWithSpace(g, tkAsm, "asm")
  757. gsub(g, n[0])
  758. gcoms(g)
  759. if n.len > 1:
  760. gsub(g, n[1])
  761. proc gident(g: var TSrcGen, n: PNode) =
  762. if g.inGenericParams and n.kind == nkSym:
  763. if sfAnon in n.sym.flags or
  764. (n.typ != nil and tfImplicitTypeParam in n.typ.flags): return
  765. var t: TTokType
  766. var s = atom(g, n)
  767. if s.len > 0 and s[0] in lexer.SymChars:
  768. if n.kind == nkIdent:
  769. if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
  770. (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
  771. t = tkSymbol
  772. else:
  773. t = TTokType(n.ident.id + ord(tkSymbol))
  774. else:
  775. t = tkSymbol
  776. else:
  777. t = tkOpr
  778. if n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp):
  779. s.add '_'
  780. s.addInt n.sym.id
  781. when defined(debugMagics):
  782. s.add '_'
  783. s.add $n.sym.magic
  784. put(g, t, s, if n.kind == nkSym and renderSyms in g.flags: n.sym else: nil)
  785. proc doParamsAux(g: var TSrcGen, params: PNode) =
  786. if params.len > 1:
  787. put(g, tkParLe, "(")
  788. gsemicolon(g, params, 1)
  789. put(g, tkParRi, ")")
  790. if params.len > 0 and params[0].kind != nkEmpty:
  791. putWithSpace(g, tkOpr, "->")
  792. gsub(g, params[0])
  793. proc gsub(g: var TSrcGen; n: PNode; i: int) =
  794. if i < n.len:
  795. gsub(g, n[i])
  796. else:
  797. put(g, tkOpr, "<<" & $i & "th child missing for " & $n.kind & " >>")
  798. type
  799. BracketKind = enum
  800. bkNone, bkBracket, bkBracketAsgn, bkCurly, bkCurlyAsgn
  801. proc bracketKind*(g: TSrcGen, n: PNode): BracketKind =
  802. if renderIds notin g.flags:
  803. case n.kind
  804. of nkClosedSymChoice, nkOpenSymChoice:
  805. if n.len > 0: result = bracketKind(g, n[0])
  806. of nkSym:
  807. result = case n.sym.name.s
  808. of "[]": bkBracket
  809. of "[]=": bkBracketAsgn
  810. of "{}": bkCurly
  811. of "{}=": bkCurlyAsgn
  812. else: bkNone
  813. else: result = bkNone
  814. proc skipHiddenNodes(n: PNode): PNode =
  815. result = n
  816. while result != nil:
  817. if result.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv} and result.len > 1:
  818. result = result[1]
  819. elif result.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString} and
  820. result.len > 0:
  821. result = result[0]
  822. else: break
  823. proc accentedName(g: var TSrcGen, n: PNode) =
  824. const backticksNeeded = OpChars + {'[', '{'}
  825. if n == nil: return
  826. let isOperator =
  827. if n.kind == nkIdent and n.ident.s.len > 0 and n.ident.s[0] in backticksNeeded: true
  828. elif n.kind == nkSym and n.sym.name.s.len > 0 and n.sym.name.s[0] in backticksNeeded: true
  829. else: false
  830. if isOperator:
  831. put(g, tkAccent, "`")
  832. gident(g, n)
  833. put(g, tkAccent, "`")
  834. else:
  835. gsub(g, n)
  836. proc infixArgument(g: var TSrcGen, n: PNode, i: int) =
  837. if i < 1 and i > 2: return
  838. var needsParenthesis = false
  839. let nNext = n[i].skipHiddenNodes
  840. if nNext.kind == nkInfix:
  841. if nNext[0].kind in {nkSym, nkIdent} and n[0].kind in {nkSym, nkIdent}:
  842. let nextId = if nNext[0].kind == nkSym: nNext[0].sym.name else: nNext[0].ident
  843. let nnId = if n[0].kind == nkSym: n[0].sym.name else: n[0].ident
  844. if i == 1:
  845. if getPrecedence(nextId) < getPrecedence(nnId):
  846. needsParenthesis = true
  847. elif i == 2:
  848. if getPrecedence(nextId) <= getPrecedence(nnId):
  849. needsParenthesis = true
  850. if needsParenthesis:
  851. put(g, tkParLe, "(")
  852. gsub(g, n, i)
  853. if needsParenthesis:
  854. put(g, tkParRi, ")")
  855. proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
  856. if isNil(n): return
  857. var
  858. a: TContext
  859. if n.comment.len > 0: pushCom(g, n)
  860. case n.kind # atoms:
  861. of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n))
  862. of nkEmpty: discard
  863. of nkType: put(g, tkInvalid, atom(g, n))
  864. of nkSym, nkIdent: gident(g, n)
  865. of nkIntLit: put(g, tkIntLit, atom(g, n))
  866. of nkInt8Lit: put(g, tkInt8Lit, atom(g, n))
  867. of nkInt16Lit: put(g, tkInt16Lit, atom(g, n))
  868. of nkInt32Lit: put(g, tkInt32Lit, atom(g, n))
  869. of nkInt64Lit: put(g, tkInt64Lit, atom(g, n))
  870. of nkUIntLit: put(g, tkUIntLit, atom(g, n))
  871. of nkUInt8Lit: put(g, tkUInt8Lit, atom(g, n))
  872. of nkUInt16Lit: put(g, tkUInt16Lit, atom(g, n))
  873. of nkUInt32Lit: put(g, tkUInt32Lit, atom(g, n))
  874. of nkUInt64Lit: put(g, tkUInt64Lit, atom(g, n))
  875. of nkFloatLit: put(g, tkFloatLit, atom(g, n))
  876. of nkFloat32Lit: put(g, tkFloat32Lit, atom(g, n))
  877. of nkFloat64Lit: put(g, tkFloat64Lit, atom(g, n))
  878. of nkFloat128Lit: put(g, tkFloat128Lit, atom(g, n))
  879. of nkStrLit: put(g, tkStrLit, atom(g, n))
  880. of nkRStrLit: put(g, tkRStrLit, atom(g, n))
  881. of nkCharLit: put(g, tkCharLit, atom(g, n))
  882. of nkNilLit: put(g, tkNil, atom(g, n)) # complex expressions
  883. of nkCall, nkConv, nkDotCall, nkPattern, nkObjConstr:
  884. if n.len > 1 and n.lastSon.kind in {nkStmtList, nkStmtListExpr}:
  885. accentedName(g, n[0])
  886. if n.len > 2:
  887. put(g, tkParLe, "(")
  888. gcomma(g, n, 1, -2)
  889. put(g, tkParRi, ")")
  890. put(g, tkColon, ":")
  891. gsub(g, n, n.len-1)
  892. elif n.len >= 1:
  893. case bracketKind(g, n[0])
  894. of bkBracket:
  895. gsub(g, n, 1)
  896. put(g, tkBracketLe, "[")
  897. gcomma(g, n, 2)
  898. put(g, tkBracketRi, "]")
  899. of bkBracketAsgn:
  900. gsub(g, n, 1)
  901. put(g, tkBracketLe, "[")
  902. gcomma(g, n, 2, -2)
  903. put(g, tkBracketRi, "]")
  904. put(g, tkSpaces, Space)
  905. putWithSpace(g, tkEquals, "=")
  906. gsub(g, n, n.len - 1)
  907. of bkCurly:
  908. gsub(g, n, 1)
  909. put(g, tkCurlyLe, "{")
  910. gcomma(g, n, 2)
  911. put(g, tkCurlyRi, "}")
  912. of bkCurlyAsgn:
  913. gsub(g, n, 1)
  914. put(g, tkCurlyLe, "{")
  915. gcomma(g, n, 2, -2)
  916. put(g, tkCurlyRi, "}")
  917. put(g, tkSpaces, Space)
  918. putWithSpace(g, tkEquals, "=")
  919. gsub(g, n, n.len - 1)
  920. of bkNone:
  921. accentedName(g, n[0])
  922. put(g, tkParLe, "(")
  923. gcomma(g, n, 1)
  924. put(g, tkParRi, ")")
  925. else:
  926. put(g, tkParLe, "(")
  927. put(g, tkParRi, ")")
  928. of nkCallStrLit:
  929. if n.len > 0: accentedName(g, n[0])
  930. if n.len > 1 and n[1].kind == nkRStrLit:
  931. put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
  932. else:
  933. gsub(g, n, 1)
  934. of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv:
  935. if n.len >= 2:
  936. gsub(g, n[1])
  937. else:
  938. put(g, tkSymbol, "(wrong conv)")
  939. of nkCast:
  940. put(g, tkCast, "cast")
  941. put(g, tkBracketLe, "[")
  942. gsub(g, n, 0)
  943. put(g, tkBracketRi, "]")
  944. put(g, tkParLe, "(")
  945. gsub(g, n, 1)
  946. put(g, tkParRi, ")")
  947. of nkAddr:
  948. put(g, tkAddr, "addr")
  949. if n.len > 0:
  950. put(g, tkParLe, "(")
  951. gsub(g, n[0])
  952. put(g, tkParRi, ")")
  953. of nkStaticExpr:
  954. put(g, tkStatic, "static")
  955. put(g, tkSpaces, Space)
  956. gsub(g, n, 0)
  957. of nkBracketExpr:
  958. gsub(g, n, 0)
  959. put(g, tkBracketLe, "[")
  960. gcomma(g, n, 1)
  961. put(g, tkBracketRi, "]")
  962. of nkCurlyExpr:
  963. gsub(g, n, 0)
  964. put(g, tkCurlyLe, "{")
  965. gcomma(g, n, 1)
  966. put(g, tkCurlyRi, "}")
  967. of nkPragmaExpr:
  968. gsub(g, n, 0)
  969. gcomma(g, n, 1)
  970. of nkCommand:
  971. accentedName(g, n[0])
  972. put(g, tkSpaces, Space)
  973. if n[^1].kind == nkStmtList:
  974. for i, child in n:
  975. if i > 1 and i < n.len - 1:
  976. put(g, tkComma, ",")
  977. elif i == n.len - 1:
  978. put(g, tkColon, ":")
  979. if i > 0:
  980. gsub(g, child)
  981. else:
  982. gcomma(g, n, 1)
  983. of nkExprEqExpr, nkAsgn, nkFastAsgn:
  984. gsub(g, n, 0)
  985. put(g, tkSpaces, Space)
  986. putWithSpace(g, tkEquals, "=")
  987. gsub(g, n, 1)
  988. of nkChckRangeF:
  989. put(g, tkSymbol, "chckRangeF")
  990. put(g, tkParLe, "(")
  991. gcomma(g, n)
  992. put(g, tkParRi, ")")
  993. of nkChckRange64:
  994. put(g, tkSymbol, "chckRange64")
  995. put(g, tkParLe, "(")
  996. gcomma(g, n)
  997. put(g, tkParRi, ")")
  998. of nkChckRange:
  999. put(g, tkSymbol, "chckRange")
  1000. put(g, tkParLe, "(")
  1001. gcomma(g, n)
  1002. put(g, tkParRi, ")")
  1003. of nkObjDownConv, nkObjUpConv:
  1004. if n.len >= 1: gsub(g, n[0])
  1005. put(g, tkParLe, "(")
  1006. gcomma(g, n, 1)
  1007. put(g, tkParRi, ")")
  1008. of nkClosedSymChoice, nkOpenSymChoice:
  1009. if renderIds in g.flags:
  1010. put(g, tkParLe, "(")
  1011. for i in 0..<n.len:
  1012. if i > 0: put(g, tkOpr, "|")
  1013. if n[i].kind == nkSym:
  1014. let s = n[i].sym
  1015. if s.owner != nil:
  1016. put g, tkSymbol, n[i].sym.owner.name.s
  1017. put g, tkOpr, "."
  1018. put g, tkSymbol, n[i].sym.name.s
  1019. else:
  1020. gsub(g, n[i], c)
  1021. put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
  1022. else:
  1023. gsub(g, n, 0)
  1024. of nkPar, nkClosure:
  1025. put(g, tkParLe, "(")
  1026. gcomma(g, n, c)
  1027. put(g, tkParRi, ")")
  1028. of nkTupleConstr:
  1029. put(g, tkParLe, "(")
  1030. gcomma(g, n, c)
  1031. if n.len == 1: put(g, tkComma, ",")
  1032. put(g, tkParRi, ")")
  1033. of nkCurly:
  1034. put(g, tkCurlyLe, "{")
  1035. gcomma(g, n, c)
  1036. put(g, tkCurlyRi, "}")
  1037. of nkArgList:
  1038. gcomma(g, n, c)
  1039. of nkTableConstr:
  1040. put(g, tkCurlyLe, "{")
  1041. if n.len > 0: gcomma(g, n, c)
  1042. else: put(g, tkColon, ":")
  1043. put(g, tkCurlyRi, "}")
  1044. of nkBracket:
  1045. put(g, tkBracketLe, "[")
  1046. gcomma(g, n, c)
  1047. put(g, tkBracketRi, "]")
  1048. of nkDotExpr:
  1049. gsub(g, n, 0)
  1050. put(g, tkDot, ".")
  1051. gsub(g, n, 1)
  1052. of nkBind:
  1053. putWithSpace(g, tkBind, "bind")
  1054. gsub(g, n, 0)
  1055. of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString:
  1056. gsub(g, n, 0)
  1057. of nkLambda:
  1058. putWithSpace(g, tkProc, "proc")
  1059. gsub(g, n, paramsPos)
  1060. gsub(g, n, pragmasPos)
  1061. put(g, tkSpaces, Space)
  1062. putWithSpace(g, tkEquals, "=")
  1063. gsub(g, n, bodyPos)
  1064. of nkDo:
  1065. putWithSpace(g, tkDo, "do")
  1066. if paramsPos < n.len:
  1067. doParamsAux(g, n[paramsPos])
  1068. gsub(g, n, pragmasPos)
  1069. put(g, tkColon, ":")
  1070. gsub(g, n, bodyPos)
  1071. of nkConstDef, nkIdentDefs:
  1072. gcomma(g, n, 0, -3)
  1073. if n.len >= 2 and n[^2].kind != nkEmpty:
  1074. putWithSpace(g, tkColon, ":")
  1075. gsub(g, n, n.len - 2)
  1076. if n.len >= 1 and n[^1].kind != nkEmpty:
  1077. put(g, tkSpaces, Space)
  1078. putWithSpace(g, tkEquals, "=")
  1079. gsub(g, n[^1], c)
  1080. of nkVarTuple:
  1081. if n[^1].kind == nkEmpty:
  1082. put(g, tkParLe, "(")
  1083. gcomma(g, n, 0, -2)
  1084. put(g, tkParRi, ")")
  1085. else:
  1086. put(g, tkParLe, "(")
  1087. gcomma(g, n, 0, -3)
  1088. put(g, tkParRi, ")")
  1089. put(g, tkSpaces, Space)
  1090. putWithSpace(g, tkEquals, "=")
  1091. gsub(g, lastSon(n), c)
  1092. of nkExprColonExpr:
  1093. gsub(g, n, 0)
  1094. putWithSpace(g, tkColon, ":")
  1095. gsub(g, n, 1)
  1096. of nkInfix:
  1097. let oldLineLen = g.lineLen # we cache this because lineLen gets updated below
  1098. infixArgument(g, n, 1)
  1099. put(g, tkSpaces, Space)
  1100. gsub(g, n, 0) # binary operator
  1101. # eg: `n1 == n2` decompses as following sum:
  1102. if n.len == 3 and not fits(g, oldLineLen + lsub(g, n[1]) + lsub(g, n[2]) + lsub(g, n[0]) + len(" ")):
  1103. optNL(g, g.indent + longIndentWid)
  1104. else:
  1105. put(g, tkSpaces, Space)
  1106. infixArgument(g, n, 2)
  1107. of nkPrefix:
  1108. if n.len > 0 and n[0].kind == nkIdent and n[0].ident.s == "<//>":
  1109. discard "XXX Remove this hack after 0.20 has been released!"
  1110. else:
  1111. gsub(g, n, 0)
  1112. if n.len > 1:
  1113. let opr = if n[0].kind == nkIdent: n[0].ident
  1114. elif n[0].kind == nkSym: n[0].sym.name
  1115. elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
  1116. else: nil
  1117. let nNext = skipHiddenNodes(n[1])
  1118. if nNext.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
  1119. put(g, tkSpaces, Space)
  1120. if nNext.kind == nkInfix:
  1121. put(g, tkParLe, "(")
  1122. gsub(g, n[1])
  1123. put(g, tkParRi, ")")
  1124. else:
  1125. gsub(g, n[1])
  1126. of nkPostfix:
  1127. gsub(g, n, 1)
  1128. gsub(g, n, 0)
  1129. of nkRange:
  1130. gsub(g, n, 0)
  1131. put(g, tkDotDot, "..")
  1132. gsub(g, n, 1)
  1133. of nkDerefExpr:
  1134. gsub(g, n, 0)
  1135. put(g, tkOpr, "[]")
  1136. of nkAccQuoted:
  1137. put(g, tkAccent, "`")
  1138. if n.len > 0: gsub(g, n[0])
  1139. for i in 1..<n.len:
  1140. put(g, tkSpaces, Space)
  1141. gsub(g, n[i])
  1142. put(g, tkAccent, "`")
  1143. of nkIfExpr:
  1144. putWithSpace(g, tkIf, "if")
  1145. if n.len > 0: gcond(g, n[0][0])
  1146. putWithSpace(g, tkColon, ":")
  1147. if n.len > 0: gsub(g, n[0], 1)
  1148. gsons(g, n, emptyContext, 1)
  1149. of nkElifExpr:
  1150. putWithSpace(g, tkElif, " elif")
  1151. gcond(g, n[0])
  1152. putWithSpace(g, tkColon, ":")
  1153. gsub(g, n, 1)
  1154. of nkElseExpr:
  1155. put(g, tkElse, " else")
  1156. putWithSpace(g, tkColon, ":")
  1157. gsub(g, n, 0)
  1158. of nkTypeOfExpr:
  1159. put(g, tkType, "typeof")
  1160. put(g, tkParLe, "(")
  1161. if n.len > 0: gsub(g, n[0])
  1162. put(g, tkParRi, ")")
  1163. of nkRefTy:
  1164. if n.len > 0:
  1165. putWithSpace(g, tkRef, "ref")
  1166. gsub(g, n[0])
  1167. else:
  1168. put(g, tkRef, "ref")
  1169. of nkPtrTy:
  1170. if n.len > 0:
  1171. putWithSpace(g, tkPtr, "ptr")
  1172. gsub(g, n[0])
  1173. else:
  1174. put(g, tkPtr, "ptr")
  1175. of nkVarTy:
  1176. if n.len > 0:
  1177. putWithSpace(g, tkVar, "var")
  1178. gsub(g, n[0])
  1179. else:
  1180. put(g, tkVar, "var")
  1181. of nkDistinctTy:
  1182. if n.len > 0:
  1183. putWithSpace(g, tkDistinct, "distinct")
  1184. gsub(g, n[0])
  1185. if n.len > 1:
  1186. if n[1].kind == nkWith:
  1187. putWithSpace(g, tkSymbol, " with")
  1188. else:
  1189. putWithSpace(g, tkSymbol, " without")
  1190. gcomma(g, n[1])
  1191. else:
  1192. put(g, tkDistinct, "distinct")
  1193. of nkTypeDef:
  1194. if n[0].kind == nkPragmaExpr:
  1195. # generate pragma after generic
  1196. gsub(g, n[0], 0)
  1197. gsub(g, n, 1)
  1198. gsub(g, n[0], 1)
  1199. else:
  1200. gsub(g, n, 0)
  1201. gsub(g, n, 1)
  1202. put(g, tkSpaces, Space)
  1203. if n.len > 2 and n[2].kind != nkEmpty:
  1204. putWithSpace(g, tkEquals, "=")
  1205. gsub(g, n[2])
  1206. of nkObjectTy:
  1207. if n.len > 0:
  1208. putWithSpace(g, tkObject, "object")
  1209. gsub(g, n[0])
  1210. gsub(g, n[1])
  1211. gcoms(g)
  1212. gsub(g, n[2])
  1213. else:
  1214. put(g, tkObject, "object")
  1215. of nkRecList:
  1216. indentNL(g)
  1217. for i in 0..<n.len:
  1218. optNL(g)
  1219. gsub(g, n[i], c)
  1220. gcoms(g)
  1221. dedent(g)
  1222. putNL(g)
  1223. of nkOfInherit:
  1224. putWithSpace(g, tkOf, "of")
  1225. gsub(g, n, 0)
  1226. of nkProcTy:
  1227. if n.len > 0:
  1228. putWithSpace(g, tkProc, "proc")
  1229. gsub(g, n, 0)
  1230. gsub(g, n, 1)
  1231. else:
  1232. put(g, tkProc, "proc")
  1233. of nkIteratorTy:
  1234. if n.len > 0:
  1235. putWithSpace(g, tkIterator, "iterator")
  1236. gsub(g, n, 0)
  1237. gsub(g, n, 1)
  1238. else:
  1239. put(g, tkIterator, "iterator")
  1240. of nkStaticTy:
  1241. put(g, tkStatic, "static")
  1242. put(g, tkBracketLe, "[")
  1243. if n.len > 0:
  1244. gsub(g, n[0])
  1245. put(g, tkBracketRi, "]")
  1246. of nkEnumTy:
  1247. if n.len > 0:
  1248. putWithSpace(g, tkEnum, "enum")
  1249. gsub(g, n[0])
  1250. gcoms(g)
  1251. indentNL(g)
  1252. gcommaAux(g, n, g.indent, 1)
  1253. gcoms(g) # BUGFIX: comment for the last enum field
  1254. dedent(g)
  1255. else:
  1256. put(g, tkEnum, "enum")
  1257. of nkEnumFieldDef:
  1258. gsub(g, n, 0)
  1259. put(g, tkSpaces, Space)
  1260. putWithSpace(g, tkEquals, "=")
  1261. gsub(g, n, 1)
  1262. of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext)
  1263. of nkIfStmt:
  1264. putWithSpace(g, tkIf, "if")
  1265. gif(g, n)
  1266. of nkWhen, nkRecWhen:
  1267. putWithSpace(g, tkWhen, "when")
  1268. gif(g, n)
  1269. of nkWhileStmt: gwhile(g, n)
  1270. of nkPragmaBlock: gpragmaBlock(g, n)
  1271. of nkCaseStmt, nkRecCase: gcase(g, n)
  1272. of nkTryStmt, nkHiddenTryStmt: gtry(g, n)
  1273. of nkForStmt, nkParForStmt: gfor(g, n)
  1274. of nkBlockStmt, nkBlockExpr: gblock(g, n)
  1275. of nkStaticStmt: gstaticStmt(g, n)
  1276. of nkAsmStmt: gasm(g, n)
  1277. of nkProcDef:
  1278. if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
  1279. gproc(g, n)
  1280. of nkFuncDef:
  1281. if renderNoProcDefs notin g.flags: putWithSpace(g, tkFunc, "func")
  1282. gproc(g, n)
  1283. of nkConverterDef:
  1284. if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
  1285. gproc(g, n)
  1286. of nkMethodDef:
  1287. if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method")
  1288. gproc(g, n)
  1289. of nkIteratorDef:
  1290. if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator")
  1291. gproc(g, n)
  1292. of nkMacroDef:
  1293. if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro")
  1294. gproc(g, n)
  1295. of nkTemplateDef:
  1296. if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template")
  1297. gproc(g, n)
  1298. of nkTypeSection:
  1299. gsection(g, n, emptyContext, tkType, "type")
  1300. of nkConstSection:
  1301. initContext(a)
  1302. incl(a.flags, rfInConstExpr)
  1303. gsection(g, n, a, tkConst, "const")
  1304. of nkVarSection, nkLetSection, nkUsingStmt:
  1305. if n.len == 0: return
  1306. if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
  1307. elif n.kind == nkLetSection: putWithSpace(g, tkLet, "let")
  1308. else: putWithSpace(g, tkUsing, "using")
  1309. if n.len > 1:
  1310. gcoms(g)
  1311. indentNL(g)
  1312. for i in 0..<n.len:
  1313. optNL(g)
  1314. gsub(g, n[i])
  1315. gcoms(g)
  1316. dedent(g)
  1317. else:
  1318. gsub(g, n[0])
  1319. of nkReturnStmt:
  1320. putWithSpace(g, tkReturn, "return")
  1321. if n.len > 0 and n[0].kind == nkAsgn:
  1322. gsub(g, n[0], 1)
  1323. else:
  1324. gsub(g, n, 0)
  1325. of nkRaiseStmt:
  1326. putWithSpace(g, tkRaise, "raise")
  1327. gsub(g, n, 0)
  1328. of nkYieldStmt:
  1329. putWithSpace(g, tkYield, "yield")
  1330. gsub(g, n, 0)
  1331. of nkDiscardStmt:
  1332. putWithSpace(g, tkDiscard, "discard")
  1333. gsub(g, n, 0)
  1334. of nkBreakStmt:
  1335. putWithSpace(g, tkBreak, "break")
  1336. gsub(g, n, 0)
  1337. of nkContinueStmt:
  1338. putWithSpace(g, tkContinue, "continue")
  1339. gsub(g, n, 0)
  1340. of nkPragma:
  1341. if g.inPragma <= 0:
  1342. inc g.inPragma
  1343. #if not previousNL(g):
  1344. put(g, tkSpaces, Space)
  1345. put(g, tkCurlyDotLe, "{.")
  1346. gcomma(g, n, emptyContext)
  1347. put(g, tkCurlyDotRi, ".}")
  1348. dec g.inPragma
  1349. else:
  1350. gcomma(g, n, emptyContext)
  1351. of nkImportStmt, nkExportStmt:
  1352. if n.kind == nkImportStmt:
  1353. putWithSpace(g, tkImport, "import")
  1354. else:
  1355. putWithSpace(g, tkExport, "export")
  1356. gcoms(g)
  1357. indentNL(g)
  1358. gcommaAux(g, n, g.indent)
  1359. dedent(g)
  1360. putNL(g)
  1361. of nkImportExceptStmt, nkExportExceptStmt:
  1362. if n.kind == nkImportExceptStmt:
  1363. putWithSpace(g, tkImport, "import")
  1364. else:
  1365. putWithSpace(g, tkExport, "export")
  1366. gsub(g, n, 0)
  1367. put(g, tkSpaces, Space)
  1368. putWithSpace(g, tkExcept, "except")
  1369. gcommaAux(g, n, g.indent, 1)
  1370. gcoms(g)
  1371. putNL(g)
  1372. of nkFromStmt:
  1373. putWithSpace(g, tkFrom, "from")
  1374. gsub(g, n, 0)
  1375. put(g, tkSpaces, Space)
  1376. putWithSpace(g, tkImport, "import")
  1377. gcomma(g, n, emptyContext, 1)
  1378. putNL(g)
  1379. of nkIncludeStmt:
  1380. putWithSpace(g, tkInclude, "include")
  1381. gcoms(g)
  1382. indentNL(g)
  1383. gcommaAux(g, n, g.indent)
  1384. dedent(g)
  1385. putNL(g)
  1386. of nkCommentStmt:
  1387. gcoms(g)
  1388. optNL(g)
  1389. of nkOfBranch:
  1390. optNL(g)
  1391. putWithSpace(g, tkOf, "of")
  1392. gcomma(g, n, c, 0, - 2)
  1393. putWithSpace(g, tkColon, ":")
  1394. gcoms(g)
  1395. gstmts(g, lastSon(n), c)
  1396. of nkImportAs:
  1397. gsub(g, n, 0)
  1398. put(g, tkSpaces, Space)
  1399. putWithSpace(g, tkAs, "as")
  1400. gsub(g, n, 1)
  1401. of nkBindStmt:
  1402. putWithSpace(g, tkBind, "bind")
  1403. gcomma(g, n, c)
  1404. of nkMixinStmt:
  1405. putWithSpace(g, tkMixin, "mixin")
  1406. gcomma(g, n, c)
  1407. of nkElifBranch:
  1408. optNL(g)
  1409. putWithSpace(g, tkElif, "elif")
  1410. gsub(g, n, 0)
  1411. putWithSpace(g, tkColon, ":")
  1412. gcoms(g)
  1413. gstmts(g, n[1], c)
  1414. of nkElse:
  1415. optNL(g)
  1416. put(g, tkElse, "else")
  1417. putWithSpace(g, tkColon, ":")
  1418. gcoms(g)
  1419. gstmts(g, n[0], c)
  1420. of nkFinally, nkDefer:
  1421. optNL(g)
  1422. if n.kind == nkFinally:
  1423. put(g, tkFinally, "finally")
  1424. else:
  1425. put(g, tkDefer, "defer")
  1426. putWithSpace(g, tkColon, ":")
  1427. gcoms(g)
  1428. gstmts(g, n[0], c)
  1429. of nkExceptBranch:
  1430. optNL(g)
  1431. if n.len != 1:
  1432. putWithSpace(g, tkExcept, "except")
  1433. else:
  1434. put(g, tkExcept, "except")
  1435. gcomma(g, n, 0, -2)
  1436. putWithSpace(g, tkColon, ":")
  1437. gcoms(g)
  1438. gstmts(g, lastSon(n), c)
  1439. of nkGenericParams:
  1440. proc hasExplicitParams(gp: PNode): bool =
  1441. for p in gp:
  1442. if p.typ == nil or tfImplicitTypeParam notin p.typ.flags:
  1443. return true
  1444. return false
  1445. if n.hasExplicitParams:
  1446. put(g, tkBracketLe, "[")
  1447. gsemicolon(g, n)
  1448. put(g, tkBracketRi, "]")
  1449. of nkFormalParams:
  1450. put(g, tkParLe, "(")
  1451. gsemicolon(g, n, 1)
  1452. put(g, tkParRi, ")")
  1453. if n.len > 0 and n[0].kind != nkEmpty:
  1454. putWithSpace(g, tkColon, ":")
  1455. gsub(g, n[0])
  1456. of nkTupleTy:
  1457. put(g, tkTuple, "tuple")
  1458. put(g, tkBracketLe, "[")
  1459. gcomma(g, n)
  1460. put(g, tkBracketRi, "]")
  1461. of nkTupleClassTy:
  1462. put(g, tkTuple, "tuple")
  1463. of nkComesFrom:
  1464. put(g, tkParLe, "(ComesFrom|")
  1465. gsub(g, n, 0)
  1466. put(g, tkParRi, ")")
  1467. of nkGotoState:
  1468. var c: TContext
  1469. initContext c
  1470. putWithSpace g, tkSymbol, "goto"
  1471. gsons(g, n, c)
  1472. of nkState:
  1473. var c: TContext
  1474. initContext c
  1475. putWithSpace g, tkSymbol, "state"
  1476. gsub(g, n[0], c)
  1477. putWithSpace(g, tkColon, ":")
  1478. indentNL(g)
  1479. gsons(g, n, c, 1)
  1480. dedent(g)
  1481. of nkBreakState:
  1482. put(g, tkTuple, "breakstate")
  1483. if renderIds in g.flags:
  1484. gsons(g, n, c, 0)
  1485. of nkTypeClassTy:
  1486. gTypeClassTy(g, n)
  1487. else:
  1488. #nkNone, nkExplicitTypeListCall:
  1489. internalError(g.config, n.info, "rnimsyn.gsub(" & $n.kind & ')')
  1490. proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string =
  1491. if n == nil: return "<nil tree>"
  1492. var g: TSrcGen
  1493. initSrcGen(g, renderFlags, newPartialConfigRef())
  1494. # do not indent the initial statement list so that
  1495. # writeFile("file.nim", repr n)
  1496. # produces working Nim code:
  1497. if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
  1498. gstmts(g, n, emptyContext, doIndent = false)
  1499. else:
  1500. gsub(g, n)
  1501. result = g.buf
  1502. proc `$`*(n: PNode): string = n.renderTree
  1503. proc renderModule*(n: PNode, infile, outfile: string,
  1504. renderFlags: TRenderFlags = {};
  1505. fid = FileIndex(-1);
  1506. conf: ConfigRef = nil) =
  1507. var
  1508. f: File
  1509. g: TSrcGen
  1510. initSrcGen(g, renderFlags, conf)
  1511. g.fid = fid
  1512. for i in 0..<n.len:
  1513. gsub(g, n[i])
  1514. optNL(g)
  1515. case n[i].kind
  1516. of nkTypeSection, nkConstSection, nkVarSection, nkLetSection,
  1517. nkCommentStmt: putNL(g)
  1518. else: discard
  1519. gcoms(g)
  1520. if open(f, outfile, fmWrite):
  1521. write(f, g.buf)
  1522. close(f)
  1523. else:
  1524. rawMessage(g.config, errGenerated, "cannot open file: " & outfile)
  1525. proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
  1526. initSrcGen(r, renderFlags, newPartialConfigRef())
  1527. gsub(r, n)
  1528. proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) =
  1529. if r.idx < r.tokens.len:
  1530. kind = r.tokens[r.idx].kind
  1531. let length = r.tokens[r.idx].length.int
  1532. literal = substr(r.buf, r.pos, r.pos + length - 1)
  1533. inc(r.pos, length)
  1534. inc(r.idx)
  1535. else:
  1536. kind = tkEof
  1537. proc getTokSym*(r: TSrcGen): PSym =
  1538. if r.idx > 0 and r.idx <= r.tokens.len:
  1539. result = r.tokens[r.idx-1].sym
  1540. else:
  1541. result = nil
  1542. proc quoteExpr*(a: string): string {.inline.} =
  1543. ## can be used for quoting expressions in error msgs.
  1544. "'" & a & "'"
  1545. proc genFieldDefect*(field: PSym, disc: PSym): string =
  1546. ## this needs to be in a module accessible by jsgen, ccgexprs, and vm to
  1547. ## provide this error msg FieldDefect; msgs would be better but it does not
  1548. ## import ast
  1549. result = field.name.s.quoteExpr & " is not accessible using discriminant " &
  1550. disc.name.s.quoteExpr & " of type " &
  1551. disc.owner.name.s.quoteExpr