renderer.nim 47 KB

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