summary refs log tree commit diff stats
path: root/compiler/renderer.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/renderer.nim')
-rw-r--r--compiler/renderer.nim536
1 files changed, 276 insertions, 260 deletions
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index b0d328f9e..ffdb60696 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -9,20 +9,20 @@
 
 # This module implements the renderer of the standard Nim representation.
 
-import 
+import
   lexer, options, idents, strutils, ast, msgs, lists
 
-type 
-  TRenderFlag* = enum 
-    renderNone, renderNoBody, renderNoComments, renderDocComments, 
+type
+  TRenderFlag* = enum
+    renderNone, renderNoBody, renderNoComments, renderDocComments,
     renderNoPragmas, renderIds, renderNoProcDefs
   TRenderFlags* = set[TRenderFlag]
-  TRenderTok*{.final.} = object 
+  TRenderTok*{.final.} = object
     kind*: TTokType
     length*: int16
 
   TRenderTokSeq* = seq[TRenderTok]
-  TSrcGen*{.final.} = object 
+  TSrcGen*{.final.} = object
     indent*: int
     lineLen*: int
     pos*: int              # current position for iteration over the buffer
@@ -34,23 +34,27 @@ type
     comStack*: seq[PNode]  # comment stack
     flags*: TRenderFlags
     checkAnon: bool        # we're in a context that can contain sfAnon
+    inPragma: int
 
 
 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)
+
+proc `$`*(n: PNode): string = n.renderTree
 # 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.
 
-proc isKeyword*(s: string): bool =
-  var i = getIdent(s)
+proc isKeyword*(i: PIdent): bool =
   if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
-      (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)): 
+      (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
     result = true
 
+proc isKeyword*(s: string): bool = isKeyword(getIdent(s))
+
 proc renderDefinitionName*(s: PSym, noQuotes = false): string =
   ## Returns the definition name of the symbol.
   ##
@@ -58,18 +62,18 @@ proc renderDefinitionName*(s: PSym, noQuotes = false): string =
   ## 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(x)):
+  if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(s.name)):
     result = x
   else:
     result = '`' & x & '`'
 
-const 
+const
   IndentWidth = 2
   longIndentWid = 4
   MaxLineLen = 80
   LineCommentColumn = 30
 
-proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = 
+proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
   g.comStack = @[]
   g.tokens = @[]
   g.indent = 0
@@ -81,67 +85,67 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
   g.pendingNL = -1
   g.checkAnon = false
 
-proc addTok(g: var TSrcGen, kind: TTokType, s: string) = 
+proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
   var 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, tkSpaces, "\n" & repeatChar(g.pendingNL))
+proc addPendingNL(g: var TSrcGen) =
+  if g.pendingNL >= 0:
+    addTok(g, tkSpaces, "\n" & spaces(g.pendingNL))
     g.lineLen = g.pendingNL
     g.pendingNL = - 1
 
-proc putNL(g: var TSrcGen, indent: int) = 
+proc putNL(g: var TSrcGen, indent: int) =
   if g.pendingNL >= 0: addPendingNL(g)
   else: addTok(g, tkSpaces, "\n")
   g.pendingNL = indent
   g.lineLen = indent
 
-proc putNL(g: var TSrcGen) = 
+proc putNL(g: var TSrcGen) =
   putNL(g, g.indent)
 
-proc optNL(g: var TSrcGen, indent: int) = 
+proc optNL(g: var TSrcGen, indent: int) =
   g.pendingNL = indent
   g.lineLen = indent          # BUGFIX
-  
-proc optNL(g: var TSrcGen) = 
+
+proc optNL(g: var TSrcGen) =
   optNL(g, g.indent)
 
-proc indentNL(g: var TSrcGen) = 
+proc indentNL(g: var TSrcGen) =
   inc(g.indent, IndentWidth)
   g.pendingNL = g.indent
   g.lineLen = g.indent
 
-proc dedent(g: var TSrcGen) = 
+proc dedent(g: var TSrcGen) =
   dec(g.indent, IndentWidth)
   assert(g.indent >= 0)
-  if g.pendingNL > IndentWidth: 
+  if g.pendingNL > IndentWidth:
     dec(g.pendingNL, IndentWidth)
     dec(g.lineLen, IndentWidth)
 
-proc put(g: var TSrcGen, kind: TTokType, s: string) = 
+proc put(g: var TSrcGen, kind: TTokType, s: string) =
   addPendingNL(g)
-  if len(s) > 0: 
+  if len(s) > 0:
     addTok(g, kind, s)
     inc(g.lineLen, len(s))
 
-proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) = 
+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 = 
+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 = 
+
+proc makeNimString(s: string): string =
   result = "\""
   for i in countup(0, len(s)-1): add(result, toNimChar(s[i]))
   add(result, '\"')
@@ -172,7 +176,7 @@ proc putComment(g: var TSrcGen, s: string) =
       add(com, s[i])
       inc(i)
       comIndent = 0
-      while s[i] == ' ': 
+      while s[i] == ' ':
         add(com, s[i])
         inc(i)
         inc(comIndent)
@@ -185,109 +189,109 @@ proc putComment(g: var TSrcGen, s: string) =
       # compute length of the following word:
       var j = i
       while s[j] > ' ': inc(j)
-      if not isCode and (g.lineLen + (j - i) > MaxLineLen): 
+      if not isCode and (g.lineLen + (j - i) > MaxLineLen):
         put(g, tkComment, com)
         optNL(g, ind)
-        com = '#' & repeatChar(comIndent)
-      while s[i] > ' ': 
+        com = '#' & spaces(comIndent)
+      while s[i] > ' ':
         add(com, s[i])
         inc(i)
   put(g, tkComment, com)
   optNL(g)
 
-proc maxLineLength(s: string): int = 
+proc maxLineLength(s: string): int =
   if s.isNil: return 0
   var i = 0
   var lineLen = 0
   while true:
     case s[i]
-    of '\0': 
-      break 
-    of '\x0D': 
+    of '\0':
+      break
+    of '\x0D':
       inc(i)
       if s[i] == '\x0A': inc(i)
       result = max(result, lineLen)
       lineLen = 0
-    of '\x0A': 
+    of '\x0A':
       inc(i)
       result = max(result, lineLen)
       lineLen = 0
-    else: 
+    else:
       inc(lineLen)
       inc(i)
 
-proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) = 
+proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
   var i = 0
   var hi = len(s) - 1
   var str = ""
-  while i <= hi: 
+  while i <= hi:
     case s[i]
-    of '\x0D': 
+    of '\x0D':
       put(g, kind, str)
       str = ""
       inc(i)
       if (i <= hi) and (s[i] == '\x0A'): inc(i)
       optNL(g, 0)
-    of '\x0A': 
+    of '\x0A':
       put(g, kind, str)
       str = ""
       inc(i)
       optNL(g, 0)
-    else: 
+    else:
       add(str, s[i])
       inc(i)
   put(g, kind, str)
 
-proc containsNL(s: string): bool = 
-  for i in countup(0, len(s) - 1): 
+proc containsNL(s: string): bool =
+  for i in countup(0, len(s) - 1):
     case s[i]
-    of '\x0D', '\x0A': 
+    of '\x0D', '\x0A':
       return true
-    else: 
+    else:
       discard
   result = false
 
-proc pushCom(g: var TSrcGen, n: PNode) = 
+proc pushCom(g: var TSrcGen, n: PNode) =
   var length = len(g.comStack)
   setLen(g.comStack, length + 1)
   g.comStack[length] = n
 
-proc popAllComs(g: var TSrcGen) = 
+proc popAllComs(g: var TSrcGen) =
   setLen(g.comStack, 0)
 
-proc popCom(g: var TSrcGen) = 
+proc popCom(g: var TSrcGen) =
   setLen(g.comStack, len(g.comStack) - 1)
 
-const 
+const
   Space = " "
 
-proc shouldRenderComment(g: var TSrcGen, n: PNode): bool = 
+proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
   result = false
-  if n.comment != nil: 
+  if n.comment != nil:
     result = (renderNoComments notin g.flags) or
         (renderDocComments in g.flags) and startsWith(n.comment, "##")
-  
-proc gcom(g: var TSrcGen, n: PNode) = 
+
+proc gcom(g: var TSrcGen, n: PNode) =
   assert(n != nil)
-  if shouldRenderComment(g, n): 
+  if shouldRenderComment(g, n):
     if (g.pendingNL < 0) and (len(g.buf) > 0) and (g.buf[len(g.buf)-1] != ' '):
-      put(g, tkSpaces, Space) 
+      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): 
+        (g.lineLen < LineCommentColumn):
       var ml = maxLineLength(n.comment)
-      if ml + LineCommentColumn <= MaxLineLen: 
-        put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen))
+      if ml + LineCommentColumn <= MaxLineLen:
+        put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen))
     putComment(g, n.comment)  #assert(g.comStack[high(g.comStack)] = n);
-  
-proc gcoms(g: var TSrcGen) = 
+
+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 =
-  proc skip(t: PType): PType = 
+  proc skip(t: PType): PType =
     result = t
     while result.kind in {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
                           tyConst, tyMutable}:
@@ -297,20 +301,20 @@ proc litAux(n: PNode, x: BiggestInt, size: int): string =
     # we need a slow linear search because of enums with holes:
     for e in items(enumfields):
       if e.sym.position == x: return e.sym.name.s
-    
+
   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 ulitAux(n: PNode, x: BiggestInt, size: int): string = 
+proc ulitAux(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
   # XXX proper unsigned output!
-  
-proc atom(n: PNode): string = 
+
+proc atom(n: PNode): string =
   var f: float32
   case n.kind
   of nkEmpty: result = ""
@@ -333,55 +337,55 @@ proc atom(n: PNode): string =
   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} == {}: 
+  of nkFloat32Lit:
+    if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
       result = $n.floatVal & "\'f32"
-    else: 
+    else:
       f = n.floatVal.float32
       result = litAux(n, (cast[PInt32](addr(f)))[], 4) & "\'f32"
-  of nkFloat64Lit: 
-    if n.flags * {nfBase2, nfBase8, nfBase16} == {}: 
+  of nkFloat64Lit:
+    if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
       result = $n.floatVal & "\'f64"
-    else: 
+    else:
       result = litAux(n, (cast[PInt64](addr(n.floatVal)))[], 8) & "\'f64"
   of nkNilLit: result = "nil"
-  of nkType: 
+  of nkType:
     if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
     else: result = "[type node]"
-  else: 
+  else:
     internalError("rnimsyn.atom " & $n.kind)
     result = ""
-  
-proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int = 
+
+proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int =
   assert(theEnd < 0)
   result = 0
-  for i in countup(start, sonsLen(n) + theEnd): 
+  for i in countup(start, sonsLen(n) + theEnd):
     inc(result, lsub(n.sons[i]))
     inc(result, 2)            # for ``, ``
-  if result > 0: 
+  if result > 0:
     dec(result, 2)            # last does not get a comma!
-  
-proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int = 
+
+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 = 
+
+proc lsub(n: PNode): int =
   # computes the length of a tree
   if isNil(n): return 0
   if n.comment != nil: return MaxLineLen + 1
   case n.kind
   of nkEmpty: result = 0
-  of nkTripleStrLit: 
+  of nkTripleStrLit:
     if containsNL(n.strVal): result = MaxLineLen + 1
     else: result = len(atom(n))
-  of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: 
+  of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
     result = len(atom(n))
   of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr:
     result = lsub(n.sons[0]) + lcomma(n, 1) + 2
   of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1])
   of nkCast: result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()")
-  of nkAddr: result = lsub(n.sons[0]) + len("addr()")
+  of nkAddr: result = (if n.len>0: lsub(n.sons[0]) + len("addr()") else: 4)
   of nkStaticExpr: result = lsub(n.sons[0]) + len("static_")
   of nkHiddenAddr, nkHiddenDeref: result = lsub(n.sons[0])
   of nkCommand: result = lsub(n.sons[0]) + lcomma(n, 1) + 1
@@ -390,9 +394,10 @@ proc lsub(n: PNode): int =
   of nkArgList: result = lcomma(n)
   of nkTableConstr:
     result = if n.len > 0: lcomma(n) + 2 else: len("{:}")
-  of nkClosedSymChoice, nkOpenSymChoice: 
+  of nkClosedSymChoice, nkOpenSymChoice:
     result = lsons(n) + len("()") + sonsLen(n) - 1
   of nkTupleTy: result = lcomma(n) + len("tuple[]")
+  of nkTupleClassTy: result = len("tuple")
   of nkDotExpr: result = lsons(n) + 1
   of nkBind: result = lsons(n) + len("bind_")
   of nkBindStmt: result = lcomma(n) + len("bind_")
@@ -400,7 +405,7 @@ proc lsub(n: PNode): int =
   of nkCheckedFieldExpr: result = lsub(n.sons[0])
   of nkLambda: result = lsons(n) + len("proc__=_")
   of nkDo: result = lsons(n) + len("do__:_")
-  of nkConstDef, nkIdentDefs: 
+  of nkConstDef, nkIdentDefs:
     result = lcomma(n, 0, - 3)
     var L = sonsLen(n)
     if n.sons[L - 2].kind != nkEmpty: result = result + lsub(n.sons[L - 2]) + 2
@@ -409,7 +414,7 @@ proc lsub(n: PNode): int =
   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: 
+  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
     result = 2
     if sonsLen(n) >= 1: result = result + lsub(n.sons[0])
     result = result + lcomma(n, 1)
@@ -423,12 +428,12 @@ proc lsub(n: PNode): int =
   of nkRange: result = lsons(n) + 2
   of nkDerefExpr: result = lsub(n.sons[0]) + 2
   of nkAccQuoted: result = lsons(n) + 2
-  of nkIfExpr: 
+  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 nkTypeOfExpr: result = (if n.len > 0: lsub(n.sons[0]) else: 0)+len("type_")
   of nkRefTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ref")
   of nkPtrTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ptr")
   of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
@@ -444,13 +449,13 @@ proc lsub(n: PNode): int =
   of nkProcTy: result = lsons(n) + len("proc_")
   of nkIteratorTy: result = lsons(n) + len("iterator_")
   of nkSharedTy: result = lsons(n) + len("shared_")
-  of nkEnumTy: 
+  of nkEnumTy:
     if sonsLen(n) > 0:
       result = lsub(n.sons[0]) + lcomma(n, 1) + len("enum_")
     else:
       result = len("enum")
   of nkEnumFieldDef: result = lsons(n) + 3
-  of nkVarSection, nkLetSection: 
+  of nkVarSection, nkLetSection:
     if sonsLen(n) > 1: result = MaxLineLen + 1
     else: result = lsons(n) + len("var_")
   of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
@@ -467,50 +472,51 @@ proc lsub(n: PNode): int =
   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: 
+  of nkFormalParams:
     result = lcomma(n, 1) + 2
     if n.sons[0].kind != nkEmpty: result = result + lsub(n.sons[0]) + 2
-  of nkExceptBranch: 
+  of nkExceptBranch:
     result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_")
   else: result = MaxLineLen + 1
-  
-proc fits(g: TSrcGen, x: int): bool = 
+
+proc fits(g: TSrcGen, x: int): bool =
   result = x + g.lineLen <= MaxLineLen
 
-type 
-  TSubFlag = enum 
+type
+  TSubFlag = enum
     rfLongMode, rfNoIndent, rfInConstExpr
   TSubFlags = set[TSubFlag]
   TContext = tuple[spacing: int, flags: TSubFlags]
 
-const 
+const
   emptyContext: TContext = (spacing: 0, flags: {})
 
-proc initContext(c: var TContext) = 
+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) = 
+proc gsub(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   gsub(g, n, c)
 
-proc hasCom(n: PNode): bool = 
+proc hasCom(n: PNode): bool =
   result = false
+  if n.isNil: return false
   if n.comment != nil: return true
   case n.kind
   of nkEmpty..nkNilLit: discard
-  else: 
-    for i in countup(0, sonsLen(n) - 1): 
+  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) = 
+
+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, separator = tkComma) = 
+proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
+               theEnd: int = - 1, separator = tkComma) =
   for i in countup(start, sonsLen(n) + theEnd):
     var c = i < sonsLen(n) + theEnd
     var sublen = lsub(n.sons[i]) + ord(c)
@@ -520,54 +526,54 @@ proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
     if c:
       if g.tokens.len > oldLen:
         putWithSpace(g, separator, TokTypeToStr[separator])
-      if hasCom(n.sons[i]): 
+      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) = 
+proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
+            theEnd: int = - 1) =
   var ind: int
-  if rfInConstExpr in c.flags: 
+  if rfInConstExpr in c.flags:
     ind = g.indent + IndentWidth
-  else: 
+  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) = 
+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) = 
+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) = 
+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) = 
+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): 
+  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 = 
+proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool =
   result = n.comment != nil
-  if not result: 
+  if not result:
     # check further
-    for i in countup(start, sonsLen(n) + theEnd): 
-      if (lsub(n.sons[i]) > MaxLineLen): 
+    for i in countup(start, sonsLen(n) + theEnd):
+      if (lsub(n.sons[i]) > MaxLineLen):
         result = true
-        break 
+        break
 
 proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
   if n.kind == nkEmpty: return
@@ -587,43 +593,43 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
     gcoms(g)
     optNL(g)
     if rfLongMode in c.flags: dedent(g)
-  
-proc gif(g: var TSrcGen, n: PNode) = 
+
+proc gif(g: var TSrcGen, n: PNode) =
   var c: TContext
   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): 
+  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)
   var length = sonsLen(n)
-  for i in countup(1, length - 1): 
+  for i in countup(1, length - 1):
     optNL(g)
     gsub(g, n.sons[i], c)
 
-proc gwhile(g: var TSrcGen, n: PNode) = 
+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): 
+  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 gpattern(g: var TSrcGen, n: PNode) = 
+proc gpattern(g: var TSrcGen, n: PNode) =
   var c: TContext
   put(g, tkCurlyLe, "{")
   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)
+  gstmts(g, n, c)
   put(g, tkCurlyRi, "}")
 
-proc gpragmaBlock(g: var TSrcGen, n: PNode) = 
+proc gpragmaBlock(g: var TSrcGen, n: PNode) =
   var c: TContext
   gsub(g, n.sons[0])
   putWithSpace(g, tkColon, ":")
@@ -633,25 +639,25 @@ proc gpragmaBlock(g: var TSrcGen, n: PNode) =
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[1], c)
 
-proc gtry(g: var TSrcGen, n: PNode) = 
+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): 
+  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) = 
+proc gfor(g: var TSrcGen, n: PNode) =
   var c: TContext
   var 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): 
+      MaxLineLen):
     incl(c.flags, rfLongMode)
   gcomma(g, n, c, 0, - 3)
   put(g, tkSpaces, Space)
@@ -661,17 +667,17 @@ proc gfor(g: var TSrcGen, n: PNode) =
   gcoms(g)
   gstmts(g, n.sons[length - 1], c)
 
-proc gmacro(g: var TSrcGen, n: PNode) = 
+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): 
+  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) = 
+proc gcase(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   var length = sonsLen(n)
@@ -682,18 +688,18 @@ proc gcase(g: var TSrcGen, n: PNode) =
   gcoms(g)
   optNL(g)
   gsons(g, n, c, 1, last)
-  if last == - 2: 
+  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) = 
+proc gproc(g: var TSrcGen, n: PNode) =
   var c: TContext
   if n.sons[namePos].kind == nkSym:
     put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym))
   else:
     gsub(g, n.sons[namePos])
-  
+
   if n.sons[patternPos].kind != nkEmpty:
     gpattern(g, n.sons[patternPos])
   let oldCheckAnon = g.checkAnon
@@ -720,7 +726,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
 proc gTypeClassTy(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
-  putWithSpace(g, tkGeneric, "generic")
+  putWithSpace(g, tkConcept, "concept")
   gsons(g, n[0], c) # arglist
   gsub(g, n[1]) # pragmas
   gsub(g, n[2]) # of
@@ -730,7 +736,7 @@ proc gTypeClassTy(g: var TSrcGen, n: PNode) =
   gstmts(g, n[3], c)
   dedent(g)
 
-proc gblock(g: var TSrcGen, n: PNode) = 
+proc gblock(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   if n.sons[0].kind != nkEmpty:
@@ -739,7 +745,7 @@ proc gblock(g: var TSrcGen, n: PNode) =
   else:
     put(g, tkBlock, "block")
   putWithSpace(g, tkColon, ":")
-  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)
   # XXX I don't get why this is needed here! gstmts should already handle this!
@@ -747,17 +753,17 @@ proc gblock(g: var TSrcGen, n: PNode) =
   gstmts(g, n.sons[1], c)
   dedent(g)
 
-proc gstaticStmt(g: var TSrcGen, n: PNode) = 
+proc gstaticStmt(g: var TSrcGen, n: PNode) =
   var c: TContext
   putWithSpace(g, tkStatic, "static")
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen): 
+  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)
 
-proc gasm(g: var TSrcGen, n: PNode) = 
+proc gasm(g: var TSrcGen, n: PNode) =
   putWithSpace(g, tkAsm, "asm")
   gsub(g, n.sons[0])
   gcoms(g)
@@ -767,16 +773,16 @@ proc gident(g: var TSrcGen, n: PNode) =
   if g.checkAnon and n.kind == nkSym and sfAnon in n.sym.flags: return
   var t: TTokType
   var s = atom(n)
-  if (s[0] in lexer.SymChars): 
-    if (n.kind == nkIdent): 
+  if (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)): 
+          (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
         t = tkSymbol
-      else: 
+      else:
         t = TTokType(n.ident.id + ord(tkSymbol))
-    else: 
+    else:
       t = tkSymbol
-  else: 
+  else:
     t = tkOpr
   put(g, t, s)
   if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
@@ -786,12 +792,12 @@ proc doParamsAux(g: var TSrcGen, params: PNode) =
     put(g, tkParLe, "(")
     gsemicolon(g, params, 1)
     put(g, tkParRi, ")")
-  
-  if params.sons[0].kind != nkEmpty: 
+
+  if params.sons[0].kind != nkEmpty:
     putWithSpace(g, tkOpr, "->")
     gsub(g, params.sons[0])
 
-proc gsub(g: var TSrcGen, n: PNode, c: TContext) = 
+proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   if isNil(n): return
   var
     a: TContext
@@ -824,14 +830,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkParLe, "(")
     gcomma(g, n, 1)
     put(g, tkParRi, ")")
-  of nkCallStrLit: 
+  of nkCallStrLit:
     gsub(g, n.sons[0])
-    if n.sons[1].kind == nkRStrLit: 
+    if n.sons[1].kind == nkRStrLit:
       put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
-    else: 
+    else:
       gsub(g, n.sons[1])
   of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: gsub(g, n.sons[1])
-  of nkCast: 
+  of nkCast:
     put(g, tkCast, "cast")
     put(g, tkBracketLe, "[")
     gsub(g, n.sons[0])
@@ -839,16 +845,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkParLe, "(")
     gsub(g, n.sons[1])
     put(g, tkParRi, ")")
-  of nkAddr: 
+  of nkAddr:
     put(g, tkAddr, "addr")
-    put(g, tkParLe, "(")
-    gsub(g, n.sons[0])
-    put(g, tkParRi, ")")
+    if n.len > 0:
+      put(g, tkParLe, "(")
+      gsub(g, n.sons[0])
+      put(g, tkParRi, ")")
   of nkStaticExpr:
     put(g, tkStatic, "static")
     put(g, tkSpaces, Space)
     gsub(g, n.sons[0])
-  of nkBracketExpr: 
+  of nkBracketExpr:
     gsub(g, n.sons[0])
     put(g, tkBracketLe, "[")
     gcomma(g, n, 1)
@@ -858,41 +865,41 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkCurlyLe, "{")
     gcomma(g, n, 1)
     put(g, tkCurlyRi, "}")
-  of nkPragmaExpr: 
+  of nkPragmaExpr:
     gsub(g, n.sons[0])
     gcomma(g, n, 1)
-  of nkCommand: 
+  of nkCommand:
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     gcomma(g, n, 1)
-  of nkExprEqExpr, nkAsgn, nkFastAsgn: 
+  of nkExprEqExpr, nkAsgn, nkFastAsgn:
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     putWithSpace(g, tkEquals, "=")
     gsub(g, n.sons[1])
-  of nkChckRangeF: 
+  of nkChckRangeF:
     put(g, tkSymbol, "chckRangeF")
     put(g, tkParLe, "(")
     gcomma(g, n)
     put(g, tkParRi, ")")
-  of nkChckRange64: 
+  of nkChckRange64:
     put(g, tkSymbol, "chckRange64")
     put(g, tkParLe, "(")
     gcomma(g, n)
     put(g, tkParRi, ")")
-  of nkChckRange: 
+  of nkChckRange:
     put(g, tkSymbol, "chckRange")
     put(g, tkParLe, "(")
     gcomma(g, n)
     put(g, tkParRi, ")")
-  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString: 
+  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
     if sonsLen(n) >= 1: gsub(g, n.sons[0])
     put(g, tkParLe, "(")
     gcomma(g, n, 1)
     put(g, tkParRi, ")")
   of nkClosedSymChoice, nkOpenSymChoice:
     put(g, tkParLe, "(")
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       if i > 0: put(g, tkOpr, "|")
       if n.sons[i].kind == nkSym:
         let s = n[i].sym
@@ -903,11 +910,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       else:
         gsub(g, n.sons[i], c)
     put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
-  of nkPar, nkClosure: 
+  of nkPar, nkClosure:
     put(g, tkParLe, "(")
     gcomma(g, n, c)
     put(g, tkParRi, ")")
-  of nkCurly: 
+  of nkCurly:
     put(g, tkCurlyLe, "{")
     gcomma(g, n, c)
     put(g, tkCurlyRi, "}")
@@ -922,14 +929,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkBracketLe, "[")
     gcomma(g, n, c)
     put(g, tkBracketRi, "]")
-  of nkDotExpr: 
+  of nkDotExpr:
     gsub(g, n.sons[0])
     put(g, tkDot, ".")
     gsub(g, n.sons[1])
-  of nkBind: 
+  of nkBind:
     putWithSpace(g, tkBind, "bind")
     gsub(g, n.sons[0])
-  of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: 
+  of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
     gsub(g, n.sons[0])
   of nkLambda:
     putWithSpace(g, tkProc, "proc")
@@ -947,34 +954,34 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkConstDef, nkIdentDefs:
     gcomma(g, n, 0, -3)
     var L = sonsLen(n)
-    if n.sons[L - 2].kind != nkEmpty: 
+    if L >= 2 and n.sons[L - 2].kind != nkEmpty:
       putWithSpace(g, tkColon, ":")
       gsub(g, n.sons[L - 2])
-    if n.sons[L - 1].kind != nkEmpty: 
+    if L >= 1 and n.sons[L - 1].kind != nkEmpty:
       put(g, tkSpaces, Space)
       putWithSpace(g, tkEquals, "=")
       gsub(g, n.sons[L - 1], c)
-  of nkVarTuple: 
+  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: 
+  of nkExprColonExpr:
     gsub(g, n.sons[0])
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[1])
-  of nkInfix: 
+  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): 
+    if not fits(g, lsub(n.sons[2]) + lsub(n.sons[0]) + 1):
       optNL(g, g.indent + longIndentWid)
-    else: 
+    else:
       put(g, tkSpaces, Space)
     gsub(g, n.sons[2])
-  of nkPrefix: 
+  of nkPrefix:
     gsub(g, n.sons[0])
     if n.len > 1:
       put(g, tkSpaces, Space)
@@ -984,10 +991,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
         put(g, tkParRi, ")")
       else:
         gsub(g, n.sons[1])
-  of nkPostfix: 
+  of nkPostfix:
     gsub(g, n.sons[1])
     gsub(g, n.sons[0])
-  of nkRange: 
+  of nkRange:
     gsub(g, n.sons[0])
     put(g, tkDotDot, "..")
     gsub(g, n.sons[1])
@@ -1001,43 +1008,43 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       put(g, tkSpaces, Space)
       gsub(g, n.sons[i])
     put(g, tkAccent, "`")
-  of nkIfExpr: 
+  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: 
+  of nkElifExpr:
     putWithSpace(g, tkElif, " elif")
     gsub(g, n.sons[0])
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[1])
-  of nkElseExpr: 
+  of nkElseExpr:
     put(g, tkElse, " else")
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[0])
   of nkTypeOfExpr:
     putWithSpace(g, tkType, "type")
     if n.len > 0: gsub(g, n.sons[0])
-  of nkRefTy: 
+  of nkRefTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkRef, "ref")
       gsub(g, n.sons[0])
     else:
       put(g, tkRef, "ref")
-  of nkPtrTy: 
+  of nkPtrTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkPtr, "ptr")
       gsub(g, n.sons[0])
     else:
       put(g, tkPtr, "ptr")
-  of nkVarTy: 
+  of nkVarTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkVar, "var")
       gsub(g, n.sons[0])
     else:
       put(g, tkVar, "var")
-  of nkDistinctTy: 
+  of nkDistinctTy:
     if n.len > 0:
       putWithSpace(g, tkDistinct, "distinct")
       gsub(g, n.sons[0])
@@ -1049,14 +1056,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
         gcomma(g, n[1])
     else:
       put(g, tkDistinct, "distinct")
-  of nkTypeDef: 
+  of nkTypeDef:
     gsub(g, n.sons[0])
     gsub(g, n.sons[1])
     put(g, tkSpaces, Space)
-    if n.sons[2].kind != nkEmpty: 
+    if n.sons[2].kind != nkEmpty:
       putWithSpace(g, tkEquals, "=")
       gsub(g, n.sons[2])
-  of nkObjectTy: 
+  of nkObjectTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkObject, "object")
       gsub(g, n.sons[0])
@@ -1065,18 +1072,18 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       gsub(g, n.sons[2])
     else:
       put(g, tkObject, "object")
-  of nkRecList: 
+  of nkRecList:
     indentNL(g)
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       optNL(g)
       gsub(g, n.sons[i], c)
       gcoms(g)
     dedent(g)
     putNL(g)
-  of nkOfInherit: 
+  of nkOfInherit:
     putWithSpace(g, tkOf, "of")
     gsub(g, n.sons[0])
-  of nkProcTy: 
+  of nkProcTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkProc, "proc")
       gsub(g, n.sons[0])
@@ -1095,7 +1102,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkBracketLe, "[")
     if n.len > 0:
       gsub(g, n.sons[0])
-    put(g, tkBracketRi, "]")    
+    put(g, tkBracketRi, "]")
   of nkEnumTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkEnum, "enum")
@@ -1107,16 +1114,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       dedent(g)
     else:
       put(g, tkEnum, "enum")
-  of nkEnumFieldDef: 
+  of nkEnumFieldDef:
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     putWithSpace(g, tkEquals, "=")
     gsub(g, n.sons[1])
   of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext)
-  of nkIfStmt: 
+  of nkIfStmt:
     putWithSpace(g, tkIf, "if")
     gif(g, n)
-  of nkWhen, nkRecWhen: 
+  of nkWhen, nkRecWhen:
     putWithSpace(g, tkWhen, "when")
     gif(g, n)
   of nkWhileStmt: gwhile(g, n)
@@ -1127,27 +1134,27 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkBlockStmt, nkBlockExpr: gblock(g, n)
   of nkStaticStmt: gstaticStmt(g, n)
   of nkAsmStmt: gasm(g, n)
-  of nkProcDef: 
+  of nkProcDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
     gproc(g, n)
   of nkConverterDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
     gproc(g, n)
-  of nkMethodDef: 
+  of nkMethodDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method")
     gproc(g, n)
-  of nkIteratorDef: 
+  of nkIteratorDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator")
     gproc(g, n)
-  of nkMacroDef: 
+  of nkMacroDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro")
     gproc(g, n)
-  of nkTemplateDef: 
+  of nkTemplateDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template")
     gproc(g, n)
-  of nkTypeSection: 
+  of nkTypeSection:
     gsection(g, n, emptyContext, tkType, "type")
-  of nkConstSection: 
+  of nkConstSection:
     initContext(a)
     incl(a.flags, rfInConstExpr)
     gsection(g, n, a, tkConst, "const")
@@ -1156,40 +1163,45 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     if L == 0: return
     if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
     else: putWithSpace(g, tkLet, "let")
-    if L > 1: 
+    if L > 1:
       gcoms(g)
       indentNL(g)
-      for i in countup(0, L - 1): 
+      for i in countup(0, L - 1):
         optNL(g)
         gsub(g, n.sons[i])
         gcoms(g)
       dedent(g)
-    else: 
+    else:
       gsub(g, n.sons[0])
-  of nkReturnStmt: 
+  of nkReturnStmt:
     putWithSpace(g, tkReturn, "return")
     gsub(g, n.sons[0])
-  of nkRaiseStmt: 
+  of nkRaiseStmt:
     putWithSpace(g, tkRaise, "raise")
     gsub(g, n.sons[0])
-  of nkYieldStmt: 
+  of nkYieldStmt:
     putWithSpace(g, tkYield, "yield")
     gsub(g, n.sons[0])
-  of nkDiscardStmt: 
+  of nkDiscardStmt:
     putWithSpace(g, tkDiscard, "discard")
     gsub(g, n.sons[0])
-  of nkBreakStmt: 
+  of nkBreakStmt:
     putWithSpace(g, tkBreak, "break")
     gsub(g, n.sons[0])
-  of nkContinueStmt: 
+  of nkContinueStmt:
     putWithSpace(g, tkContinue, "continue")
     gsub(g, n.sons[0])
-  of nkPragma: 
+  of nkPragma:
     if renderNoPragmas notin g.flags:
-      put(g, tkSpaces, Space)
-      put(g, tkCurlyDotLe, "{.")
-      gcomma(g, n, emptyContext)
-      put(g, tkCurlyDotRi, ".}")
+      if g.inPragma <= 0:
+        inc g.inPragma
+        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")
@@ -1211,24 +1223,24 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gcommaAux(g, n, g.indent, 1)
     gcoms(g)
     putNL(g)
-  of nkFromStmt: 
+  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: 
+  of nkIncludeStmt:
     putWithSpace(g, tkInclude, "include")
     gcoms(g)
     indentNL(g)
     gcommaAux(g, n, g.indent)
     dedent(g)
     putNL(g)
-  of nkCommentStmt: 
+  of nkCommentStmt:
     gcoms(g)
     optNL(g)
-  of nkOfBranch: 
+  of nkOfBranch:
     optNL(g)
     putWithSpace(g, tkOf, "of")
     gcomma(g, n, c, 0, - 2)
@@ -1240,55 +1252,59 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkSpaces, Space)
     putWithSpace(g, tkAs, "as")
     gsub(g, n.sons[1])
-  of nkBindStmt: 
+  of nkBindStmt:
     putWithSpace(g, tkBind, "bind")
     gcomma(g, n, c)
   of nkMixinStmt:
     putWithSpace(g, tkMixin, "mixin")
     gcomma(g, n, c)
-  of nkElifBranch: 
+  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: 
+  of nkElse:
     optNL(g)
     put(g, tkElse, "else")
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, n.sons[0], c)
-  of nkFinally: 
+  of nkFinally, nkDefer:
     optNL(g)
-    put(g, tkFinally, "finally")
+    if n.kind == nkFinally:
+      put(g, tkFinally, "finally")
+    else:
+      put(g, tkDefer, "defer")
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, n.sons[0], c)
-  of nkExceptBranch: 
+  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: 
+  of nkGenericParams:
     put(g, tkBracketLe, "[")
     gcomma(g, n)
     put(g, tkBracketRi, "]")
-  of nkFormalParams: 
+  of nkFormalParams:
     put(g, tkParLe, "(")
     gsemicolon(g, n, 1)
     put(g, tkParRi, ")")
-    if n.sons[0].kind != nkEmpty: 
+    if n.sons[0].kind != nkEmpty:
       putWithSpace(g, tkColon, ":")
       gsub(g, n.sons[0])
-  of nkTupleTy: 
+  of nkTupleTy:
+    put(g, tkTuple, "tuple")
+    put(g, tkBracketLe, "[")
+    gcomma(g, n)
+    put(g, tkBracketRi, "]")
+  of nkTupleClassTy:
     put(g, tkTuple, "tuple")
-    if sonsLen(n) > 0:
-      put(g, tkBracketLe, "[")
-      gcomma(g, n)
-      put(g, tkBracketRi, "]")
   of nkMetaNode_Obsolete:
     put(g, tkParLe, "(META|")
     gsub(g, n.sons[0])
@@ -1300,17 +1316,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gsons(g, n, c)
   of nkTypeClassTy:
     gTypeClassTy(g, n)
-  else: 
-    #nkNone, nkExplicitTypeListCall: 
+  else:
+    #nkNone, nkExplicitTypeListCall:
     internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
 
-proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string = 
+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, 
+proc renderModule(n: PNode, filename: string,
                   renderFlags: TRenderFlags = {}) =
   var
     f: File
@@ -1330,18 +1346,18 @@ proc renderModule(n: PNode, filename: string,
     write(f, g.buf)
     close(f)
   else:
-    rawMessage(errCannotOpenFile, filename)    
+    rawMessage(errCannotOpenFile, filename)
 
-proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = 
+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) = 
-  if r.idx < len(r.tokens): 
+proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) =
+  if r.idx < len(r.tokens):
     kind = r.tokens[r.idx].kind
     var 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: 
+  else:
     kind = tkEof