renderer.nim 52 KB

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