renderer.nim 49 KB

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