renderer.nim 54 KB

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