renderer.nim 56 KB

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