renderer.nim 56 KB

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