mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
* remove some dead code and leftovers from past features * fix yaml printing of uint64 literals
1867 lines
56 KiB
Nim
1867 lines
56 KiB
Nim
#
|
|
#
|
|
# The Nim Compiler
|
|
# (c) Copyright 2013 Andreas Rumpf
|
|
#
|
|
# See the file "copying.txt", included in this
|
|
# distribution, for details about the copyright.
|
|
#
|
|
|
|
# This module implements the renderer of the standard Nim representation.
|
|
|
|
# 'import renderer' is so useful for debugging
|
|
# that Nim shouldn't produce a warning for that:
|
|
{.used.}
|
|
|
|
import
|
|
lexer, options, idents, ast, msgs, lineinfos, wordrecg
|
|
|
|
import std/[strutils]
|
|
|
|
when defined(nimPreviewSlimSystem):
|
|
import std/[syncio, assertions, formatfloat]
|
|
|
|
type
|
|
TRenderFlag* = enum
|
|
renderNone, renderNoBody, renderNoComments, renderDocComments,
|
|
renderNoPragmas, renderIds, renderNoProcDefs, renderSyms, renderRunnableExamples,
|
|
renderIr, renderNonExportedFields, renderExpandUsing
|
|
|
|
TRenderFlags* = set[TRenderFlag]
|
|
TRenderTok* = object
|
|
kind*: TokType
|
|
length*: int16
|
|
sym*: PSym
|
|
|
|
Section = enum
|
|
GenericParams
|
|
ObjectDef
|
|
|
|
TRenderTokSeq* = seq[TRenderTok]
|
|
TSrcGen* = object
|
|
indent*: int
|
|
lineLen*: int
|
|
col: int
|
|
pos*: int # current position for iteration over the buffer
|
|
idx*: int # current token index for iteration over the buffer
|
|
tokens*: TRenderTokSeq
|
|
buf*: string
|
|
pendingNL*: int # negative if not active; else contains the
|
|
# indentation value
|
|
pendingWhitespace: int
|
|
comStack*: seq[PNode] # comment stack
|
|
flags*: TRenderFlags
|
|
inside: set[Section] # Keeps track of contexts we are in
|
|
checkAnon: bool # we're in a context that can contain sfAnon
|
|
inPragma: int
|
|
when defined(nimpretty):
|
|
pendingNewlineCount: int
|
|
fid*: FileIndex
|
|
config*: ConfigRef
|
|
mangler: seq[PSym]
|
|
|
|
proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string
|
|
|
|
# We render the source code in a two phases: The first
|
|
# determines how long the subtree will likely be, the second
|
|
# phase appends to a buffer that will be the output.
|
|
|
|
proc disamb(g: var TSrcGen; s: PSym): int =
|
|
# we group by 's.name.s' to compute the stable name ID.
|
|
result = 0
|
|
for i in 0 ..< g.mangler.len:
|
|
if s == g.mangler[i]: return result
|
|
if s.name.s == g.mangler[i].name.s: inc result
|
|
g.mangler.add s
|
|
|
|
proc isKeyword*(i: PIdent): bool =
|
|
if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
|
|
(i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
|
|
result = true
|
|
else:
|
|
result = false
|
|
|
|
proc isExported(n: PNode): bool =
|
|
## Checks if an ident is exported.
|
|
## This is meant to be used with idents in nkIdentDefs.
|
|
case n.kind
|
|
of nkPostfix:
|
|
n[0].ident.s == "*" and n[1].kind == nkIdent
|
|
of nkPragmaExpr:
|
|
n[0].isExported()
|
|
else: false
|
|
|
|
proc renderDefinitionName*(s: PSym, noQuotes = false): string =
|
|
## Returns the definition name of the symbol.
|
|
##
|
|
## If noQuotes is false the symbol may be returned in backticks. This will
|
|
## happen if the name happens to be a keyword or the first character is not
|
|
## part of the SymStartChars set.
|
|
let x = s.name.s
|
|
if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(s.name)):
|
|
result = x
|
|
else:
|
|
result = '`' & x & '`'
|
|
|
|
template inside(g: var TSrcGen, section: Section, body: untyped) =
|
|
## Runs `body` with `section` included in `g.inside`.
|
|
## Removes it at the end of the body if `g` wasn't inside it
|
|
## before the template.
|
|
let wasntInSection = section notin g.inside
|
|
g.inside.incl section
|
|
body
|
|
if wasntInSection:
|
|
g.inside.excl section
|
|
|
|
template outside(g: var TSrcGen, section: Section, body: untyped) =
|
|
## Temporarily removes `section` from `g.inside`. Adds it back
|
|
## at the end of the body if `g` was inside it before the template
|
|
let wasInSection = section in g.inside
|
|
g.inside.excl section
|
|
body
|
|
if wasInSection:
|
|
g.inside.incl section
|
|
|
|
const
|
|
IndentWidth = 2
|
|
longIndentWid = IndentWidth * 2
|
|
MaxLineLen = 80
|
|
LineCommentColumn = 30
|
|
|
|
when defined(nimpretty):
|
|
proc minmaxLine(n: PNode): (int, int) =
|
|
case n.kind
|
|
of nkTripleStrLit:
|
|
result = (n.info.line.int, n.info.line.int + countLines(n.strVal))
|
|
of nkCommentStmt:
|
|
result = (n.info.line.int, n.info.line.int + countLines(n.comment))
|
|
else:
|
|
result = (n.info.line.int, n.info.line.int)
|
|
for i in 0..<n.safeLen:
|
|
let (currMin, currMax) = minmaxLine(n[i])
|
|
if currMin < result[0]: result[0] = currMin
|
|
if currMax > result[1]: result[1] = currMax
|
|
|
|
proc lineDiff(a, b: PNode): int =
|
|
result = minmaxLine(b)[0] - minmaxLine(a)[1]
|
|
|
|
proc initSrcGen(renderFlags: TRenderFlags; config: ConfigRef): TSrcGen =
|
|
result = TSrcGen(comStack: @[], tokens: @[], indent: 0,
|
|
lineLen: 0, pos: 0, idx: 0, buf: "",
|
|
flags: renderFlags, pendingNL: -1,
|
|
pendingWhitespace: -1, inside: {},
|
|
config: config
|
|
)
|
|
|
|
proc addTok(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
|
|
g.tokens.add TRenderTok(kind: kind, length: int16(s.len), sym: sym)
|
|
g.buf.add(s)
|
|
if kind != tkSpaces:
|
|
inc g.col, s.len
|
|
|
|
proc addPendingNL(g: var TSrcGen) =
|
|
if g.pendingNL >= 0:
|
|
when defined(nimpretty):
|
|
let newlines = repeat("\n", clamp(g.pendingNewlineCount, 1, 3))
|
|
else:
|
|
const newlines = "\n"
|
|
addTok(g, tkSpaces, newlines & spaces(g.pendingNL))
|
|
g.lineLen = g.pendingNL
|
|
g.col = g.pendingNL
|
|
g.pendingNL = - 1
|
|
g.pendingWhitespace = -1
|
|
elif g.pendingWhitespace >= 0:
|
|
addTok(g, tkSpaces, spaces(g.pendingWhitespace))
|
|
g.pendingWhitespace = -1
|
|
|
|
proc putNL(g: var TSrcGen, indent: int) =
|
|
if g.pendingNL >= 0: addPendingNL(g)
|
|
else:
|
|
addTok(g, tkSpaces, "\n")
|
|
g.col = 0
|
|
|
|
g.pendingNL = indent
|
|
g.lineLen = indent
|
|
g.pendingWhitespace = -1
|
|
|
|
proc previousNL(g: TSrcGen): bool =
|
|
result = g.pendingNL >= 0 or (g.tokens.len > 0 and
|
|
g.tokens[^1].kind == tkSpaces)
|
|
|
|
proc putNL(g: var TSrcGen) =
|
|
putNL(g, g.indent)
|
|
|
|
proc optNL(g: var TSrcGen, indent: int) =
|
|
g.pendingNL = indent
|
|
g.lineLen = indent
|
|
g.col = g.indent
|
|
when defined(nimpretty): g.pendingNewlineCount = 0
|
|
|
|
proc optNL(g: var TSrcGen) =
|
|
optNL(g, g.indent)
|
|
|
|
proc optNL(g: var TSrcGen; a, b: PNode) =
|
|
g.pendingNL = g.indent
|
|
g.lineLen = g.indent
|
|
g.col = g.indent
|
|
when defined(nimpretty): g.pendingNewlineCount = lineDiff(a, b)
|
|
|
|
proc indentNL(g: var TSrcGen) =
|
|
inc(g.indent, IndentWidth)
|
|
g.pendingNL = g.indent
|
|
g.lineLen = g.indent
|
|
|
|
proc dedent(g: var TSrcGen) =
|
|
dec(g.indent, IndentWidth)
|
|
assert(g.indent >= 0)
|
|
if g.pendingNL > IndentWidth:
|
|
dec(g.pendingNL, IndentWidth)
|
|
dec(g.lineLen, IndentWidth)
|
|
|
|
proc put(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
|
|
if kind != tkSpaces:
|
|
addPendingNL(g)
|
|
if s.len > 0 or kind in {tkHideableStart, tkHideableEnd}:
|
|
addTok(g, kind, s, sym)
|
|
else:
|
|
g.pendingWhitespace = s.len
|
|
inc g.col, s.len
|
|
inc(g.lineLen, s.len)
|
|
|
|
proc putComment(g: var TSrcGen, s: string) =
|
|
if s.len == 0: return
|
|
var i = 0
|
|
let hi = s.len - 1
|
|
let isCode = (s.len >= 2) and (s[1] != ' ')
|
|
let ind = g.col
|
|
var com = "## "
|
|
while i <= hi:
|
|
case s[i]
|
|
of '\0':
|
|
break
|
|
of '\r':
|
|
put(g, tkComment, com)
|
|
com = "## "
|
|
inc(i)
|
|
if i <= hi and s[i] == '\n': inc(i)
|
|
optNL(g, ind)
|
|
of '\n':
|
|
put(g, tkComment, com)
|
|
com = "## "
|
|
inc(i)
|
|
optNL(g, ind)
|
|
of ' ', '\t':
|
|
com.add(s[i])
|
|
inc(i)
|
|
else:
|
|
# we may break the comment into a multi-line comment if the line
|
|
# gets too long:
|
|
# compute length of the following word:
|
|
var j = i
|
|
while j <= hi and s[j] > ' ': inc(j)
|
|
if not isCode and (g.col + (j - i) > MaxLineLen):
|
|
put(g, tkComment, com)
|
|
optNL(g, ind)
|
|
com = "## "
|
|
while i <= hi and s[i] > ' ':
|
|
com.add(s[i])
|
|
inc(i)
|
|
put(g, tkComment, com)
|
|
optNL(g)
|
|
|
|
proc maxLineLength(s: string): int =
|
|
result = 0
|
|
if s.len == 0: return 0
|
|
var i = 0
|
|
let hi = s.len - 1
|
|
var lineLen = 0
|
|
while i <= hi:
|
|
case s[i]
|
|
of '\0':
|
|
break
|
|
of '\r':
|
|
inc(i)
|
|
if i <= hi and s[i] == '\n': inc(i)
|
|
result = max(result, lineLen)
|
|
lineLen = 0
|
|
of '\n':
|
|
inc(i)
|
|
result = max(result, lineLen)
|
|
lineLen = 0
|
|
else:
|
|
inc(lineLen)
|
|
inc(i)
|
|
|
|
proc putRawStr(g: var TSrcGen, kind: TokType, s: string) =
|
|
var i = 0
|
|
let hi = s.len - 1
|
|
var str = ""
|
|
while i <= hi:
|
|
case s[i]
|
|
of '\r':
|
|
put(g, kind, str)
|
|
str = ""
|
|
inc(i)
|
|
if i <= hi and s[i] == '\n': inc(i)
|
|
optNL(g, 0)
|
|
of '\n':
|
|
put(g, kind, str)
|
|
str = ""
|
|
inc(i)
|
|
optNL(g, 0)
|
|
else:
|
|
str.add(s[i])
|
|
inc(i)
|
|
put(g, kind, str)
|
|
|
|
proc containsNL(s: string): bool =
|
|
for i in 0..<s.len:
|
|
case s[i]
|
|
of '\r', '\n':
|
|
return true
|
|
else:
|
|
discard
|
|
result = false
|
|
|
|
proc pushCom(g: var TSrcGen, n: PNode) =
|
|
setLen(g.comStack, g.comStack.len + 1)
|
|
g.comStack[^1] = n
|
|
|
|
proc popAllComs(g: var TSrcGen) =
|
|
setLen(g.comStack, 0)
|
|
|
|
const
|
|
Space = " "
|
|
|
|
proc shouldRenderComment(g: TSrcGen): bool {.inline.} =
|
|
(renderNoComments notin g.flags or renderDocComments in g.flags)
|
|
|
|
proc shouldRenderComment(g: TSrcGen, n: PNode): bool {.inline.} =
|
|
shouldRenderComment(g) and n.comment.len > 0
|
|
|
|
proc gcom(g: var TSrcGen, n: PNode) =
|
|
assert(n != nil)
|
|
if shouldRenderComment(g, n):
|
|
var oneSpaceAdded = 0
|
|
if (g.pendingNL < 0) and (g.buf.len > 0) and (g.buf[^1] != ' '):
|
|
put(g, tkSpaces, Space)
|
|
oneSpaceAdded = 1
|
|
# Before long comments we cannot make sure that a newline is generated,
|
|
# because this might be wrong. But it is no problem in practice.
|
|
if (g.pendingNL < 0) and (g.buf.len > 0) and
|
|
(g.col < LineCommentColumn):
|
|
var ml = maxLineLength(n.comment)
|
|
if ml + LineCommentColumn <= MaxLineLen:
|
|
put(g, tkSpaces, spaces(LineCommentColumn - g.col))
|
|
dec g.col, oneSpaceAdded
|
|
putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
|
|
|
|
proc gcoms(g: var TSrcGen) =
|
|
for i in 0..high(g.comStack): gcom(g, g.comStack[i])
|
|
popAllComs(g)
|
|
|
|
proc lsub(g: TSrcGen; n: PNode): int
|
|
proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
|
|
proc skip(t: PType): PType =
|
|
result = t
|
|
while result != nil and result.kind in {tyGenericInst, tyRange, tyVar,
|
|
tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}:
|
|
result = lastSon(result)
|
|
|
|
result = ""
|
|
let typ = n.typ.skip
|
|
if typ != nil and typ.kind in {tyBool, tyEnum}:
|
|
if sfPure in typ.sym.flags:
|
|
result = typ.sym.name.s & '.'
|
|
let enumfields = typ.n
|
|
# we need a slow linear search because of enums with holes:
|
|
for e in items(enumfields):
|
|
if e.sym.position == x:
|
|
result &= e.sym.name.s
|
|
return
|
|
|
|
if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
|
|
elif nfBase8 in n.flags:
|
|
var y = if size < sizeof(BiggestInt): x and ((1.BiggestInt shl (size*8)) - 1)
|
|
else: x
|
|
result = "0o" & toOct(y, size * 3)
|
|
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
|
|
else: result = $x
|
|
|
|
proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
|
|
if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
|
|
elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
|
|
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
|
|
else: result = $cast[BiggestUInt](x)
|
|
|
|
proc atom(g: TSrcGen; n: PNode): string =
|
|
when defined(nimpretty):
|
|
doAssert g.config != nil, "g.config not initialized!"
|
|
let comment = if n.info.commentOffsetA < n.info.commentOffsetB:
|
|
" " & fileSection(g.config, g.fid, n.info.commentOffsetA, n.info.commentOffsetB)
|
|
else:
|
|
""
|
|
if n.info.offsetA <= n.info.offsetB:
|
|
# for some constructed tokens this can not be the case and we're better
|
|
# off to not mess with the offset then.
|
|
return fileSection(g.config, g.fid, n.info.offsetA, n.info.offsetB) & comment
|
|
var f: float32
|
|
case n.kind
|
|
of nkEmpty: result = ""
|
|
of nkIdent: result = n.ident.s
|
|
of nkSym: result = n.sym.name.s
|
|
of nkClosedSymChoice, nkOpenSymChoice: result = n[0].sym.name.s
|
|
of nkStrLit: result = ""; result.addQuoted(n.strVal)
|
|
of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"'
|
|
of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\""
|
|
of nkCharLit:
|
|
result = "\'"
|
|
result.addEscapedChar(chr(int(n.intVal)));
|
|
result.add '\''
|
|
of nkIntLit: result = litAux(g, n, n.intVal, 4)
|
|
of nkInt8Lit: result = litAux(g, n, n.intVal, 1) & "\'i8"
|
|
of nkInt16Lit: result = litAux(g, n, n.intVal, 2) & "\'i16"
|
|
of nkInt32Lit: result = litAux(g, n, n.intVal, 4) & "\'i32"
|
|
of nkInt64Lit: result = litAux(g, n, n.intVal, 8) & "\'i64"
|
|
of nkUIntLit: result = ulitAux(g, n, n.intVal, 4) & "\'u"
|
|
of nkUInt8Lit: result = ulitAux(g, n, n.intVal, 1) & "\'u8"
|
|
of nkUInt16Lit: result = ulitAux(g, n, n.intVal, 2) & "\'u16"
|
|
of nkUInt32Lit: result = ulitAux(g, n, n.intVal, 4) & "\'u32"
|
|
of nkUInt64Lit: result = ulitAux(g, n, n.intVal, 8) & "\'u64"
|
|
of nkFloatLit:
|
|
if n.flags * {nfBase2, nfBase8, nfBase16} == {}: result = $(n.floatVal)
|
|
else: result = litAux(g, n, (cast[ptr int64](addr(n.floatVal)))[] , 8)
|
|
of nkFloat32Lit:
|
|
if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
|
|
result = $n.floatVal & "\'f32"
|
|
else:
|
|
f = n.floatVal.float32
|
|
result = litAux(g, n, (cast[ptr int32](addr(f)))[], 4) & "\'f32"
|
|
of nkFloat64Lit:
|
|
if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
|
|
result = $n.floatVal & "\'f64"
|
|
else:
|
|
result = litAux(g, n, (cast[ptr int64](addr(n.floatVal)))[], 8) & "\'f64"
|
|
of nkNilLit: result = "nil"
|
|
of nkType:
|
|
if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
|
|
else: result = "[type node]"
|
|
else:
|
|
internalError(g.config, "renderer.atom " & $n.kind)
|
|
result = ""
|
|
|
|
proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
|
|
assert(theEnd < 0)
|
|
result = 0
|
|
for i in start..n.len + theEnd:
|
|
let param = n[i]
|
|
if nfDefaultParam notin param.flags:
|
|
inc(result, lsub(g, param))
|
|
inc(result, 2) # for ``, ``
|
|
if result > 0:
|
|
dec(result, 2) # last does not get a comma!
|
|
|
|
proc lsons(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
|
|
assert(theEnd < 0)
|
|
result = 0
|
|
for i in start..n.len + theEnd: inc(result, lsub(g, n[i]))
|
|
|
|
proc origUsingType(n: PNode): PSym {.inline.} =
|
|
## Returns the type that a parameter references. Check with referencesUsing first
|
|
## to check `n` is actually referencing a using node
|
|
# If the node is untyped the typ field will be nil
|
|
if n[0].sym.typ != nil:
|
|
n[0].sym.typ.sym
|
|
else: nil
|
|
|
|
proc referencesUsing(n: PNode): bool =
|
|
## Returns true if n references a using statement.
|
|
## e.g. proc foo(x) # x doesn't have type or def value so it references a using
|
|
result = n.kind == nkIdentDefs and
|
|
# Sometimes the node might not have been semmed (e.g. doc0) and will be nkIdent instead
|
|
n[0].kind == nkSym and
|
|
# Templates/macros can have parameters with no type (But their orig type will be nil)
|
|
n.origUsingType != nil and
|
|
n[1].kind == nkEmpty and n[2].kind == nkEmpty
|
|
|
|
proc lsub(g: TSrcGen; n: PNode): int =
|
|
# computes the length of a tree
|
|
result = 0
|
|
if isNil(n): return 0
|
|
if shouldRenderComment(g, n): return MaxLineLen + 1
|
|
case n.kind
|
|
of nkEmpty: result = 0
|
|
of nkTripleStrLit:
|
|
if containsNL(n.strVal): result = MaxLineLen + 1
|
|
else: result = atom(g, n).len
|
|
of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
|
|
result = atom(g, n).len
|
|
of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr:
|
|
result = lsub(g, n[0]) + lcomma(g, n, 1) + 2
|
|
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(g, n[1])
|
|
of nkCast: result = lsub(g, n[0]) + lsub(g, n[1]) + len("cast[]()")
|
|
of nkAddr: result = (if n.len>0: lsub(g, n[0]) + len("addr()") else: 4)
|
|
of nkStaticExpr: result = lsub(g, n[0]) + len("static_")
|
|
of nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString: result = lsub(g, n[0])
|
|
of nkCommand: result = lsub(g, n[0]) + lcomma(g, n, 1) + 1
|
|
of nkExprEqExpr, nkAsgn, nkFastAsgn: result = lsons(g, n) + 3
|
|
of nkPar, nkCurly, nkBracket, nkClosure: result = lcomma(g, n) + 2
|
|
of nkTupleConstr:
|
|
# assume the trailing comma:
|
|
result = lcomma(g, n) + 3
|
|
of nkArgList: result = lcomma(g, n)
|
|
of nkTableConstr:
|
|
result = if n.len > 0: lcomma(g, n) + 2 else: len("{:}")
|
|
of nkClosedSymChoice, nkOpenSymChoice:
|
|
if n.len > 0: result += lsub(g, n[0])
|
|
of nkTupleTy: result = lcomma(g, n) + len("tuple[]")
|
|
of nkTupleClassTy: result = len("tuple")
|
|
of nkDotExpr: result = lsons(g, n) + 1
|
|
of nkBind: result = lsons(g, n) + len("bind_")
|
|
of nkBindStmt: result = lcomma(g, n) + len("bind_")
|
|
of nkMixinStmt: result = lcomma(g, n) + len("mixin_")
|
|
of nkCheckedFieldExpr: result = lsub(g, n[0])
|
|
of nkLambda: result = lsons(g, n) + len("proc__=_")
|
|
of nkDo: result = lsons(g, n) + len("do__:_")
|
|
of nkConstDef, nkIdentDefs:
|
|
result = lcomma(g, n, 0, - 3)
|
|
if n.referencesUsing:
|
|
result += lsub(g, newSymNode(n.origUsingType)) + 2
|
|
else:
|
|
if n[^2].kind != nkEmpty: result += lsub(g, n[^2]) + 2
|
|
if n[^1].kind != nkEmpty: result += lsub(g, n[^1]) + 3
|
|
of nkVarTuple:
|
|
if n[^1].kind == nkEmpty:
|
|
result = lcomma(g, n, 0, - 2) + len("()")
|
|
else:
|
|
result = lcomma(g, n, 0, - 3) + len("() = ") + lsub(g, lastSon(n))
|
|
of nkChckRangeF: result = len("chckRangeF") + 2 + lcomma(g, n)
|
|
of nkChckRange64: result = len("chckRange64") + 2 + lcomma(g, n)
|
|
of nkChckRange: result = len("chckRange") + 2 + lcomma(g, n)
|
|
of nkObjDownConv, nkObjUpConv:
|
|
result = 2
|
|
if n.len >= 1: result += lsub(g, n[0])
|
|
result += lcomma(g, n, 1)
|
|
of nkExprColonExpr: result = lsons(g, n) + 2
|
|
of nkInfix: result = lsons(g, n) + 2
|
|
of nkPrefix:
|
|
result = lsons(g, n)+1+(if n.len > 0 and n[1].kind == nkInfix: 2 else: 0)
|
|
of nkPostfix: result = lsons(g, n)
|
|
of nkCallStrLit: result = lsons(g, n)
|
|
of nkPragmaExpr: result = lsub(g, n[0]) + lcomma(g, n, 1)
|
|
of nkRange: result = lsons(g, n) + 2
|
|
of nkDerefExpr: result = lsub(g, n[0]) + 2
|
|
of nkAccQuoted: result = lsons(g, n) + 2
|
|
of nkIfExpr:
|
|
result = lsub(g, n[0][0]) + lsub(g, n[0][1]) + lsons(g, n, 1) +
|
|
len("if_:_")
|
|
of nkElifExpr: result = lsons(g, n) + len("_elif_:_")
|
|
of nkElseExpr: result = lsub(g, n[0]) + len("_else:_") # type descriptions
|
|
of nkTypeOfExpr: result = (if n.len > 0: lsub(g, n[0]) else: 0)+len("typeof()")
|
|
of nkRefTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ref")
|
|
of nkPtrTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ptr")
|
|
of nkVarTy, nkOutTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("var")
|
|
of nkDistinctTy:
|
|
result = len("distinct") + (if n.len > 0: lsub(g, n[0])+1 else: 0)
|
|
if n.len > 1:
|
|
result += (if n[1].kind == nkWith: len("_with_") else: len("_without_"))
|
|
result += lcomma(g, n[1])
|
|
of nkStaticTy: result = (if n.len > 0: lsub(g, n[0]) else: 0) +
|
|
len("static[]")
|
|
of nkTypeDef: result = lsons(g, n) + 3
|
|
of nkOfInherit: result = lsub(g, n[0]) + len("of_")
|
|
of nkProcTy: result = lsons(g, n) + len("proc_")
|
|
of nkIteratorTy: result = lsons(g, n) + len("iterator_")
|
|
of nkSinkAsgn: result = lsons(g, n) + len("`=sink`(, )")
|
|
of nkEnumTy:
|
|
if n.len > 0:
|
|
result = lsub(g, n[0]) + lcomma(g, n, 1) + len("enum_")
|
|
else:
|
|
result = len("enum")
|
|
of nkEnumFieldDef: result = lsons(g, n) + 3
|
|
of nkVarSection, nkLetSection:
|
|
if n.len > 1: result = MaxLineLen + 1
|
|
else: result = lsons(g, n) + len("var_")
|
|
of nkUsingStmt:
|
|
if n.len > 1: result = MaxLineLen + 1
|
|
else: result = lsons(g, n) + len("using_")
|
|
of nkReturnStmt:
|
|
if n.len > 0 and n[0].kind == nkAsgn and renderIr notin g.flags:
|
|
result = len("return_") + lsub(g, n[0][1])
|
|
else:
|
|
result = len("return_") + lsub(g, n[0])
|
|
of nkRaiseStmt: result = lsub(g, n[0]) + len("raise_")
|
|
of nkYieldStmt: result = lsub(g, n[0]) + len("yield_")
|
|
of nkDiscardStmt: result = lsub(g, n[0]) + len("discard_")
|
|
of nkBreakStmt: result = lsub(g, n[0]) + len("break_")
|
|
of nkContinueStmt: result = lsub(g, n[0]) + len("continue_")
|
|
of nkPragma: result = lcomma(g, n) + 4
|
|
of nkCommentStmt: result = n.comment.len
|
|
of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
|
|
of nkImportAs: result = lsub(g, n[0]) + len("_as_") + lsub(g, n[1])
|
|
of nkElifBranch: result = lsons(g, n) + len("elif_:_")
|
|
of nkElse: result = lsub(g, n[0]) + len("else:_")
|
|
of nkFinally: result = lsub(g, n[0]) + len("finally:_")
|
|
of nkGenericParams: result = lcomma(g, n) + 2
|
|
of nkFormalParams:
|
|
result = lcomma(g, n, 1) + 2
|
|
if n[0].kind != nkEmpty: result += lsub(g, n[0]) + 2
|
|
of nkExceptBranch:
|
|
result = lcomma(g, n, 0, -2) + lsub(g, lastSon(n)) + len("except_:_")
|
|
of nkObjectTy:
|
|
result = len("object_")
|
|
else: result = MaxLineLen + 1
|
|
|
|
proc fits(g: TSrcGen, x: int): bool =
|
|
result = x <= MaxLineLen
|
|
|
|
type
|
|
TSubFlag = enum
|
|
rfLongMode, rfInConstExpr
|
|
TSubFlags = set[TSubFlag]
|
|
TContext = tuple[spacing: int, flags: TSubFlags]
|
|
|
|
const
|
|
emptyContext: TContext = (spacing: 0, flags: {})
|
|
|
|
proc initContext(): TContext =
|
|
result = (spacing: 0, flags: {})
|
|
|
|
proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false)
|
|
proc gsub(g: var TSrcGen, n: PNode, fromStmtList = false) =
|
|
var c: TContext = initContext()
|
|
gsub(g, n, c, fromStmtList = fromStmtList)
|
|
|
|
proc hasCom(n: PNode): bool =
|
|
result = false
|
|
if n.isNil: return false
|
|
if n.comment.len > 0: return true
|
|
case n.kind
|
|
of nkEmpty..nkNilLit: discard
|
|
else:
|
|
for i in 0..<n.len:
|
|
if hasCom(n[i]): return true
|
|
|
|
proc putWithSpace(g: var TSrcGen, kind: TokType, s: string) =
|
|
put(g, kind, s)
|
|
put(g, tkSpaces, Space)
|
|
|
|
proc isHideable(config: ConfigRef, n: PNode): bool =
|
|
# xxx compare `ident` directly with `getIdent(cache, wRaises)`, but
|
|
# this requires a `cache`.
|
|
case n.kind
|
|
of nkExprColonExpr:
|
|
result = n[0].kind == nkIdent and
|
|
n[0].ident.s.nimIdentNormalize in ["raises", "tags", "extern", "deprecated", "forbids", "stacktrace"]
|
|
of nkIdent: result = n.ident.s in ["gcsafe", "deprecated"]
|
|
else: result = false
|
|
|
|
proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
|
|
theEnd: int = - 1, separator = tkComma) =
|
|
let inPragma = g.inPragma == 1 # just the top-level
|
|
var inHideable = false
|
|
for i in start..n.len + theEnd:
|
|
let c = i < n.len + theEnd
|
|
let sublen = lsub(g, n[i]) + ord(c)
|
|
if not fits(g, g.lineLen + sublen) and (ind + sublen < MaxLineLen): optNL(g, ind)
|
|
let oldLen = g.tokens.len
|
|
if inPragma:
|
|
if not inHideable and isHideable(g.config, n[i]):
|
|
inHideable = true
|
|
put(g, tkHideableStart, "")
|
|
elif inHideable and not isHideable(g.config, n[i]):
|
|
inHideable = false
|
|
put(g, tkHideableEnd, "")
|
|
gsub(g, n[i])
|
|
if c:
|
|
if g.tokens.len > oldLen:
|
|
putWithSpace(g, separator, $separator)
|
|
if shouldRenderComment(g) and hasCom(n[i]):
|
|
gcoms(g)
|
|
optNL(g, ind)
|
|
if inHideable:
|
|
put(g, tkHideableEnd, "")
|
|
inHideable = false
|
|
|
|
proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
|
|
theEnd: int = -1) =
|
|
var ind: int
|
|
if rfInConstExpr in c.flags:
|
|
ind = g.indent + IndentWidth
|
|
else:
|
|
ind = g.lineLen
|
|
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
|
|
gcommaAux(g, n, ind, start, theEnd)
|
|
|
|
proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
|
|
var ind = g.lineLen
|
|
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
|
|
gcommaAux(g, n, ind, start, theEnd)
|
|
|
|
proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
|
|
var ind = g.lineLen
|
|
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
|
|
gcommaAux(g, n, ind, start, theEnd, tkSemiColon)
|
|
|
|
proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
|
|
theEnd: int = - 1) =
|
|
for i in start..n.len + theEnd: gsub(g, n[i], c)
|
|
|
|
proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TokType,
|
|
k: string) =
|
|
if n.len == 0: return # empty var sections are possible
|
|
putWithSpace(g, kind, k)
|
|
gcoms(g)
|
|
indentNL(g)
|
|
for i in 0..<n.len:
|
|
optNL(g)
|
|
gsub(g, n[i], c)
|
|
gcoms(g)
|
|
dedent(g)
|
|
|
|
proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool =
|
|
result = shouldRenderComment(g, n)
|
|
if not result:
|
|
# check further
|
|
for i in start..n.len + theEnd:
|
|
if (lsub(g, n[i]) > MaxLineLen):
|
|
result = true
|
|
break
|
|
|
|
proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
|
|
if n.kind == nkEmpty: return
|
|
if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
|
|
if doIndent: indentNL(g)
|
|
for i in 0..<n.len:
|
|
if i > 0:
|
|
optNL(g, n[i-1], n[i])
|
|
else:
|
|
optNL(g)
|
|
if n[i].kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
|
|
gstmts(g, n[i], c, doIndent=false)
|
|
else:
|
|
gsub(g, n[i], fromStmtList = true)
|
|
gcoms(g)
|
|
if doIndent: dedent(g)
|
|
else:
|
|
indentNL(g)
|
|
gsub(g, n)
|
|
gcoms(g)
|
|
dedent(g)
|
|
optNL(g)
|
|
|
|
|
|
proc gcond(g: var TSrcGen, n: PNode) =
|
|
if n.kind == nkStmtListExpr:
|
|
put(g, tkParLe, "(")
|
|
gsub(g, n)
|
|
if n.kind == nkStmtListExpr:
|
|
put(g, tkParRi, ")")
|
|
|
|
proc gif(g: var TSrcGen, n: PNode) =
|
|
var c: TContext = initContext()
|
|
gcond(g, n[0][0])
|
|
putWithSpace(g, tkColon, ":")
|
|
if longMode(g, n) or (lsub(g, n[0][1]) + g.lineLen > MaxLineLen):
|
|
incl(c.flags, rfLongMode)
|
|
gcoms(g) # a good place for comments
|
|
gstmts(g, n[0][1], c)
|
|
for i in 1..<n.len:
|
|
optNL(g)
|
|
gsub(g, n[i], c)
|
|
|
|
proc gwhile(g: var TSrcGen, n: PNode) =
|
|
var c: TContext = initContext()
|
|
putWithSpace(g, tkWhile, "while")
|
|
gcond(g, n[0])
|
|
putWithSpace(g, tkColon, ":")
|
|
if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
|
|
incl(c.flags, rfLongMode)
|
|
gcoms(g) # a good place for comments
|
|
gstmts(g, n[1], c)
|
|
|
|
proc gpattern(g: var TSrcGen, n: PNode) =
|
|
var c: TContext = initContext()
|
|
put(g, tkCurlyLe, "{")
|
|
if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
|
|
incl(c.flags, rfLongMode)
|
|
gcoms(g) # a good place for comments
|
|
gstmts(g, n, c)
|
|
put(g, tkCurlyRi, "}")
|
|
|
|
proc gpragmaBlock(g: var TSrcGen, n: PNode) =
|
|
var c: TContext = initContext()
|
|
gsub(g, n[0])
|
|
putWithSpace(g, tkColon, ":")
|
|
if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
|
|
incl(c.flags, rfLongMode)
|
|
gcoms(g) # a good place for comments
|
|
gstmts(g, n[1], c)
|
|
|
|
proc gtry(g: var TSrcGen, n: PNode) =
|
|
var c: TContext = initContext()
|
|
put(g, tkTry, "try")
|
|
putWithSpace(g, tkColon, ":")
|
|
if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
|
|
incl(c.flags, rfLongMode)
|
|
gcoms(g) # a good place for comments
|
|
gstmts(g, n[0], c)
|
|
gsons(g, n, c, 1)
|
|
|
|
proc gfor(g: var TSrcGen, n: PNode) =
|
|
var c: TContext = initContext()
|
|
putWithSpace(g, tkFor, "for")
|
|
if longMode(g, n) or
|
|
(lsub(g, n[^1]) + lsub(g, n[^2]) + 6 + g.lineLen > MaxLineLen):
|
|
incl(c.flags, rfLongMode)
|
|
gcomma(g, n, c, 0, - 3)
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkIn, "in")
|
|
gsub(g, n[^2], c)
|
|
putWithSpace(g, tkColon, ":")
|
|
gcoms(g)
|
|
gstmts(g, n[^1], c)
|
|
|
|
proc gcase(g: var TSrcGen, n: PNode) =
|
|
var c: TContext = initContext()
|
|
if n.len == 0: return
|
|
var last = if n[^1].kind == nkElse: -2 else: -1
|
|
if longMode(g, n, 0, last): incl(c.flags, rfLongMode)
|
|
putWithSpace(g, tkCase, "case")
|
|
gcond(g, n[0])
|
|
gcoms(g)
|
|
optNL(g)
|
|
gsons(g, n, c, 1, last)
|
|
if last == - 2:
|
|
c = initContext()
|
|
if longMode(g, n[^1]): incl(c.flags, rfLongMode)
|
|
gsub(g, n[^1], c)
|
|
|
|
proc genSymSuffix(result: var string, s: PSym) {.inline.} =
|
|
if sfGenSym in s.flags and s.name.id != ord(wUnderscore):
|
|
result.add '_'
|
|
result.addInt s.id
|
|
|
|
proc gproc(g: var TSrcGen, n: PNode) =
|
|
var c: TContext = initContext()
|
|
if n[namePos].kind == nkSym:
|
|
let s = n[namePos].sym
|
|
var ret = renderDefinitionName(s)
|
|
ret.genSymSuffix(s)
|
|
put(g, tkSymbol, ret)
|
|
else:
|
|
gsub(g, n[namePos])
|
|
|
|
if n[patternPos].kind != nkEmpty:
|
|
gpattern(g, n[patternPos])
|
|
g.inside(GenericParams):
|
|
if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
|
|
n[miscPos][1].kind != nkEmpty:
|
|
gsub(g, n[miscPos][1])
|
|
else:
|
|
gsub(g, n[genericParamsPos])
|
|
gsub(g, n[paramsPos])
|
|
if renderNoPragmas notin g.flags:
|
|
gsub(g, n[pragmasPos])
|
|
if renderNoBody notin g.flags:
|
|
if n.len > bodyPos and n[bodyPos].kind != nkEmpty:
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkEquals, "=")
|
|
indentNL(g)
|
|
gcoms(g)
|
|
dedent(g)
|
|
c = initContext()
|
|
gstmts(g, n[bodyPos], c)
|
|
putNL(g)
|
|
else:
|
|
indentNL(g)
|
|
gcoms(g)
|
|
dedent(g)
|
|
|
|
proc gTypeClassTy(g: var TSrcGen, n: PNode) =
|
|
var c: TContext = initContext()
|
|
putWithSpace(g, tkConcept, "concept")
|
|
gsons(g, n[0], c) # arglist
|
|
gsub(g, n[1]) # pragmas
|
|
gsub(g, n[2]) # of
|
|
gcoms(g)
|
|
indentNL(g)
|
|
gcoms(g)
|
|
gstmts(g, n[3], c)
|
|
dedent(g)
|
|
|
|
proc gblock(g: var TSrcGen, n: PNode) =
|
|
# you shouldn't simplify it to `n.len < 2`
|
|
# because the following codes should be executed
|
|
# even when block stmt has only one child for getting
|
|
# better error messages.
|
|
if n.len == 0:
|
|
return
|
|
|
|
var c: TContext = initContext()
|
|
|
|
if n[0].kind != nkEmpty:
|
|
putWithSpace(g, tkBlock, "block")
|
|
gsub(g, n[0])
|
|
else:
|
|
put(g, tkBlock, "block")
|
|
|
|
# block stmt should have two children
|
|
if n.len == 1:
|
|
return
|
|
|
|
putWithSpace(g, tkColon, ":")
|
|
|
|
if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
|
|
incl(c.flags, rfLongMode)
|
|
gcoms(g)
|
|
gstmts(g, n[1], c)
|
|
|
|
proc gstaticStmt(g: var TSrcGen, n: PNode) =
|
|
var c: TContext = initContext()
|
|
putWithSpace(g, tkStatic, "static")
|
|
putWithSpace(g, tkColon, ":")
|
|
if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
|
|
incl(c.flags, rfLongMode)
|
|
gcoms(g) # a good place for comments
|
|
gstmts(g, n[0], c)
|
|
|
|
proc gasm(g: var TSrcGen, n: PNode) =
|
|
putWithSpace(g, tkAsm, "asm")
|
|
gsub(g, n[0])
|
|
gcoms(g)
|
|
if n.len > 1:
|
|
gsub(g, n[1])
|
|
|
|
proc gident(g: var TSrcGen, n: PNode) =
|
|
if GenericParams in g.inside and n.kind == nkSym:
|
|
if sfAnon in n.sym.flags or
|
|
(n.typ != nil and tfImplicitTypeParam in n.typ.flags): return
|
|
|
|
var t: TokType
|
|
var s = atom(g, n)
|
|
if s.len > 0 and s[0] in lexer.SymChars:
|
|
if n.kind == nkIdent:
|
|
if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
|
|
(n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
|
|
t = tkSymbol
|
|
else:
|
|
t = TokType(n.ident.id + ord(tkSymbol))
|
|
else:
|
|
t = tkSymbol
|
|
else:
|
|
t = tkOpr
|
|
if renderIr in g.flags and n.kind == nkSym:
|
|
let localId = disamb(g, n.sym)
|
|
if localId != 0 and n.sym.magic == mNone:
|
|
s.add '_'
|
|
s.addInt localId
|
|
if sfCursor in n.sym.flags:
|
|
s.add "_cursor"
|
|
elif n.kind == nkSym and (renderIds in g.flags or
|
|
(sfGenSym in n.sym.flags and n.sym.name.id != ord(wUnderscore)) or
|
|
n.sym.kind == skTemp):
|
|
s.add '_'
|
|
s.addInt n.sym.id
|
|
when defined(debugMagics):
|
|
s.add '_'
|
|
s.add $n.sym.magic
|
|
put(g, t, s, if n.kind == nkSym and renderSyms in g.flags: n.sym else: nil)
|
|
|
|
proc doParamsAux(g: var TSrcGen, params: PNode) =
|
|
if params.len > 1:
|
|
put(g, tkParLe, "(")
|
|
gsemicolon(g, params, 1)
|
|
put(g, tkParRi, ")")
|
|
|
|
if params.len > 0 and params[0].kind != nkEmpty:
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkOpr, "->")
|
|
gsub(g, params[0])
|
|
|
|
proc gsub(g: var TSrcGen; n: PNode; i: int) =
|
|
if i < n.len:
|
|
gsub(g, n[i])
|
|
else:
|
|
put(g, tkOpr, "<<" & $i & "th child missing for " & $n.kind & " >>")
|
|
|
|
type
|
|
BracketKind = enum
|
|
bkNone, bkBracket, bkBracketAsgn, bkCurly, bkCurlyAsgn
|
|
|
|
proc bracketKind*(g: TSrcGen, n: PNode): BracketKind =
|
|
if renderIds notin g.flags:
|
|
case n.kind
|
|
of nkClosedSymChoice, nkOpenSymChoice:
|
|
if n.len > 0: result = bracketKind(g, n[0])
|
|
else: result = bkNone
|
|
of nkSym:
|
|
result = case n.sym.name.s
|
|
of "[]": bkBracket
|
|
of "[]=": bkBracketAsgn
|
|
of "{}": bkCurly
|
|
of "{}=": bkCurlyAsgn
|
|
else: bkNone
|
|
else: result = bkNone
|
|
else:
|
|
result = bkNone
|
|
|
|
proc skipHiddenNodes(n: PNode): PNode =
|
|
result = n
|
|
while result != nil:
|
|
if result.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv} and result.len > 1:
|
|
result = result[1]
|
|
elif result.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString} and
|
|
result.len > 0:
|
|
result = result[0]
|
|
else: break
|
|
|
|
proc accentedName(g: var TSrcGen, n: PNode) =
|
|
# This is for cases where ident should've really been a `nkAccQuoted`, e.g. `:tmp`
|
|
# or if user writes a macro with `ident":foo"`. It's unclear whether these should be legal.
|
|
const backticksNeeded = OpChars + {'[', '{', '\''}
|
|
if n == nil: return
|
|
let ident = n.getPIdent
|
|
if ident != nil and ident.s[0] in backticksNeeded:
|
|
put(g, tkAccent, "`")
|
|
gident(g, n)
|
|
put(g, tkAccent, "`")
|
|
else:
|
|
gsub(g, n)
|
|
|
|
proc infixArgument(g: var TSrcGen, n: PNode, i: int) =
|
|
if i < 1 or i > 2: return
|
|
var needsParenthesis = false
|
|
let nNext = n[i].skipHiddenNodes
|
|
if nNext.kind == nkInfix:
|
|
if nNext[0].kind in {nkSym, nkIdent} and n[0].kind in {nkSym, nkIdent}:
|
|
let nextId = if nNext[0].kind == nkSym: nNext[0].sym.name else: nNext[0].ident
|
|
let nnId = if n[0].kind == nkSym: n[0].sym.name else: n[0].ident
|
|
if i == 1:
|
|
if getPrecedence(nextId) < getPrecedence(nnId):
|
|
needsParenthesis = true
|
|
elif i == 2:
|
|
if getPrecedence(nextId) <= getPrecedence(nnId):
|
|
needsParenthesis = true
|
|
if needsParenthesis:
|
|
put(g, tkParLe, "(")
|
|
gsub(g, n, i)
|
|
if needsParenthesis:
|
|
put(g, tkParRi, ")")
|
|
|
|
const postExprBlocks = {nkStmtList, nkStmtListExpr,
|
|
nkOfBranch, nkElifBranch, nkElse,
|
|
nkExceptBranch, nkFinally, nkDo}
|
|
|
|
proc postStatements(g: var TSrcGen, n: PNode, i: int, fromStmtList: bool) =
|
|
var i = i
|
|
if n[i].kind in {nkStmtList, nkStmtListExpr}:
|
|
if fromStmtList:
|
|
put(g, tkColon, ":")
|
|
else:
|
|
put(g, tkSpaces, Space)
|
|
put(g, tkDo, "do")
|
|
put(g, tkColon, ":")
|
|
gsub(g, n, i)
|
|
i.inc
|
|
for j in i ..< n.len:
|
|
if n[j].kind == nkDo:
|
|
optNL(g)
|
|
elif n[j].kind in {nkStmtList, nkStmtListExpr}:
|
|
optNL(g)
|
|
put(g, tkDo, "do")
|
|
put(g, tkColon, ":")
|
|
gsub(g, n, j)
|
|
|
|
proc isCustomLit(n: PNode): bool =
|
|
if n.len == 2 and n[0].kind == nkRStrLit:
|
|
let ident = n[1].getPIdent
|
|
result = ident != nil and ident.s.startsWith('\'')
|
|
else:
|
|
result = false
|
|
|
|
proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
|
if isNil(n): return
|
|
var
|
|
a: TContext = default(TContext)
|
|
if shouldRenderComment(g, n): pushCom(g, n)
|
|
case n.kind # atoms:
|
|
of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n))
|
|
of nkEmpty: discard
|
|
of nkType: put(g, tkInvalid, atom(g, n))
|
|
of nkSym, nkIdent: gident(g, n)
|
|
of nkIntLit: put(g, tkIntLit, atom(g, n))
|
|
of nkInt8Lit: put(g, tkInt8Lit, atom(g, n))
|
|
of nkInt16Lit: put(g, tkInt16Lit, atom(g, n))
|
|
of nkInt32Lit: put(g, tkInt32Lit, atom(g, n))
|
|
of nkInt64Lit: put(g, tkInt64Lit, atom(g, n))
|
|
of nkUIntLit: put(g, tkUIntLit, atom(g, n))
|
|
of nkUInt8Lit: put(g, tkUInt8Lit, atom(g, n))
|
|
of nkUInt16Lit: put(g, tkUInt16Lit, atom(g, n))
|
|
of nkUInt32Lit: put(g, tkUInt32Lit, atom(g, n))
|
|
of nkUInt64Lit: put(g, tkUInt64Lit, atom(g, n))
|
|
of nkFloatLit: put(g, tkFloatLit, atom(g, n))
|
|
of nkFloat32Lit: put(g, tkFloat32Lit, atom(g, n))
|
|
of nkFloat64Lit: put(g, tkFloat64Lit, atom(g, n))
|
|
of nkFloat128Lit: put(g, tkFloat128Lit, atom(g, n))
|
|
of nkStrLit: put(g, tkStrLit, atom(g, n))
|
|
of nkRStrLit: put(g, tkRStrLit, atom(g, n))
|
|
of nkCharLit: put(g, tkCharLit, atom(g, n))
|
|
of nkNilLit: put(g, tkNil, atom(g, n)) # complex expressions
|
|
of nkCall, nkConv, nkDotCall, nkPattern, nkObjConstr:
|
|
if n.len > 1 and n.lastSon.kind in postExprBlocks:
|
|
accentedName(g, n[0])
|
|
var i = 1
|
|
while i < n.len and n[i].kind notin postExprBlocks: i.inc
|
|
if i > 1:
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n, 1, i - 1 - n.len)
|
|
put(g, tkParRi, ")")
|
|
postStatements(g, n, i, fromStmtList)
|
|
elif n.len >= 1:
|
|
case bracketKind(g, n[0])
|
|
of bkBracket:
|
|
gsub(g, n, 1)
|
|
put(g, tkBracketLe, "[")
|
|
gcomma(g, n, 2)
|
|
put(g, tkBracketRi, "]")
|
|
of bkBracketAsgn:
|
|
gsub(g, n, 1)
|
|
put(g, tkBracketLe, "[")
|
|
gcomma(g, n, 2, -2)
|
|
put(g, tkBracketRi, "]")
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkEquals, "=")
|
|
gsub(g, n, n.len - 1)
|
|
of bkCurly:
|
|
gsub(g, n, 1)
|
|
put(g, tkCurlyLe, "{")
|
|
gcomma(g, n, 2)
|
|
put(g, tkCurlyRi, "}")
|
|
of bkCurlyAsgn:
|
|
gsub(g, n, 1)
|
|
put(g, tkCurlyLe, "{")
|
|
gcomma(g, n, 2, -2)
|
|
put(g, tkCurlyRi, "}")
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkEquals, "=")
|
|
gsub(g, n, n.len - 1)
|
|
of bkNone:
|
|
accentedName(g, n[0])
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n, 1)
|
|
put(g, tkParRi, ")")
|
|
else:
|
|
put(g, tkParLe, "(")
|
|
put(g, tkParRi, ")")
|
|
of nkCallStrLit:
|
|
if n.len > 0: accentedName(g, n[0])
|
|
if n.len > 1 and n[1].kind == nkRStrLit:
|
|
put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
|
|
else:
|
|
gsub(g, n, 1)
|
|
of nkHiddenStdConv, nkHiddenSubConv:
|
|
if n.len >= 2:
|
|
when false:
|
|
# if {renderIds, renderIr} * g.flags != {}:
|
|
put(g, tkSymbol, "(conv)")
|
|
put(g, tkParLe, "(")
|
|
gsub(g, n[1])
|
|
put(g, tkParRi, ")")
|
|
else:
|
|
gsub(g, n[1])
|
|
else:
|
|
put(g, tkSymbol, "(wrong conv)")
|
|
of nkHiddenCallConv:
|
|
if {renderIds, renderIr} * g.flags != {}:
|
|
accentedName(g, n[0])
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n, 1)
|
|
put(g, tkParRi, ")")
|
|
elif n.len >= 2:
|
|
gsub(g, n[1])
|
|
else:
|
|
put(g, tkSymbol, "(wrong conv)")
|
|
of nkCast:
|
|
put(g, tkCast, "cast")
|
|
if n.len > 0 and n[0].kind != nkEmpty:
|
|
put(g, tkBracketLe, "[")
|
|
gsub(g, n, 0)
|
|
put(g, tkBracketRi, "]")
|
|
put(g, tkParLe, "(")
|
|
gsub(g, n, 1)
|
|
put(g, tkParRi, ")")
|
|
of nkAddr:
|
|
put(g, tkAddr, "addr")
|
|
if n.len > 0:
|
|
put(g, tkParLe, "(")
|
|
gsub(g, n[0])
|
|
put(g, tkParRi, ")")
|
|
of nkStaticExpr:
|
|
put(g, tkStatic, "static")
|
|
put(g, tkSpaces, Space)
|
|
gsub(g, n, 0)
|
|
of nkBracketExpr:
|
|
gsub(g, n, 0)
|
|
put(g, tkBracketLe, "[")
|
|
gcomma(g, n, 1)
|
|
put(g, tkBracketRi, "]")
|
|
of nkCurlyExpr:
|
|
gsub(g, n, 0)
|
|
put(g, tkCurlyLe, "{")
|
|
gcomma(g, n, 1)
|
|
put(g, tkCurlyRi, "}")
|
|
of nkPragmaExpr:
|
|
gsub(g, n, 0)
|
|
gcomma(g, n, 1)
|
|
of nkCommand:
|
|
accentedName(g, n[0])
|
|
put(g, tkSpaces, Space)
|
|
if n.len > 1 and n.lastSon.kind in postExprBlocks:
|
|
var i = 1
|
|
while i < n.len and n[i].kind notin postExprBlocks: i.inc
|
|
if i > 1:
|
|
gcomma(g, n, 1, i - 1 - n.len)
|
|
postStatements(g, n, i, fromStmtList)
|
|
else:
|
|
gcomma(g, n, 1)
|
|
of nkExprEqExpr, nkAsgn, nkFastAsgn:
|
|
gsub(g, n, 0)
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkEquals, "=")
|
|
gsub(g, n, 1)
|
|
of nkSinkAsgn:
|
|
put(g, tkSymbol, "`=sink`")
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n)
|
|
put(g, tkParRi, ")")
|
|
of nkChckRangeF:
|
|
put(g, tkSymbol, "chckRangeF")
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n)
|
|
put(g, tkParRi, ")")
|
|
of nkChckRange64:
|
|
put(g, tkSymbol, "chckRange64")
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n)
|
|
put(g, tkParRi, ")")
|
|
of nkChckRange:
|
|
put(g, tkSymbol, "chckRange")
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n)
|
|
put(g, tkParRi, ")")
|
|
of nkObjDownConv, nkObjUpConv:
|
|
let typ = if (n.typ != nil) and (n.typ.sym != nil): n.typ.sym.name.s else: ""
|
|
put(g, tkParLe, typ & "(")
|
|
if n.len >= 1: gsub(g, n[0])
|
|
put(g, tkParRi, ")")
|
|
of nkClosedSymChoice, nkOpenSymChoice:
|
|
if renderIds in g.flags:
|
|
put(g, tkParLe, "(")
|
|
for i in 0..<n.len:
|
|
if i > 0: put(g, tkOpr, "|")
|
|
if n[i].kind == nkSym:
|
|
let s = n[i].sym
|
|
if s.owner != nil:
|
|
put g, tkSymbol, n[i].sym.owner.name.s
|
|
put g, tkOpr, "."
|
|
put g, tkSymbol, n[i].sym.name.s
|
|
else:
|
|
gsub(g, n[i], c)
|
|
put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
|
|
else:
|
|
gsub(g, n, 0)
|
|
of nkPar, nkClosure:
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n, c)
|
|
put(g, tkParRi, ")")
|
|
of nkTupleConstr:
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n, c)
|
|
if n.len == 1 and n[0].kind != nkExprColonExpr: put(g, tkComma, ",")
|
|
put(g, tkParRi, ")")
|
|
of nkCurly:
|
|
put(g, tkCurlyLe, "{")
|
|
gcomma(g, n, c)
|
|
put(g, tkCurlyRi, "}")
|
|
of nkArgList:
|
|
gcomma(g, n, c)
|
|
of nkTableConstr:
|
|
put(g, tkCurlyLe, "{")
|
|
if n.len > 0: gcomma(g, n, c)
|
|
else: put(g, tkColon, ":")
|
|
put(g, tkCurlyRi, "}")
|
|
of nkBracket:
|
|
put(g, tkBracketLe, "[")
|
|
gcomma(g, n, c)
|
|
put(g, tkBracketRi, "]")
|
|
of nkDotExpr:
|
|
if isCustomLit(n):
|
|
put(g, tkCustomLit, n[0].strVal)
|
|
gsub(g, n, 1)
|
|
else:
|
|
gsub(g, n, 0)
|
|
put(g, tkDot, ".")
|
|
assert n.len == 2, $n.len
|
|
accentedName(g, n[1])
|
|
of nkBind:
|
|
putWithSpace(g, tkBind, "bind")
|
|
gsub(g, n, 0)
|
|
of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString:
|
|
if renderIds in g.flags:
|
|
put(g, tkAddr, $n.kind)
|
|
put(g, tkParLe, "(")
|
|
gsub(g, n, 0)
|
|
if renderIds in g.flags:
|
|
put(g, tkParRi, ")")
|
|
|
|
of nkLambda:
|
|
putWithSpace(g, tkProc, "proc")
|
|
gsub(g, n, paramsPos)
|
|
gsub(g, n, pragmasPos)
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkEquals, "=")
|
|
gsub(g, n, bodyPos)
|
|
of nkDo:
|
|
putWithSpace(g, tkDo, "do")
|
|
if paramsPos < n.len:
|
|
doParamsAux(g, n[paramsPos])
|
|
gsub(g, n, pragmasPos)
|
|
put(g, tkColon, ":")
|
|
gsub(g, n, bodyPos)
|
|
of nkIdentDefs:
|
|
# Skip if this is a property in a type and its not exported
|
|
# (While also not allowing rendering of non exported fields)
|
|
if ObjectDef in g.inside and (not n[0].isExported() and renderNonExportedFields notin g.flags):
|
|
return
|
|
# We render the identDef without being inside the section incase we render something like
|
|
# y: proc (x: string) # (We wouldn't want to check if x is exported)
|
|
g.outside(ObjectDef):
|
|
gcomma(g, n, 0, -3)
|
|
if n.len >= 2 and n[^2].kind != nkEmpty:
|
|
putWithSpace(g, tkColon, ":")
|
|
gsub(g, n[^2], c)
|
|
elif n.referencesUsing and renderExpandUsing in g.flags:
|
|
putWithSpace(g, tkColon, ":")
|
|
gsub(g, newSymNode(n.origUsingType), c)
|
|
|
|
if n.len >= 1 and n[^1].kind != nkEmpty:
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkEquals, "=")
|
|
gsub(g, n[^1], c)
|
|
of nkConstDef:
|
|
gcomma(g, n, 0, -3)
|
|
if n.len >= 2 and n[^2].kind != nkEmpty:
|
|
putWithSpace(g, tkColon, ":")
|
|
gsub(g, n[^2], c)
|
|
|
|
if n.len >= 1 and n[^1].kind != nkEmpty:
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkEquals, "=")
|
|
gsub(g, n[^1], c)
|
|
of nkVarTuple:
|
|
if n[^1].kind == nkEmpty:
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n, 0, -2)
|
|
put(g, tkParRi, ")")
|
|
else:
|
|
put(g, tkParLe, "(")
|
|
gcomma(g, n, 0, -3)
|
|
put(g, tkParRi, ")")
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkEquals, "=")
|
|
gsub(g, lastSon(n), c)
|
|
of nkExprColonExpr:
|
|
gsub(g, n, 0)
|
|
putWithSpace(g, tkColon, ":")
|
|
gsub(g, n, 1)
|
|
of nkInfix:
|
|
if n.len < 3:
|
|
var i = 0
|
|
put(g, tkOpr, "Too few children for nkInfix")
|
|
return
|
|
let oldLineLen = g.lineLen # we cache this because lineLen gets updated below
|
|
infixArgument(g, n, 1)
|
|
put(g, tkSpaces, Space)
|
|
gsub(g, n, 0) # binary operator
|
|
# e.g.: `n1 == n2` decompses as following sum:
|
|
if n.len == 3 and not fits(g, oldLineLen + lsub(g, n[1]) + lsub(g, n[2]) + lsub(g, n[0]) + len(" ")):
|
|
optNL(g, g.indent + longIndentWid)
|
|
else:
|
|
put(g, tkSpaces, Space)
|
|
infixArgument(g, n, 2)
|
|
if n.len > 3 and n.lastSon.kind in postExprBlocks:
|
|
var i = 3
|
|
while i < n.len and n[i].kind notin postExprBlocks: i.inc
|
|
postStatements(g, n, i, fromStmtList)
|
|
of nkPrefix:
|
|
gsub(g, n, 0)
|
|
if n.len > 1:
|
|
let opr = if n[0].kind == nkIdent: n[0].ident
|
|
elif n[0].kind == nkSym: n[0].sym.name
|
|
elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
|
|
else: nil
|
|
let nNext = skipHiddenNodes(n[1])
|
|
if nNext.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
|
|
put(g, tkSpaces, Space)
|
|
if nNext.kind == nkInfix:
|
|
put(g, tkParLe, "(")
|
|
gsub(g, n[1])
|
|
put(g, tkParRi, ")")
|
|
else:
|
|
gsub(g, n[1])
|
|
if n.len > 2 and n.lastSon.kind in postExprBlocks:
|
|
var i = 2
|
|
while i < n.len and n[i].kind notin postExprBlocks: i.inc
|
|
postStatements(g, n, i, fromStmtList)
|
|
of nkPostfix:
|
|
gsub(g, n, 1)
|
|
gsub(g, n, 0)
|
|
of nkRange:
|
|
gsub(g, n, 0)
|
|
put(g, tkDotDot, "..")
|
|
gsub(g, n, 1)
|
|
of nkDerefExpr:
|
|
gsub(g, n, 0)
|
|
put(g, tkOpr, "[]")
|
|
of nkAccQuoted:
|
|
put(g, tkAccent, "`")
|
|
for i in 0..<n.len:
|
|
proc isAlpha(n: PNode): bool =
|
|
if n.kind in {nkIdent, nkSym}:
|
|
let tmp = n.getPIdent.s
|
|
result = tmp.len > 0 and tmp[0] in {'a'..'z', 'A'..'Z'}
|
|
else:
|
|
result = false
|
|
var useSpace = false
|
|
if i == 1 and n[0].kind == nkIdent and n[0].ident.s in ["=", "'"]:
|
|
if not n[1].isAlpha: # handle `=destroy`, `'big'
|
|
useSpace = true
|
|
elif i == 1 and n[1].kind == nkIdent and n[1].ident.s == "=":
|
|
if not n[0].isAlpha: # handle setters, e.g. `foo=`
|
|
useSpace = true
|
|
elif i > 0: useSpace = true
|
|
if useSpace: put(g, tkSpaces, Space)
|
|
gsub(g, n[i])
|
|
put(g, tkAccent, "`")
|
|
of nkIfExpr:
|
|
putWithSpace(g, tkIf, "if")
|
|
if n.len > 0: gcond(g, n[0][0])
|
|
putWithSpace(g, tkColon, ":")
|
|
if n.len > 0: gsub(g, n[0], 1)
|
|
gsons(g, n, emptyContext, 1)
|
|
of nkElifExpr:
|
|
putWithSpace(g, tkElif, " elif")
|
|
gcond(g, n[0])
|
|
putWithSpace(g, tkColon, ":")
|
|
gsub(g, n, 1)
|
|
of nkElseExpr:
|
|
put(g, tkElse, " else")
|
|
putWithSpace(g, tkColon, ":")
|
|
gsub(g, n, 0)
|
|
of nkTypeOfExpr:
|
|
put(g, tkType, "typeof")
|
|
put(g, tkParLe, "(")
|
|
if n.len > 0: gsub(g, n[0])
|
|
put(g, tkParRi, ")")
|
|
of nkRefTy:
|
|
if n.len > 0:
|
|
putWithSpace(g, tkRef, "ref")
|
|
gsub(g, n[0])
|
|
else:
|
|
put(g, tkRef, "ref")
|
|
of nkPtrTy:
|
|
if n.len > 0:
|
|
putWithSpace(g, tkPtr, "ptr")
|
|
gsub(g, n[0])
|
|
else:
|
|
put(g, tkPtr, "ptr")
|
|
of nkVarTy:
|
|
if n.len > 0:
|
|
putWithSpace(g, tkVar, "var")
|
|
gsub(g, n[0])
|
|
else:
|
|
put(g, tkVar, "var")
|
|
of nkOutTy:
|
|
if n.len > 0:
|
|
putWithSpace(g, tkOut, "out")
|
|
gsub(g, n[0])
|
|
else:
|
|
put(g, tkOut, "out")
|
|
of nkDistinctTy:
|
|
if n.len > 0:
|
|
putWithSpace(g, tkDistinct, "distinct")
|
|
gsub(g, n[0])
|
|
if n.len > 1:
|
|
if n[1].kind == nkWith:
|
|
putWithSpace(g, tkSymbol, " with")
|
|
else:
|
|
putWithSpace(g, tkSymbol, " without")
|
|
gcomma(g, n[1])
|
|
else:
|
|
put(g, tkDistinct, "distinct")
|
|
of nkTypeDef:
|
|
if n[0].kind == nkPragmaExpr:
|
|
# generate pragma after generic
|
|
gsub(g, n[0], 0)
|
|
gsub(g, n, 1)
|
|
gsub(g, n[0], 1)
|
|
else:
|
|
gsub(g, n, 0)
|
|
gsub(g, n, 1)
|
|
put(g, tkSpaces, Space)
|
|
if n.len > 2 and n[2].kind != nkEmpty:
|
|
putWithSpace(g, tkEquals, "=")
|
|
gsub(g, n[2])
|
|
of nkObjectTy:
|
|
if n.len > 0:
|
|
putWithSpace(g, tkObject, "object")
|
|
g.inside(ObjectDef):
|
|
gsub(g, n[0])
|
|
gsub(g, n[1])
|
|
gcoms(g)
|
|
gsub(g, n[2])
|
|
else:
|
|
put(g, tkObject, "object")
|
|
of nkRecList:
|
|
indentNL(g)
|
|
for i in 0..<n.len:
|
|
optNL(g)
|
|
gsub(g, n[i], c)
|
|
gcoms(g)
|
|
dedent(g)
|
|
putNL(g)
|
|
of nkOfInherit:
|
|
putWithSpace(g, tkOf, "of")
|
|
gsub(g, n, 0)
|
|
of nkProcTy:
|
|
if n.len > 0:
|
|
putWithSpace(g, tkProc, "proc")
|
|
gsub(g, n, 0)
|
|
gsub(g, n, 1)
|
|
else:
|
|
put(g, tkProc, "proc")
|
|
of nkIteratorTy:
|
|
if n.len > 0:
|
|
putWithSpace(g, tkIterator, "iterator")
|
|
gsub(g, n, 0)
|
|
gsub(g, n, 1)
|
|
else:
|
|
put(g, tkIterator, "iterator")
|
|
of nkStaticTy:
|
|
put(g, tkStatic, "static")
|
|
put(g, tkBracketLe, "[")
|
|
if n.len > 0:
|
|
gsub(g, n[0])
|
|
put(g, tkBracketRi, "]")
|
|
of nkEnumTy:
|
|
if n.len > 0:
|
|
putWithSpace(g, tkEnum, "enum")
|
|
gsub(g, n[0])
|
|
gcoms(g)
|
|
indentNL(g)
|
|
gcommaAux(g, n, g.indent, 1)
|
|
gcoms(g) # BUGFIX: comment for the last enum field
|
|
dedent(g)
|
|
else:
|
|
put(g, tkEnum, "enum")
|
|
of nkEnumFieldDef:
|
|
gsub(g, n, 0)
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkEquals, "=")
|
|
gsub(g, n, 1)
|
|
of nkStmtList, nkStmtListExpr, nkStmtListType:
|
|
if n.len == 1 and n[0].kind == nkDiscardStmt:
|
|
put(g, tkParLe, "(")
|
|
gsub(g, n[0])
|
|
put(g, tkParRi, ")")
|
|
else:
|
|
gstmts(g, n, emptyContext)
|
|
of nkIfStmt:
|
|
putWithSpace(g, tkIf, "if")
|
|
gif(g, n)
|
|
of nkWhen, nkRecWhen:
|
|
putWithSpace(g, tkWhen, "when")
|
|
gif(g, n)
|
|
of nkWhileStmt: gwhile(g, n)
|
|
of nkPragmaBlock: gpragmaBlock(g, n)
|
|
of nkCaseStmt, nkRecCase: gcase(g, n)
|
|
of nkTryStmt, nkHiddenTryStmt: gtry(g, n)
|
|
of nkForStmt, nkParForStmt: gfor(g, n)
|
|
of nkBlockStmt, nkBlockExpr: gblock(g, n)
|
|
of nkStaticStmt: gstaticStmt(g, n)
|
|
of nkAsmStmt: gasm(g, n)
|
|
of nkProcDef:
|
|
if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
|
|
gproc(g, n)
|
|
of nkFuncDef:
|
|
if renderNoProcDefs notin g.flags: putWithSpace(g, tkFunc, "func")
|
|
gproc(g, n)
|
|
of nkConverterDef:
|
|
if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
|
|
gproc(g, n)
|
|
of nkMethodDef:
|
|
if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method")
|
|
gproc(g, n)
|
|
of nkIteratorDef:
|
|
if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator")
|
|
gproc(g, n)
|
|
of nkMacroDef:
|
|
if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro")
|
|
gproc(g, n)
|
|
of nkTemplateDef:
|
|
if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template")
|
|
gproc(g, n)
|
|
of nkTypeSection:
|
|
gsection(g, n, emptyContext, tkType, "type")
|
|
of nkConstSection:
|
|
a = initContext()
|
|
incl(a.flags, rfInConstExpr)
|
|
gsection(g, n, a, tkConst, "const")
|
|
of nkVarSection, nkLetSection, nkUsingStmt:
|
|
if n.len == 0: return
|
|
if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
|
|
elif n.kind == nkLetSection: putWithSpace(g, tkLet, "let")
|
|
else: putWithSpace(g, tkUsing, "using")
|
|
if n.len > 1:
|
|
gcoms(g)
|
|
indentNL(g)
|
|
for i in 0..<n.len:
|
|
optNL(g)
|
|
gsub(g, n[i])
|
|
gcoms(g)
|
|
dedent(g)
|
|
else:
|
|
gsub(g, n[0])
|
|
of nkReturnStmt:
|
|
putWithSpace(g, tkReturn, "return")
|
|
if n.len > 0 and n[0].kind == nkAsgn and renderIr notin g.flags:
|
|
gsub(g, n[0], 1)
|
|
else:
|
|
gsub(g, n, 0)
|
|
of nkRaiseStmt:
|
|
putWithSpace(g, tkRaise, "raise")
|
|
gsub(g, n, 0)
|
|
of nkYieldStmt:
|
|
putWithSpace(g, tkYield, "yield")
|
|
gsub(g, n, 0)
|
|
of nkDiscardStmt:
|
|
putWithSpace(g, tkDiscard, "discard")
|
|
gsub(g, n, 0)
|
|
of nkBreakStmt:
|
|
putWithSpace(g, tkBreak, "break")
|
|
gsub(g, n, 0)
|
|
of nkContinueStmt:
|
|
putWithSpace(g, tkContinue, "continue")
|
|
gsub(g, n, 0)
|
|
of nkPragma:
|
|
if g.inPragma <= 0:
|
|
inc g.inPragma
|
|
#if not previousNL(g):
|
|
put(g, tkSpaces, Space)
|
|
put(g, tkCurlyDotLe, "{.")
|
|
gcomma(g, n, emptyContext)
|
|
put(g, tkCurlyDotRi, ".}")
|
|
dec g.inPragma
|
|
else:
|
|
gcomma(g, n, emptyContext)
|
|
of nkImportStmt, nkExportStmt:
|
|
if n.kind == nkImportStmt:
|
|
putWithSpace(g, tkImport, "import")
|
|
else:
|
|
putWithSpace(g, tkExport, "export")
|
|
gcoms(g)
|
|
indentNL(g)
|
|
gcommaAux(g, n, g.indent)
|
|
dedent(g)
|
|
putNL(g)
|
|
of nkImportExceptStmt, nkExportExceptStmt:
|
|
if n.kind == nkImportExceptStmt:
|
|
putWithSpace(g, tkImport, "import")
|
|
else:
|
|
putWithSpace(g, tkExport, "export")
|
|
gsub(g, n, 0)
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkExcept, "except")
|
|
gcommaAux(g, n, g.indent, 1)
|
|
gcoms(g)
|
|
putNL(g)
|
|
of nkFromStmt:
|
|
putWithSpace(g, tkFrom, "from")
|
|
gsub(g, n, 0)
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkImport, "import")
|
|
gcomma(g, n, emptyContext, 1)
|
|
putNL(g)
|
|
of nkIncludeStmt:
|
|
putWithSpace(g, tkInclude, "include")
|
|
gcoms(g)
|
|
indentNL(g)
|
|
gcommaAux(g, n, g.indent)
|
|
dedent(g)
|
|
putNL(g)
|
|
of nkCommentStmt:
|
|
gcoms(g)
|
|
optNL(g)
|
|
of nkOfBranch:
|
|
optNL(g)
|
|
putWithSpace(g, tkOf, "of")
|
|
gcomma(g, n, c, 0, - 2)
|
|
putWithSpace(g, tkColon, ":")
|
|
gcoms(g)
|
|
gstmts(g, lastSon(n), c)
|
|
of nkImportAs:
|
|
gsub(g, n, 0)
|
|
put(g, tkSpaces, Space)
|
|
putWithSpace(g, tkAs, "as")
|
|
gsub(g, n, 1)
|
|
of nkBindStmt:
|
|
putWithSpace(g, tkBind, "bind")
|
|
gcomma(g, n, c)
|
|
of nkMixinStmt:
|
|
putWithSpace(g, tkMixin, "mixin")
|
|
gcomma(g, n, c)
|
|
of nkElifBranch:
|
|
optNL(g)
|
|
putWithSpace(g, tkElif, "elif")
|
|
gsub(g, n, 0)
|
|
putWithSpace(g, tkColon, ":")
|
|
gcoms(g)
|
|
gstmts(g, n[1], c)
|
|
of nkElse:
|
|
optNL(g)
|
|
put(g, tkElse, "else")
|
|
putWithSpace(g, tkColon, ":")
|
|
gcoms(g)
|
|
gstmts(g, n[0], c)
|
|
of nkFinally, nkDefer:
|
|
optNL(g)
|
|
if n.kind == nkFinally:
|
|
put(g, tkFinally, "finally")
|
|
else:
|
|
put(g, tkDefer, "defer")
|
|
putWithSpace(g, tkColon, ":")
|
|
gcoms(g)
|
|
gstmts(g, n[0], c)
|
|
of nkExceptBranch:
|
|
optNL(g)
|
|
if n.len != 1:
|
|
putWithSpace(g, tkExcept, "except")
|
|
else:
|
|
put(g, tkExcept, "except")
|
|
gcomma(g, n, 0, -2)
|
|
putWithSpace(g, tkColon, ":")
|
|
gcoms(g)
|
|
gstmts(g, lastSon(n), c)
|
|
of nkGenericParams:
|
|
proc hasExplicitParams(gp: PNode): bool =
|
|
for p in gp:
|
|
if p.typ == nil or tfImplicitTypeParam notin p.typ.flags:
|
|
return true
|
|
return false
|
|
|
|
if n.hasExplicitParams:
|
|
put(g, tkBracketLe, "[")
|
|
gsemicolon(g, n)
|
|
put(g, tkBracketRi, "]")
|
|
of nkFormalParams:
|
|
put(g, tkParLe, "(")
|
|
gsemicolon(g, n, 1)
|
|
put(g, tkParRi, ")")
|
|
if n.len > 0 and n[0].kind != nkEmpty:
|
|
putWithSpace(g, tkColon, ":")
|
|
gsub(g, n[0])
|
|
of nkTupleTy:
|
|
put(g, tkTuple, "tuple")
|
|
put(g, tkBracketLe, "[")
|
|
gcomma(g, n)
|
|
put(g, tkBracketRi, "]")
|
|
of nkTupleClassTy:
|
|
put(g, tkTuple, "tuple")
|
|
of nkComesFrom:
|
|
put(g, tkParLe, "(ComesFrom|")
|
|
gsub(g, n, 0)
|
|
put(g, tkParRi, ")")
|
|
of nkGotoState:
|
|
var c: TContext = initContext()
|
|
putWithSpace g, tkSymbol, "goto"
|
|
gsons(g, n, c)
|
|
of nkState:
|
|
var c: TContext = initContext()
|
|
putWithSpace g, tkSymbol, "state"
|
|
gsub(g, n[0], c)
|
|
putWithSpace(g, tkColon, ":")
|
|
indentNL(g)
|
|
gsons(g, n, c, 1)
|
|
dedent(g)
|
|
|
|
of nkBreakState:
|
|
put(g, tkTuple, "breakstate")
|
|
if renderIds in g.flags:
|
|
gsons(g, n, c, 0)
|
|
of nkTypeClassTy:
|
|
gTypeClassTy(g, n)
|
|
of nkError:
|
|
putWithSpace(g, tkSymbol, "error")
|
|
#gcomma(g, n, c)
|
|
gsub(g, n[0], c)
|
|
else:
|
|
#nkNone, nkExplicitTypeListCall:
|
|
internalError(g.config, n.info, "renderer.gsub(" & $n.kind & ')')
|
|
|
|
proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string =
|
|
if n == nil: return "<nil tree>"
|
|
var g: TSrcGen = initSrcGen(renderFlags, newPartialConfigRef())
|
|
# do not indent the initial statement list so that
|
|
# writeFile("file.nim", repr n)
|
|
# produces working Nim code:
|
|
if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
|
|
gstmts(g, n, emptyContext, doIndent = false)
|
|
else:
|
|
gsub(g, n)
|
|
result = g.buf
|
|
|
|
proc `$`*(n: PNode): string = n.renderTree
|
|
|
|
proc renderModule*(n: PNode, outfile: string,
|
|
renderFlags: TRenderFlags = {};
|
|
fid = FileIndex(-1);
|
|
conf: ConfigRef = nil) =
|
|
var
|
|
f: File = default(File)
|
|
g: TSrcGen = initSrcGen(renderFlags, conf)
|
|
g.fid = fid
|
|
for i in 0..<n.len:
|
|
gsub(g, n[i])
|
|
optNL(g)
|
|
case n[i].kind
|
|
of nkTypeSection, nkConstSection, nkVarSection, nkLetSection,
|
|
nkCommentStmt: putNL(g)
|
|
else: discard
|
|
gcoms(g)
|
|
if open(f, outfile, fmWrite):
|
|
write(f, g.buf)
|
|
close(f)
|
|
else:
|
|
rawMessage(g.config, errGenerated, "cannot open file: " & outfile)
|
|
|
|
proc initTokRender*(n: PNode, renderFlags: TRenderFlags = {}): TSrcGen =
|
|
result = initSrcGen(renderFlags, newPartialConfigRef())
|
|
gsub(result, n)
|
|
|
|
proc getNextTok*(r: var TSrcGen, kind: var TokType, literal: var string) =
|
|
if r.idx < r.tokens.len:
|
|
kind = r.tokens[r.idx].kind
|
|
let length = r.tokens[r.idx].length.int
|
|
literal = substr(r.buf, r.pos, r.pos + length - 1)
|
|
inc(r.pos, length)
|
|
inc(r.idx)
|
|
else:
|
|
kind = tkEof
|
|
|
|
proc getTokSym*(r: TSrcGen): PSym =
|
|
if r.idx > 0 and r.idx <= r.tokens.len:
|
|
result = r.tokens[r.idx-1].sym
|
|
else:
|
|
result = nil
|