renderer.nim 48 KB

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