diff options
author | Andreas Rumpf <andreas@andreas-desktop> | 2009-12-07 01:23:19 +0100 |
---|---|---|
committer | Andreas Rumpf <andreas@andreas-desktop> | 2009-12-07 01:23:19 +0100 |
commit | e254741541b0389dfb0b675116c76a6a144b90b7 (patch) | |
tree | c6769c04b3bdc6a77bcc5075b0df011252e3702b /rod/rnimsyn.nim | |
parent | 90119066adf6a9a2e8d779d4955637c6dd99aba3 (diff) | |
download | Nim-e254741541b0389dfb0b675116c76a6a144b90b7.tar.gz |
version 0.8.5: added Nimrod version of the compiler
Diffstat (limited to 'rod/rnimsyn.nim')
-rwxr-xr-x | rod/rnimsyn.nim | 1194 |
1 files changed, 1194 insertions, 0 deletions
diff --git a/rod/rnimsyn.nim b/rod/rnimsyn.nim new file mode 100755 index 000000000..c7f8ea11f --- /dev/null +++ b/rod/rnimsyn.nim @@ -0,0 +1,1194 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2009 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# This module implements the renderer of the standard Nimrod representation. + +import + scanner, options, idents, strutils, ast, msgs, lists + +type + TRenderFlag* = enum + renderNone, renderNoBody, renderNoComments, renderDocComments, + renderNoPragmas, renderIds + TRenderFlags* = set[TRenderFlag] + TRenderTok*{.final.} = object + kind*: TTokType + length*: int16 + + TRenderTokSeq* = seq[TRenderTok] + TSrcGen*{.final.} = object + indent*: int + lineLen*: 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 + comStack*: seq[PNode] # comment stack + flags*: TRenderFlags + + +proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {}) +proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string +proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) +proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) +# implementation +# 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. + +const + IndentWidth = 2 + longIndentWid = 4 + MaxLineLen = 80 + LineCommentColumn = 30 + +proc InitSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = + g.comStack = @ [] + g.tokens = @ [] + g.indent = 0 + g.lineLen = 0 + g.pos = 0 + g.idx = 0 + g.buf = "" + g.flags = renderFlags + g.pendingNL = - 1 + +proc addTok(g: var TSrcGen, kind: TTokType, s: string) = + var length: int + length = len(g.tokens) + setlen(g.tokens, length + 1) + g.tokens[length].kind = kind + g.tokens[length].length = int16(len(s)) + add(g.buf, s) + +proc addPendingNL(g: var TSrcGen) = + if g.pendingNL >= 0: + addTok(g, tkInd, "\n" & repeatChar(g.pendingNL)) + g.lineLen = g.pendingNL + g.pendingNL = - 1 + +proc putNL(g: var TSrcGen, indent: int) = + if g.pendingNL >= 0: addPendingNL(g) + else: addTok(g, tkInd, "\n") + g.pendingNL = indent + g.lineLen = indent + +proc putNL(g: var TSrcGen) = + putNL(g, g.indent) + +proc optNL(g: var TSrcGen, indent: int) = + g.pendingNL = indent + g.lineLen = indent # BUGFIX + +proc optNL(g: var TSrcGen) = + optNL(g, g.indent) + +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: TTokType, s: string) = + addPendingNL(g) + if len(s) > 0: + addTok(g, kind, s) + inc(g.lineLen, len(s)) + +proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) = + # use this for tokens over multiple lines. + addPendingNL(g) + addTok(g, kind, s) + g.lineLen = lineLen + +proc toNimChar(c: Char): string = + case c + of '\0': result = "\\0" + of '\x01'..'\x1F', '\x80'..'\xFF': result = "\\x" & strutils.toHex(ord(c), 2) + of '\'', '\"', '\\': result = '\\' & c + else: result = c & "" + +proc makeNimString(s: string): string = + result = "\"" + for i in countup(0, len(s) + 0 - 1): add(result, toNimChar(s[i])) + add(result, '\"') + +proc putComment(g: var TSrcGen, s: string) = + var + i, j, ind, comIndent: int + isCode: bool + com: string + i = 0 + comIndent = 1 + isCode = (len(s) >= 2) and (s[0 + 1] != ' ') + ind = g.lineLen + com = "" + while true: + case s[i] + of '\0': + break + of '\x0D': + put(g, tkComment, com) + com = "" + inc(i) + if s[i] == '\x0A': inc(i) + optNL(g, ind) + of '\x0A': + put(g, tkComment, com) + com = "" + inc(i) + optNL(g, ind) + of '#': + add(com, s[i]) + inc(i) + comIndent = 0 + while s[i] == ' ': + add(com, s[i]) + inc(i) + inc(comIndent) + of ' ', '\x09': + add(com, 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: + j = i + while s[j] > ' ': inc(j) + if not isCode and (g.lineLen + (j - i) > MaxLineLen): + put(g, tkComment, com) + com = "" + optNL(g, ind) + com = com & '#' & repeatChar(comIndent) + while s[i] > ' ': + add(com, s[i]) + inc(i) + put(g, tkComment, com) + optNL(g) + +proc maxLineLength(s: string): int = + var i, linelen: int + result = 0 + i = 0 + lineLen = 0 + while true: + case s[i] + of '\0': + break + of '\x0D': + inc(i) + if s[i] == '\x0A': inc(i) + result = max(result, lineLen) + lineLen = 0 + of '\x0A': + inc(i) + result = max(result, lineLen) + lineLen = 0 + else: + inc(lineLen) + inc(i) + +proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) = + var + i, hi: int + str: string + i = 0 + hi = len(s) + 0 - 1 + str = "" + while i <= hi: + case s[i] + of '\x0D': + put(g, kind, str) + str = "" + inc(i) + if (i <= hi) and (s[i] == '\x0A'): inc(i) + optNL(g, 0) + of '\x0A': + put(g, kind, str) + str = "" + inc(i) + optNL(g, 0) + else: + add(str, s[i]) + inc(i) + put(g, kind, str) + +proc containsNL(s: string): bool = + for i in countup(0, len(s) + 0 - 1): + case s[i] + of '\x0D', '\x0A': + return true + else: + nil + result = false + +proc pushCom(g: var TSrcGen, n: PNode) = + var length: int + length = len(g.comStack) + setlen(g.comStack, length + 1) + g.comStack[length] = n + +proc popAllComs(g: var TSrcGen) = + setlen(g.comStack, 0) + +proc popCom(g: var TSrcGen) = + setlen(g.comStack, len(g.comStack) - 1) + +const + Space = " " + +proc shouldRenderComment(g: var TSrcGen, n: PNode): bool = + result = false + if n.comment != nil: + result = not (renderNoComments in g.flags) or + (renderDocComments in g.flags) and startsWith(n.comment, "##") + +proc gcom(g: var TSrcGen, n: PNode) = + var ml: int + assert(n != nil) + if shouldRenderComment(g, n): + if (g.pendingNL < 0) and (len(g.buf) > 0) and (g.buf[len(g.buf)] != ' '): + put(g, tkSpaces, Space) # 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 (len(g.buf) > 0) and + (g.lineLen < LineCommentColumn): + ml = maxLineLength(n.comment) + if ml + LineCommentColumn <= maxLineLen: + put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen)) + putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n); + +proc gcoms(g: var TSrcGen) = + for i in countup(0, high(g.comStack)): gcom(g, g.comStack[i]) + popAllComs(g) + +proc lsub(n: PNode): int +proc litAux(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 = $(x) + +proc atom(n: PNode): string = + var f: float32 + case n.kind + of nkEmpty: + result = "" + of nkIdent: + result = n.ident.s + of nkSym: + result = n.sym.name.s + of nkStrLit: + result = makeNimString(n.strVal) + of nkRStrLit: + result = "r\"" & n.strVal & '\"' + of nkTripleStrLit: + result = "\"\"\"" & n.strVal & "\"\"\"" + of nkCharLit: + result = '\'' & toNimChar(chr(int(n.intVal))) & '\'' + of nkIntLit: + result = litAux(n, n.intVal, 4) + of nkInt8Lit: + result = litAux(n, n.intVal, 1) & "\'i8" + of nkInt16Lit: + result = litAux(n, n.intVal, 2) & "\'i16" + of nkInt32Lit: + result = litAux(n, n.intVal, 4) & "\'i32" + of nkInt64Lit: + result = litAux(n, n.intVal, 8) & "\'i64" + of nkFloatLit: + if n.flags * {nfBase2, nfBase8, nfBase16} == {}: result = $(n.floatVal) + else: result = litAux(n, (cast[PInt64](addr(n.floatVal)))^ , 8) + of nkFloat32Lit: + if n.flags * {nfBase2, nfBase8, nfBase16} == {}: + result = $(n.floatVal) & "\'f32" + else: + f = n.floatVal + result = litAux(n, (cast[PInt32](addr(f)))^ , 4) & "\'f32" + of nkFloat64Lit: + if n.flags * {nfBase2, nfBase8, nfBase16} == {}: + result = $(n.floatVal) & "\'f64" + else: + result = litAux(n, (cast[PInt64](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("rnimsyn.atom " & $n.kind) + +proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int = + assert(theEnd < 0) + result = 0 + for i in countup(start, sonsLen(n) + theEnd): + inc(result, lsub(n.sons[i])) + inc(result, 2) # for ``, `` + if result > 0: + dec(result, 2) # last does not get a comma! + +proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int = + assert(theEnd < 0) + result = 0 + for i in countup(start, sonsLen(n) + theEnd): inc(result, lsub(n.sons[i])) + +proc lsub(n: PNode): int = + # computes the length of a tree + var L: int + if n == nil: + return 0 + if n.comment != nil: + return maxLineLen + 1 + case n.kind + of nkTripleStrLit: + if containsNL(n.strVal): result = maxLineLen + 1 + else: result = len(atom(n)) + of nkEmpty..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: + result = len(atom(n)) + of nkCall, nkBracketExpr, nkConv: + result = lsub(n.sons[0]) + lcomma(n, 1) + 2 + of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: + result = lsub(n.sons[1]) + of nkCast: + result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()") + of nkAddr: + result = lsub(n.sons[0]) + len("addr()") + of nkHiddenAddr, nkHiddenDeref: + result = lsub(n.sons[0]) + of nkCommand: + result = lsub(n.sons[0]) + lcomma(n, 1) + 1 + of nkExprEqExpr, nkAsgn, nkFastAsgn: + result = lsons(n) + 3 + of nkPar, nkCurly, nkBracket: + result = lcomma(n) + 2 + of nkSymChoice: + result = lsons(n) + len("()") + sonsLen(n) - 1 + of nkTupleTy: + result = lcomma(n) + len("tuple[]") + of nkDotExpr: + result = lsons(n) + 1 + of nkBind: + result = lsons(n) + len("bind_") + of nkCheckedFieldExpr: + result = lsub(n.sons[0]) + of nkLambda: + result = lsons(n) + len("lambda__=_") + of nkConstDef, nkIdentDefs: + result = lcomma(n, 0, - 3) + L = sonsLen(n) + if n.sons[L - 2] != nil: result = result + lsub(n.sons[L - 2]) + 2 + if n.sons[L - 1] != nil: result = result + lsub(n.sons[L - 1]) + 3 + of nkVarTuple: + result = lcomma(n, 0, - 3) + len("() = ") + lsub(lastSon(n)) + of nkChckRangeF: + result = len("chckRangeF") + 2 + lcomma(n) + of nkChckRange64: + result = len("chckRange64") + 2 + lcomma(n) + of nkChckRange: + result = len("chckRange") + 2 + lcomma(n) + of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString, + nkPassAsOpenArray: + result = 2 + if sonsLen(n) >= 1: result = result + lsub(n.sons[0]) + result = result + lcomma(n, 1) + of nkExprColonExpr: + result = lsons(n) + 2 + of nkInfix: + result = lsons(n) + 2 + of nkPrefix: + result = lsons(n) + 1 + of nkPostfix: + result = lsons(n) + of nkCallStrLit: + result = lsons(n) + of nkPragmaExpr: + result = lsub(n.sons[0]) + lcomma(n, 1) + of nkRange: + result = lsons(n) + 2 + of nkDerefExpr: + result = lsub(n.sons[0]) + 2 + of nkAccQuoted: + result = lsub(n.sons[0]) + 2 + of nkIfExpr: + result = lsub(n.sons[0].sons[0]) + lsub(n.sons[0].sons[1]) + lsons(n, 1) + + len("if_:_") + of nkElifExpr: + result = lsons(n) + len("_elif_:_") + of nkElseExpr: + result = lsub(n.sons[0]) + len("_else:_") # type descriptions + of nkTypeOfExpr: + result = lsub(n.sons[0]) + len("type_") + of nkRefTy: + result = lsub(n.sons[0]) + len("ref_") + of nkPtrTy: + result = lsub(n.sons[0]) + len("ptr_") + of nkVarTy: + result = lsub(n.sons[0]) + len("var_") + of nkDistinctTy: + result = lsub(n.sons[0]) + len("Distinct_") + of nkTypeDef: + result = lsons(n) + 3 + of nkOfInherit: + result = lsub(n.sons[0]) + len("of_") + of nkProcTy: + result = lsons(n) + len("proc_") + of nkEnumTy: + result = lsub(n.sons[0]) + lcomma(n, 1) + len("enum_") + of nkEnumFieldDef: + result = lsons(n) + 3 + of nkVarSection: + if sonsLen(n) > 1: result = maxLineLen + 1 + else: result = lsons(n) + len("var_") + of nkReturnStmt: + result = lsub(n.sons[0]) + len("return_") + of nkRaiseStmt: + result = lsub(n.sons[0]) + len("raise_") + of nkYieldStmt: + result = lsub(n.sons[0]) + len("yield_") + of nkDiscardStmt: + result = lsub(n.sons[0]) + len("discard_") + of nkBreakStmt: + result = lsub(n.sons[0]) + len("break_") + of nkContinueStmt: + result = lsub(n.sons[0]) + len("continue_") + of nkPragma: + result = lcomma(n) + 4 + of nkCommentStmt: + result = len(n.comment) + of nkOfBranch: + result = lcomma(n, 0, - 2) + lsub(lastSon(n)) + len("of_:_") + of nkElifBranch: + result = lsons(n) + len("elif_:_") + of nkElse: + result = lsub(n.sons[0]) + len("else:_") + of nkFinally: + result = lsub(n.sons[0]) + len("finally:_") + of nkGenericParams: + result = lcomma(n) + 2 + of nkFormalParams: + result = lcomma(n, 1) + 2 + if n.sons[0] != nil: result = result + lsub(n.sons[0]) + 2 + of nkExceptBranch: + result = lcomma(n, 0, - 2) + lsub(lastSon(n)) + len("except_:_") + else: result = maxLineLen + 1 + +proc fits(g: TSrcGen, x: int): bool = + result = x + g.lineLen <= maxLineLen + +type + TSubFlag = enum + rfLongMode, rfNoIndent, rfInConstExpr + TSubFlags = set[TSubFlag] + TContext = tuple[spacing: int, flags: TSubFlags] + +const + emptyContext: TContext = (spacing: 0, flags: {}) + +proc initContext(c: var TContext) = + c.spacing = 0 + c.flags = {} + +proc gsub(g: var TSrcGen, n: PNode, c: TContext) +proc gsub(g: var TSrcGen, n: PNode) = + var c: TContext + initContext(c) + gsub(g, n, c) + +proc hasCom(n: PNode): bool = + result = false + if n == nil: return + if n.comment != nil: + return true + case n.kind + of nkEmpty..nkNilLit: + nil + else: + for i in countup(0, sonsLen(n) - 1): + if hasCom(n.sons[i]): + return true + +proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) = + put(g, kind, s) + put(g, tkSpaces, Space) + +proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0, + theEnd: int = - 1) = + var + sublen: int + c: bool + for i in countup(start, sonsLen(n) + theEnd): + c = i < sonsLen(n) + theEnd + sublen = lsub(n.sons[i]) + ord(c) + if not fits(g, sublen) and (ind + sublen < maxLineLen): optNL(g, ind) + gsub(g, n.sons[i]) + if c: + putWithSpace(g, tkComma, ",") + if hasCom(n.sons[i]): + gcoms(g) + optNL(g, ind) + +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: int + ind = g.lineLen + if ind > maxLineLen div 2: ind = g.indent + longIndentWid + gcommaAux(g, n, ind, start, theEnd) + +proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0, + theEnd: int = - 1) = + for i in countup(start, sonsLen(n) + theEnd): + gsub(g, n.sons[i], c) + +proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType, k: string) = + if sonsLen(n) == 0: + return # empty var sections are possible + putWithSpace(g, kind, k) + gcoms(g) + indentNL(g) + for i in countup(0, sonsLen(n) - 1): + optNL(g) + gsub(g, n.sons[i], c) + gcoms(g) + dedent(g) + +proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool = + result = n.comment != nil + if not result: + # check further + for i in countup(start, sonsLen(n) + theEnd): + if (lsub(n.sons[i]) > maxLineLen): + result = true + break + +proc gstmts(g: var TSrcGen, n: PNode, c: TContext) = + if n == nil: return + if (n.kind == nkStmtList) or (n.kind == nkStmtListExpr): + indentNL(g) + for i in countup(0, sonsLen(n) - 1): + optNL(g) + gsub(g, n.sons[i]) + gcoms(g) + dedent(g) + else: + if rfLongMode in c.flags: indentNL(g) + gsub(g, n) + gcoms(g) + optNL(g) + if rfLongMode in c.flags: dedent(g) + +proc gif(g: var TSrcGen, n: PNode) = + var + c: TContext + length: int + gsub(g, n.sons[0].sons[0]) + initContext(c) + putWithSpace(g, tkColon, ":") + if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > maxLineLen): + incl(c.flags, rfLongMode) + gcoms(g) # a good place for comments + gstmts(g, n.sons[0].sons[1], c) + length = sonsLen(n) + for i in countup(1, length - 1): + optNL(g) + gsub(g, n.sons[i], c) + +proc gwhile(g: var TSrcGen, n: PNode) = + var c: TContext + putWithSpace(g, tkWhile, "while") + gsub(g, n.sons[0]) + putWithSpace(g, tkColon, ":") + initContext(c) + if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen): + incl(c.flags, rfLongMode) + gcoms(g) # a good place for comments + gstmts(g, n.sons[1], c) + +proc gtry(g: var TSrcGen, n: PNode) = + var c: TContext + put(g, tkTry, "try") + putWithSpace(g, tkColon, ":") + initContext(c) + if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen): + incl(c.flags, rfLongMode) + gcoms(g) # a good place for comments + gstmts(g, n.sons[0], c) + gsons(g, n, c, 1) + +proc gfor(g: var TSrcGen, n: PNode) = + var + c: TContext + length: int + length = sonsLen(n) + putWithSpace(g, tkFor, "for") + initContext(c) + if longMode(n) or + (lsub(n.sons[length - 1]) + lsub(n.sons[length - 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.sons[length - 2], c) + putWithSpace(g, tkColon, ":") + gcoms(g) + gstmts(g, n.sons[length - 1], c) + +proc gmacro(g: var TSrcGen, n: PNode) = + var c: TContext + initContext(c) + gsub(g, n.sons[0]) + putWithSpace(g, tkColon, ":") + if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen): + incl(c.flags, rfLongMode) + gcoms(g) + gsons(g, n, c, 1) + +proc gcase(g: var TSrcGen, n: PNode) = + var + c: TContext + length, last: int + initContext(c) + length = sonsLen(n) + if n.sons[length - 1].kind == nkElse: last = - 2 + else: last = - 1 + if longMode(n, 0, last): incl(c.flags, rfLongMode) + putWithSpace(g, tkCase, "case") + gsub(g, n.sons[0]) + gcoms(g) + optNL(g) + gsons(g, n, c, 1, last) + if last == - 2: + initContext(c) + if longMode(n.sons[length - 1]): incl(c.flags, rfLongMode) + gsub(g, n.sons[length - 1], c) + +proc gproc(g: var TSrcGen, n: PNode) = + var c: TContext + gsub(g, n.sons[0]) + gsub(g, n.sons[1]) + gsub(g, n.sons[2]) + gsub(g, n.sons[3]) + if not (renderNoBody in g.flags): + if n.sons[4] != nil: + put(g, tkSpaces, Space) + putWithSpace(g, tkEquals, "=") + indentNL(g) + gcoms(g) + dedent(g) + initContext(c) + gstmts(g, n.sons[4], c) + putNL(g) + else: + indentNL(g) + gcoms(g) + dedent(g) + +proc gblock(g: var TSrcGen, n: PNode) = + var c: TContext + initContext(c) + putWithSpace(g, tkBlock, "block") + gsub(g, n.sons[0]) + putWithSpace(g, tkColon, ":") + if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen): + incl(c.flags, rfLongMode) + gcoms(g) + gstmts(g, n.sons[1], c) + +proc gasm(g: var TSrcGen, n: PNode) = + putWithSpace(g, tkAsm, "asm") + gsub(g, n.sons[0]) + gcoms(g) + gsub(g, n.sons[1]) + +proc gident(g: var TSrcGen, n: PNode) = + var + s: string + t: TTokType + s = atom(n) + if (s[0] in scanner.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 = TTokType(n.ident.id + ord(tkSymbol)) + else: + t = tkSymbol + else: + t = tkOpr + put(g, t, s) + if (n.kind == nkSym) and (renderIds in g.flags): put(g, tkIntLit, $(n.sym.id)) + +proc gsub(g: var TSrcGen, n: PNode, c: TContext) = + var + L: int + a: TContext + if n == nil: return + if n.comment != nil: pushCom(g, n) + case n.kind # atoms: + of nkTripleStrLit: + putRawStr(g, tkTripleStrLit, n.strVal) + of nkEmpty, nkType: + put(g, tkInvalid, atom(n)) + of nkSym, nkIdent: + gident(g, n) + of nkIntLit: + put(g, tkIntLit, atom(n)) + of nkInt8Lit: + put(g, tkInt8Lit, atom(n)) + of nkInt16Lit: + put(g, tkInt16Lit, atom(n)) + of nkInt32Lit: + put(g, tkInt32Lit, atom(n)) + of nkInt64Lit: + put(g, tkInt64Lit, atom(n)) + of nkFloatLit: + put(g, tkFloatLit, atom(n)) + of nkFloat32Lit: + put(g, tkFloat32Lit, atom(n)) + of nkFloat64Lit: + put(g, tkFloat64Lit, atom(n)) + of nkStrLit: + put(g, tkStrLit, atom(n)) + of nkRStrLit: + put(g, tkRStrLit, atom(n)) + of nkCharLit: + put(g, tkCharLit, atom(n)) + of nkNilLit: + put(g, tkNil, atom(n)) # complex expressions + of nkCall, nkConv, nkDotCall: + if sonsLen(n) >= 1: gsub(g, n.sons[0]) + put(g, tkParLe, "(") + gcomma(g, n, 1) + put(g, tkParRi, ")") + of nkCallStrLit: + gsub(g, n.sons[0]) + if n.sons[1].kind == nkRStrLit: + put(g, tkRStrLit, '\"' & n.sons[1].strVal & '\"') + else: + gsub(g, n.sons[0]) + of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: + gsub(g, n.sons[0]) + of nkCast: + put(g, tkCast, "cast") + put(g, tkBracketLe, "[") + gsub(g, n.sons[0]) + put(g, tkBracketRi, "]") + put(g, tkParLe, "(") + gsub(g, n.sons[1]) + put(g, tkParRi, ")") + of nkAddr: + put(g, tkAddr, "addr") + put(g, tkParLe, "(") + gsub(g, n.sons[0]) + put(g, tkParRi, ")") + of nkBracketExpr: + gsub(g, n.sons[0]) + put(g, tkBracketLe, "[") + gcomma(g, n, 1) + put(g, tkBracketRi, "]") + of nkPragmaExpr: + gsub(g, n.sons[0]) + gcomma(g, n, 1) + of nkCommand: + gsub(g, n.sons[0]) + put(g, tkSpaces, space) + gcomma(g, n, 1) + of nkExprEqExpr, nkAsgn, nkFastAsgn: + gsub(g, n.sons[0]) + put(g, tkSpaces, Space) + putWithSpace(g, tkEquals, "=") + gsub(g, n.sons[1]) + 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, nkStringToCString, nkCStringToString, + nkPassAsOpenArray: + if sonsLen(n) >= 1: gsub(g, n.sons[0]) + put(g, tkParLe, "(") + gcomma(g, n, 1) + put(g, tkParRi, ")") + of nkSymChoice: + put(g, tkParLe, "(") + for i in countup(0, sonsLen(n) - 1): + if i > 0: put(g, tkOpr, "|") + gsub(g, n.sons[i], c) + put(g, tkParRi, ")") + of nkPar: + put(g, tkParLe, "(") + gcomma(g, n, c) + put(g, tkParRi, ")") + of nkCurly: + put(g, tkCurlyLe, "{") + gcomma(g, n, c) + put(g, tkCurlyRi, "}") + of nkBracket: + put(g, tkBracketLe, "[") + gcomma(g, n, c) + put(g, tkBracketRi, "]") + of nkDotExpr: + gsub(g, n.sons[0]) + put(g, tkDot, ".") + gsub(g, n.sons[1]) + of nkBind: + putWithSpace(g, tkBind, "bind") + gsub(g, n.sons[0]) + of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: + gsub(g, n.sons[0]) + of nkLambda: + assert(n.sons[genericParamsPos] == nil) + putWithSpace(g, tkLambda, "lambda") + gsub(g, n.sons[paramsPos]) + gsub(g, n.sons[pragmasPos]) + put(g, tkSpaces, Space) + putWithSpace(g, tkEquals, "=") + gsub(g, n.sons[codePos]) + of nkConstDef, nkIdentDefs: + gcomma(g, n, 0, - 3) + L = sonsLen(n) + if n.sons[L - 2] != nil: + putWithSpace(g, tkColon, ":") + gsub(g, n.sons[L - 2]) + if n.sons[L - 1] != nil: + put(g, tkSpaces, Space) + putWithSpace(g, tkEquals, "=") + gsub(g, n.sons[L - 1], c) + of nkVarTuple: + 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.sons[0]) + putWithSpace(g, tkColon, ":") + gsub(g, n.sons[1]) + of nkInfix: + gsub(g, n.sons[1]) + put(g, tkSpaces, Space) + gsub(g, n.sons[0]) # binary operator + if not fits(g, lsub(n.sons[2]) + lsub(n.sons[0]) + 1): + optNL(g, g.indent + longIndentWid) + else: + put(g, tkSpaces, Space) + gsub(g, n.sons[2]) + of nkPrefix: + gsub(g, n.sons[0]) + put(g, tkSpaces, space) + gsub(g, n.sons[1]) + of nkPostfix: + gsub(g, n.sons[1]) + gsub(g, n.sons[0]) + of nkRange: + gsub(g, n.sons[0]) + put(g, tkDotDot, "..") + gsub(g, n.sons[1]) + of nkDerefExpr: + gsub(g, n.sons[0]) + putWithSpace(g, tkHat, "^") # unfortunately this requires a space, because ^. would be + # only one operator + of nkAccQuoted: + put(g, tkAccent, "`") + gsub(g, n.sons[0]) + put(g, tkAccent, "`") + of nkIfExpr: + putWithSpace(g, tkIf, "if") + gsub(g, n.sons[0].sons[0]) + putWithSpace(g, tkColon, ":") + gsub(g, n.sons[0].sons[1]) + gsons(g, n, emptyContext, 1) + of nkElifExpr: + putWithSpace(g, tkElif, " elif") + gsub(g, n.sons[0]) + putWithSpace(g, tkColon, ":") + gsub(g, n.sons[1]) + of nkElseExpr: + put(g, tkElse, " else") + putWithSpace(g, tkColon, ":") + gsub(g, n.sons[0]) + of nkTypeOfExpr: + putWithSpace(g, tkType, "type") + gsub(g, n.sons[0]) + of nkRefTy: + putWithSpace(g, tkRef, "ref") + gsub(g, n.sons[0]) + of nkPtrTy: + putWithSpace(g, tkPtr, "ptr") + gsub(g, n.sons[0]) + of nkVarTy: + putWithSpace(g, tkVar, "var") + gsub(g, n.sons[0]) + of nkDistinctTy: + putWithSpace(g, tkDistinct, "distinct") + gsub(g, n.sons[0]) + of nkTypeDef: + gsub(g, n.sons[0]) + gsub(g, n.sons[1]) + put(g, tkSpaces, Space) + if n.sons[2] != nil: + putWithSpace(g, tkEquals, "=") + gsub(g, n.sons[2]) + of nkObjectTy: + putWithSpace(g, tkObject, "object") + gsub(g, n.sons[0]) + gsub(g, n.sons[1]) + gcoms(g) + gsub(g, n.sons[2]) + of nkRecList: + indentNL(g) + for i in countup(0, sonsLen(n) - 1): + optNL(g) + gsub(g, n.sons[i], c) + gcoms(g) + dedent(g) + putNL(g) + of nkOfInherit: + putWithSpace(g, tkOf, "of") + gsub(g, n.sons[0]) + of nkProcTy: + putWithSpace(g, tkProc, "proc") + gsub(g, n.sons[0]) + gsub(g, n.sons[1]) + of nkEnumTy: + putWithSpace(g, tkEnum, "enum") + gsub(g, n.sons[0]) + gcoms(g) + indentNL(g) + gcommaAux(g, n, g.indent, 1) + gcoms(g) # BUGFIX: comment for the last enum field + dedent(g) + of nkEnumFieldDef: + gsub(g, n.sons[0]) + put(g, tkSpaces, Space) + putWithSpace(g, tkEquals, "=") + gsub(g, n.sons[1]) + of nkStmtList, nkStmtListExpr: + gstmts(g, n, emptyContext) + of nkIfStmt: + putWithSpace(g, tkIf, "if") + gif(g, n) + of nkWhenStmt, nkRecWhen: + putWithSpace(g, tkWhen, "when") + gif(g, n) + of nkWhileStmt: + gwhile(g, n) + of nkCaseStmt, nkRecCase: + gcase(g, n) + of nkMacroStmt: + gmacro(g, n) + of nkTryStmt: + gtry(g, n) + of nkForStmt: + gfor(g, n) + of nkBlockStmt, nkBlockExpr: + gblock(g, n) + of nkAsmStmt: + gasm(g, n) + of nkProcDef: + putWithSpace(g, tkProc, "proc") + gproc(g, n) + of nkMethodDef: + putWithSpace(g, tkMethod, "method") + gproc(g, n) + of nkIteratorDef: + putWithSpace(g, tkIterator, "iterator") + gproc(g, n) + of nkMacroDef: + putWithSpace(g, tkMacro, "macro") + gproc(g, n) + of nkTemplateDef: + putWithSpace(g, tkTemplate, "template") + gproc(g, n) + of nkTypeSection: + gsection(g, n, emptyContext, tkType, "type") + of nkConstSection: + initContext(a) + incl(a.flags, rfInConstExpr) + gsection(g, n, a, tkConst, "const") + of nkVarSection: + L = sonsLen(n) + if L == 0: return + putWithSpace(g, tkVar, "var") + if L > 1: + gcoms(g) + indentNL(g) + for i in countup(0, L - 1): + optNL(g) + gsub(g, n.sons[i]) + gcoms(g) + dedent(g) + else: + gsub(g, n.sons[0]) + of nkReturnStmt: + putWithSpace(g, tkReturn, "return") + gsub(g, n.sons[0]) + of nkRaiseStmt: + putWithSpace(g, tkRaise, "raise") + gsub(g, n.sons[0]) + of nkYieldStmt: + putWithSpace(g, tkYield, "yield") + gsub(g, n.sons[0]) + of nkDiscardStmt: + putWithSpace(g, tkDiscard, "discard") + gsub(g, n.sons[0]) + of nkBreakStmt: + putWithSpace(g, tkBreak, "break") + gsub(g, n.sons[0]) + of nkContinueStmt: + putWithSpace(g, tkContinue, "continue") + gsub(g, n.sons[0]) + of nkPragma: + if not (renderNoPragmas in g.flags): + put(g, tkCurlyDotLe, "{.") + gcomma(g, n, emptyContext) + put(g, tkCurlyDotRi, ".}") + of nkImportStmt: + putWithSpace(g, tkImport, "import") + gcoms(g) + indentNL(g) + gcommaAux(g, n, g.indent) + dedent(g) + putNL(g) + of nkFromStmt: + putWithSpace(g, tkFrom, "from") + gsub(g, n.sons[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 nkElifBranch: + optNL(g) + putWithSpace(g, tkElif, "elif") + gsub(g, n.sons[0]) + putWithSpace(g, tkColon, ":") + gcoms(g) + gstmts(g, n.sons[1], c) + of nkElse: + optNL(g) + put(g, tkElse, "else") + putWithSpace(g, tkColon, ":") + gcoms(g) + gstmts(g, n.sons[0], c) + of nkFinally: + optNL(g) + put(g, tkFinally, "finally") + putWithSpace(g, tkColon, ":") + gcoms(g) + gstmts(g, n.sons[0], c) + of nkExceptBranch: + optNL(g) + putWithSpace(g, tkExcept, "except") + gcomma(g, n, 0, - 2) + putWithSpace(g, tkColon, ":") + gcoms(g) + gstmts(g, lastSon(n), c) + of nkGenericParams: + put(g, tkBracketLe, "[") + gcomma(g, n) + put(g, tkBracketRi, "]") + of nkFormalParams: + put(g, tkParLe, "(") + gcomma(g, n, 1) + put(g, tkParRi, ")") + if n.sons[0] != nil: + putWithSpace(g, tkColon, ":") + gsub(g, n.sons[0]) + of nkTupleTy: + put(g, tkTuple, "tuple") + put(g, tkBracketLe, "[") + gcomma(g, n) + put(g, tkBracketRi, "]") + else: + #nkNone, nkMetaNode, nkTableConstr, nkExplicitTypeListCall: + InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')') + +proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string = + var g: TSrcGen + initSrcGen(g, renderFlags) + gsub(g, n) + result = g.buf + +proc renderModule(n: PNode, filename: string, renderFlags: TRenderFlags = {}) = + var + f: tfile + g: TSrcGen + initSrcGen(g, renderFlags) + for i in countup(0, sonsLen(n) - 1): + gsub(g, n.sons[i]) + optNL(g) + if n.sons[i] != nil: + case n.sons[i].kind + of nkTypeSection, nkConstSection, nkVarSection, nkCommentStmt: putNL(g) + else: + nil + gcoms(g) + if open(f, filename, fmWrite): + write(f, g.buf) + close(f) + +proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = + initSrcGen(r, renderFlags) + gsub(r, n) + +proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) = + var length: int + if r.idx < len(r.tokens): + kind = r.tokens[r.idx].kind + length = r.tokens[r.idx].length + literal = copy(r.buf, r.pos + 0, r.pos + 0 + length - 1) + inc(r.pos, length) + inc(r.idx) + else: + kind = tkEof + |