renderer.nim 44 KB

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