renderer.nim 52 KB

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