renderer.nim 56 KB

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