summary refs log tree commit diff stats
path: root/compiler/pbraces.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/pbraces.nim')
-rw-r--r--compiler/pbraces.nim1790
1 files changed, 0 insertions, 1790 deletions
diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim
deleted file mode 100644
index eba6f0b62..000000000
--- a/compiler/pbraces.nim
+++ /dev/null
@@ -1,1790 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2017 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-# This module implements the parser of the braces Nim syntax.
-
-import
-  llstream, lexer, idents, strutils, ast, astalgo, msgs
-
-from parser import TParser
-
-proc getTok(p: var TParser) =
-  ## Get the next token from the parser's lexer, and store it in the parser's
-  ## `tok` member.
-  rawGetTok(p.lex, p.tok)
-
-proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream;
-                 cache: IdentCache) =
-  ## Open a parser, using the given arguments to set up its internal state.
-  ##
-  initToken(p.tok)
-  openLexer(p.lex, fileIdx, inputStream, cache)
-  getTok(p)                   # read the first token
-  p.lex.allowTabs = true
-
-proc openParser*(p: var TParser, filename: string, inputStream: PLLStream;
-                 cache: IdentCache) =
-  openParser(p, filename.fileInfoIdx, inputStream, cache)
-
-proc closeParser*(p: var TParser) =
-  ## Close a parser, freeing up its resources.
-  closeLexer(p.lex)
-
-proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
-  ## Produce and emit the parser message `arg` to output.
-  lexMessageTok(p.lex, msg, p.tok, arg)
-
-proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
-  ## Produce and emit a parser message to output about the token `tok`
-  parMessage(p, msg, prettyTok(tok))
-
-proc rawSkipComment(p: var TParser, node: PNode) =
-  if p.tok.tokType == tkComment:
-    if node != nil:
-      if node.comment == nil: node.comment = ""
-      add(node.comment, p.tok.literal)
-    else:
-      parMessage(p, errInternal, "skipComment")
-    getTok(p)
-
-proc skipComment(p: var TParser, node: PNode) =
-  rawSkipComment(p, node)
-
-proc flexComment(p: var TParser, node: PNode) =
-  rawSkipComment(p, node)
-
-proc skipInd(p: var TParser) = discard
-proc optPar(p: var TParser) = discard
-
-proc optInd(p: var TParser, n: PNode) =
-  skipComment(p, n)
-
-proc getTokNoInd(p: var TParser) =
-  getTok(p)
-
-proc expectIdentOrKeyw(p: TParser) =
-  if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
-    lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
-
-proc expectIdent(p: TParser) =
-  if p.tok.tokType != tkSymbol:
-    lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
-
-proc eat(p: var TParser, tokType: TTokType) =
-  ## Move the parser to the next token if the current token is of type
-  ## `tokType`, otherwise error.
-  if p.tok.tokType == tokType:
-    getTok(p)
-  else:
-    lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType])
-
-proc parLineInfo(p: TParser): TLineInfo =
-  ## Retrieve the line information associated with the parser's current state.
-  result = getLineInfo(p.lex, p.tok)
-
-proc indAndComment(p: var TParser, n: PNode) =
-  rawSkipComment(p, n)
-
-proc newNodeP(kind: TNodeKind, p: TParser): PNode =
-  result = newNodeI(kind, parLineInfo(p))
-
-proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode =
-  result = newNodeP(kind, p)
-  result.intVal = intVal
-
-proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat,
-                   p: TParser): PNode =
-  result = newNodeP(kind, p)
-  result.floatVal = floatVal
-
-proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode =
-  result = newNodeP(kind, p)
-  result.strVal = strVal
-
-proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
-  result = newNodeP(nkIdent, p)
-  result.ident = ident
-
-proc parseExpr(p: var TParser): PNode
-proc parseStmt(p: var TParser): PNode
-proc parseTypeDesc(p: var TParser): PNode
-proc parseDoBlocks(p: var TParser, call: PNode)
-proc parseParamList(p: var TParser, retColon = true): PNode
-proc parseStmtPragma(p: var TParser): PNode
-proc parseCase(p: var TParser): PNode
-proc parseTry(p: var TParser): PNode
-
-proc isSigilLike(tok: TToken): bool {.inline.} =
-  result = tok.tokType == tkOpr and tok.ident.s[0] == '@'
-
-proc isAt(tok: TToken): bool {.inline.} =
-  tok.tokType == tkOpr and tok.ident.s == "@" and tok.strongSpaceB == 0
-
-proc isRightAssociative(tok: TToken): bool {.inline.} =
-  ## Determines whether the token is right assocative.
-  result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
-  # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
-
-proc getPrecedence(tok: TToken): int =
-  ## Calculates the precedence of the given token.
-  template considerStrongSpaces(x): untyped = x
-
-  case tok.tokType
-  of tkOpr:
-    let L = tok.ident.s.len
-    let relevantChar = tok.ident.s[0]
-
-    # arrow like?
-    if L > 1 and tok.ident.s[L-1] == '>' and
-      tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
-
-    template considerAsgn(value: untyped) =
-      result = if tok.ident.s[L-1] == '=': 1 else: value
-
-    case relevantChar
-    of '$', '^': considerAsgn(10)
-    of '*', '%', '/', '\\': considerAsgn(9)
-    of '~': result = 8
-    of '+', '-', '|': considerAsgn(8)
-    of '&': considerAsgn(7)
-    of '=', '<', '>', '!': result = 5
-    of '.': considerAsgn(6)
-    of '?': result = 2
-    else: considerAsgn(2)
-  of tkDiv, tkMod, tkShl, tkShr: result = 9
-  of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
-  of tkDotDot: result = 6
-  of tkAnd: result = 4
-  of tkOr, tkXor, tkPtr, tkRef: result = 3
-  else: return -10
-  result = considerStrongSpaces(result)
-
-proc isOperator(tok: TToken): bool =
-  ## Determines if the given token is an operator type token.
-  tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
-                  tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
-
-proc isUnary(p: TParser): bool =
-  ## Check if the current parser token is a unary operator
-  if p.tok.tokType in {tkOpr, tkDotDot}:
-      result = true
-
-proc checkBinary(p: TParser) {.inline.} =
-  ## Check if the current parser token is a binary operator.
-  # we don't check '..' here as that's too annoying
-  discard
-
-#| module = stmt ^* (';' / IND{=})
-#|
-#| comma = ',' COMMENT?
-#| semicolon = ';' COMMENT?
-#| colon = ':' COMMENT?
-#| colcom = ':' COMMENT?
-#|
-#| operator =  OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9
-#|          | 'or' | 'xor' | 'and'
-#|          | 'is' | 'isnot' | 'in' | 'notin' | 'of'
-#|          | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..'
-#|
-#| prefixOperator = operator
-#|
-#| optInd = COMMENT?
-#| optPar = (IND{>} | IND{=})?
-#|
-#| simpleExpr = arrowExpr (OP0 optInd arrowExpr)*
-#| arrowExpr = assignExpr (OP1 optInd assignExpr)*
-#| assignExpr = orExpr (OP2 optInd orExpr)*
-#| orExpr = andExpr (OP3 optInd andExpr)*
-#| andExpr = cmpExpr (OP4 optInd cmpExpr)*
-#| cmpExpr = sliceExpr (OP5 optInd sliceExpr)*
-#| sliceExpr = ampExpr (OP6 optInd ampExpr)*
-#| ampExpr = plusExpr (OP7 optInd plusExpr)*
-#| plusExpr = mulExpr (OP8 optInd mulExpr)*
-#| mulExpr = dollarExpr (OP9 optInd dollarExpr)*
-#| dollarExpr = primary (OP10 optInd primary)*
-
-proc colcom(p: var TParser, n: PNode) =
-  skipComment(p, n)
-
-proc parseSymbol(p: var TParser, allowNil = false): PNode =
-  #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
-  #|        | IDENT | 'addr' | 'type'
-  case p.tok.tokType
-  of tkSymbol, tkAddr, tkType:
-    result = newIdentNodeP(p.tok.ident, p)
-    getTok(p)
-  of tkAccent:
-    result = newNodeP(nkAccQuoted, p)
-    getTok(p)
-    while true:
-      case p.tok.tokType
-      of tkAccent:
-        if result.len == 0:
-          parMessage(p, errIdentifierExpected, p.tok)
-        break
-      of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi:
-        var accm = ""
-        while p.tok.tokType in {tkOpr, tkDot, tkDotDot, tkEquals,
-                                tkParLe..tkParDotRi}:
-          accm.add(tokToStr(p.tok))
-          getTok(p)
-        result.add(newIdentNodeP(p.lex.cache.getIdent(accm), p))
-      of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit:
-        result.add(newIdentNodeP(p.lex.cache.getIdent(tokToStr(p.tok)), p))
-        getTok(p)
-      else:
-        parMessage(p, errIdentifierExpected, p.tok)
-        break
-    eat(p, tkAccent)
-  else:
-    if allowNil and p.tok.tokType == tkNil:
-      result = newNodeP(nkNilLit, p)
-      getTok(p)
-    else:
-      parMessage(p, errIdentifierExpected, p.tok)
-      # BUGFIX: We must consume a token here to prevent endless loops!
-      # But: this really sucks for idetools and keywords, so we don't do it
-      # if it is a keyword:
-      if not isKeyword(p.tok.tokType): getTok(p)
-      result = ast.emptyNode
-
-proc colonOrEquals(p: var TParser, a: PNode): PNode =
-  if p.tok.tokType == tkColon:
-    result = newNodeP(nkExprColonExpr, p)
-    getTok(p)
-    #optInd(p, result)
-    addSon(result, a)
-    addSon(result, parseExpr(p))
-  elif p.tok.tokType == tkEquals:
-    result = newNodeP(nkExprEqExpr, p)
-    getTok(p)
-    #optInd(p, result)
-    addSon(result, a)
-    addSon(result, parseExpr(p))
-  else:
-    result = a
-
-proc exprColonEqExpr(p: var TParser): PNode =
-  #| exprColonEqExpr = expr (':'|'=' expr)?
-  var a = parseExpr(p)
-  result = colonOrEquals(p, a)
-
-proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
-  #| exprList = expr ^+ comma
-  getTok(p)
-  optInd(p, result)
-  while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
-    var a = parseExpr(p)
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-
-proc dotExpr(p: var TParser, a: PNode): PNode =
-  #| dotExpr = expr '.' optInd symbol
-  var info = p.parLineInfo
-  getTok(p)
-  result = newNodeI(nkDotExpr, info)
-  optInd(p, result)
-  addSon(result, a)
-  addSon(result, parseSymbol(p))
-
-proc qualifiedIdent(p: var TParser): PNode =
-  #| qualifiedIdent = symbol ('.' optInd symbol)?
-  result = parseSymbol(p)
-  if p.tok.tokType == tkDot: result = dotExpr(p, result)
-
-proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
-  assert(endTok in {tkCurlyLe, tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
-  getTok(p)
-  optInd(p, result)
-  while p.tok.tokType != endTok and p.tok.tokType != tkEof:
-    var a = exprColonEqExpr(p)
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    skipComment(p, a)
-  optPar(p)
-  eat(p, endTok)
-
-proc exprColonEqExprList(p: var TParser, kind: TNodeKind,
-                         endTok: TTokType): PNode =
-  #| exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
-  result = newNodeP(kind, p)
-  exprColonEqExprListAux(p, endTok, result)
-
-proc setOrTableConstr(p: var TParser): PNode =
-  result = newNodeP(nkCurly, p)
-  getTok(p)
-  optInd(p, result)
-  if p.tok.tokType == tkColon:
-    getTok(p) # skip ':'
-    result.kind = nkTableConstr
-  else:
-    while p.tok.tokType notin {tkBracketDotRi, tkEof}:
-      var a = exprColonEqExpr(p)
-      if a.kind == nkExprColonExpr: result.kind = nkTableConstr
-      addSon(result, a)
-      if p.tok.tokType != tkComma: break
-      getTok(p)
-      skipComment(p, a)
-  optPar(p)
-  eat(p, tkBracketDotRi)
-
-proc parseCast(p: var TParser): PNode =
-  #| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
-  result = newNodeP(nkCast, p)
-  getTok(p)
-  eat(p, tkBracketLe)
-  optInd(p, result)
-  addSon(result, parseTypeDesc(p))
-  optPar(p)
-  eat(p, tkBracketRi)
-  eat(p, tkParLe)
-  optInd(p, result)
-  addSon(result, parseExpr(p))
-  optPar(p)
-  eat(p, tkParRi)
-
-proc setBaseFlags(n: PNode, base: TNumericalBase) =
-  case base
-  of base10: discard
-  of base2: incl(n.flags, nfBase2)
-  of base8: incl(n.flags, nfBase8)
-  of base16: incl(n.flags, nfBase16)
-
-proc parseGStrLit(p: var TParser, a: PNode): PNode =
-  case p.tok.tokType
-  of tkGStrLit:
-    result = newNodeP(nkCallStrLit, p)
-    addSon(result, a)
-    addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
-    getTok(p)
-  of tkGTripleStrLit:
-    result = newNodeP(nkCallStrLit, p)
-    addSon(result, a)
-    addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p))
-    getTok(p)
-  else:
-    result = a
-
-type
-  TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
-
-proc complexOrSimpleStmt(p: var TParser): PNode
-proc simpleExpr(p: var TParser, mode = pmNormal): PNode
-
-proc semiStmtList(p: var TParser, result: PNode) =
-  inc p.inSemiStmtList
-  result.add(complexOrSimpleStmt(p))
-  while p.tok.tokType == tkSemiColon:
-    getTok(p)
-    optInd(p, result)
-    result.add(complexOrSimpleStmt(p))
-  dec p.inSemiStmtList
-  result.kind = nkStmtListExpr
-
-proc parsePar(p: var TParser): PNode =
-  #| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
-  #|         | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
-  #|         | 'when' | 'var' | 'mixin'
-  #| par = '(' optInd
-  #|           ( &parKeyw complexOrSimpleStmt ^+ ';'
-  #|           | ';' complexOrSimpleStmt ^+ ';'
-  #|           | pragmaStmt
-  #|           | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )
-  #|                        | (':' expr (',' exprColonEqExpr     ^+ ',' )? ) ) )
-  #|           optPar ')'
-  #
-  # unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a
-  # leading ';' could be used to enforce a 'stmt' context ...
-  result = newNodeP(nkPar, p)
-  getTok(p)
-  optInd(p, result)
-  if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
-                       tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
-                       tkConst, tkLet, tkWhen, tkVar,
-                       tkMixin}:
-    # XXX 'bind' used to be an expression, so we exclude it here;
-    # tests/reject/tbind2 fails otherwise.
-    semiStmtList(p, result)
-  elif p.tok.tokType == tkSemiColon:
-    # '(;' enforces 'stmt' context:
-    getTok(p)
-    optInd(p, result)
-    semiStmtList(p, result)
-  elif p.tok.tokType == tkCurlyDotLe:
-    result.add(parseStmtPragma(p))
-  elif p.tok.tokType != tkParRi:
-    var a = simpleExpr(p)
-    if p.tok.tokType == tkEquals:
-      # special case: allow assignments
-      getTok(p)
-      optInd(p, result)
-      let b = parseExpr(p)
-      let asgn = newNodeI(nkAsgn, a.info, 2)
-      asgn.sons[0] = a
-      asgn.sons[1] = b
-      result.add(asgn)
-      if p.tok.tokType == tkSemiColon:
-        semiStmtList(p, result)
-    elif p.tok.tokType == tkSemiColon:
-      # stmt context:
-      result.add(a)
-      semiStmtList(p, result)
-    else:
-      a = colonOrEquals(p, a)
-      result.add(a)
-      if p.tok.tokType == tkComma:
-        getTok(p)
-        skipComment(p, a)
-        while p.tok.tokType != tkParRi and p.tok.tokType != tkEof:
-          var a = exprColonEqExpr(p)
-          addSon(result, a)
-          if p.tok.tokType != tkComma: break
-          getTok(p)
-          skipComment(p, a)
-  optPar(p)
-  eat(p, tkParRi)
-
-proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
-  #| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
-  #|           | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
-  #|           | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
-  #|           | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
-  #|           | CHAR_LIT
-  #|           | NIL
-  #| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
-  #| identOrLiteral = generalizedLit | symbol | literal
-  #|                | par | arrayConstr | setOrTableConstr
-  #|                | castExpr
-  #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
-  #| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
-  case p.tok.tokType
-  of tkSymbol, tkType, tkAddr:
-    result = newIdentNodeP(p.tok.ident, p)
-    getTok(p)
-    result = parseGStrLit(p, result)
-  of tkAccent:
-    result = parseSymbol(p)       # literals
-  of tkIntLit:
-    result = newIntNodeP(nkIntLit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkInt8Lit:
-    result = newIntNodeP(nkInt8Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkInt16Lit:
-    result = newIntNodeP(nkInt16Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkInt32Lit:
-    result = newIntNodeP(nkInt32Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkInt64Lit:
-    result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkUIntLit:
-    result = newIntNodeP(nkUIntLit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkUInt8Lit:
-    result = newIntNodeP(nkUInt8Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkUInt16Lit:
-    result = newIntNodeP(nkUInt16Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkUInt32Lit:
-    result = newIntNodeP(nkUInt32Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkUInt64Lit:
-    result = newIntNodeP(nkUInt64Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkFloatLit:
-    result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkFloat32Lit:
-    result = newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkFloat64Lit:
-    result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkFloat128Lit:
-    result = newFloatNodeP(nkFloat128Lit, p.tok.fNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkStrLit:
-    result = newStrNodeP(nkStrLit, p.tok.literal, p)
-    getTok(p)
-  of tkRStrLit:
-    result = newStrNodeP(nkRStrLit, p.tok.literal, p)
-    getTok(p)
-  of tkTripleStrLit:
-    result = newStrNodeP(nkTripleStrLit, p.tok.literal, p)
-    getTok(p)
-  of tkCharLit:
-    result = newIntNodeP(nkCharLit, ord(p.tok.literal[0]), p)
-    getTok(p)
-  of tkNil:
-    result = newNodeP(nkNilLit, p)
-    getTok(p)
-  of tkParLe:
-    # () constructor
-    if mode in {pmTypeDesc, pmTypeDef}:
-      result = exprColonEqExprList(p, nkPar, tkParRi)
-    else:
-      result = parsePar(p)
-  of tkBracketDotLe:
-    # {} constructor
-    result = setOrTableConstr(p)
-  of tkBracketLe:
-    # [] constructor
-    result = exprColonEqExprList(p, nkBracket, tkBracketRi)
-  of tkCast:
-    result = parseCast(p)
-  else:
-    parMessage(p, errExprExpected, p.tok)
-    getTok(p)  # we must consume a token here to prevend endless loops!
-    result = ast.emptyNode
-
-proc namedParams(p: var TParser, callee: PNode,
-                 kind: TNodeKind, endTok: TTokType): PNode =
-  let a = callee
-  result = newNodeP(kind, p)
-  addSon(result, a)
-  exprColonEqExprListAux(p, endTok, result)
-
-proc parseMacroColon(p: var TParser, x: PNode): PNode
-proc primarySuffix(p: var TParser, r: PNode): PNode =
-  #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
-  #|       | doBlocks
-  #|       | '.' optInd symbol generalizedLit?
-  #|       | '[' optInd indexExprList optPar ']'
-  #|       | '{' optInd indexExprList optPar '}'
-  #|       | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
-  result = r
-
-  template somePar() = discard
-  while p.tok.indent < 0:
-    case p.tok.tokType
-    of tkParLe:
-      somePar()
-      result = namedParams(p, result, nkCall, tkParRi)
-      if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
-        result.kind = nkObjConstr
-      else:
-        parseDoBlocks(p, result)
-    of tkDo:
-      var a = result
-      result = newNodeP(nkCall, p)
-      addSon(result, a)
-      parseDoBlocks(p, result)
-    of tkDot:
-      result = dotExpr(p, result)
-      result = parseGStrLit(p, result)
-    of tkBracketLe:
-      somePar()
-      result = namedParams(p, result, nkBracketExpr, tkBracketRi)
-    of tkBracketDotLe:
-      somePar()
-      result = namedParams(p, result, nkCurlyExpr, tkBracketDotRi)
-    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType:
-      if p.inPragma == 0:
-        # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
-        # solution, but pragmas.nim can't handle that
-        let a = result
-        result = newNodeP(nkCommand, p)
-        addSon(result, a)
-        when true:
-          addSon result, parseExpr(p)
-        else:
-          while p.tok.tokType != tkEof:
-            let x = parseExpr(p)
-            addSon(result, x)
-            if p.tok.tokType != tkComma: break
-            getTok(p)
-            optInd(p, x)
-          if p.tok.tokType == tkDo:
-            parseDoBlocks(p, result)
-          else:
-            result = parseMacroColon(p, result)
-      break
-    else:
-      break
-
-proc primary(p: var TParser, mode: TPrimaryMode): PNode
-proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
-
-proc parseOperators(p: var TParser, headNode: PNode,
-                    limit: int, mode: TPrimaryMode): PNode =
-  result = headNode
-  # expand while operators have priorities higher than 'limit'
-  var opPrec = getPrecedence(p.tok)
-  let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
-  # the operator itself must not start on a new line:
-  while opPrec >= limit and p.tok.indent < 0 and not isAt(p.tok):
-    checkBinary(p)
-    var leftAssoc = 1-ord(isRightAssociative(p.tok))
-    var a = newNodeP(nkInfix, p)
-    var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
-    getTok(p)
-    optInd(p, a)
-    # read sub-expression with higher priority:
-    var b = simpleExprAux(p, opPrec + leftAssoc, modeB)
-    addSon(a, opNode)
-    addSon(a, result)
-    addSon(a, b)
-    result = a
-    opPrec = getPrecedence(p.tok)
-
-proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
-  result = primary(p, mode)
-  result = parseOperators(p, result, limit, mode)
-
-proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
-  result = simpleExprAux(p, -1, mode)
-
-proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
-  #| condExpr = expr colcom expr optInd
-  #|         ('elif' expr colcom expr optInd)*
-  #|          'else' colcom expr
-  #| ifExpr = 'if' condExpr
-  #| whenExpr = 'when' condExpr
-  result = newNodeP(kind, p)
-  while true:
-    getTok(p)                 # skip `if`, `elif`
-    var branch = newNodeP(nkElifExpr, p)
-    addSon(branch, parseExpr(p))
-    colcom(p, branch)
-    addSon(branch, parseExpr(p))
-    optInd(p, branch)
-    addSon(result, branch)
-    if p.tok.tokType != tkElif: break
-  var branch = newNodeP(nkElseExpr, p)
-  eat(p, tkElse)
-  colcom(p, branch)
-  addSon(branch, parseExpr(p))
-  addSon(result, branch)
-
-proc parsePragma(p: var TParser): PNode =
-  result = newNodeP(nkPragma, p)
-  inc p.inPragma
-  if isAt(p.tok):
-    while isAt(p.tok):
-      getTok(p)
-      var a = parseExpr(p)
-      optInd(p, a)
-      if a.kind in nkCallKinds and a.len == 2:
-        let repaired = newNodeI(nkExprColonExpr, a.info)
-        repaired.add a[0]
-        repaired.add a[1]
-        a = repaired
-      addSon(result, a)
-      skipComment(p, a)
-  else:
-    getTok(p)
-    optInd(p, result)
-    while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
-      var a = exprColonEqExpr(p)
-      addSon(result, a)
-      if p.tok.tokType == tkComma:
-        getTok(p)
-        skipComment(p, a)
-    optPar(p)
-    if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
-    else: parMessage(p, errTokenExpected, ".}")
-  dec p.inPragma
-
-proc identVis(p: var TParser; allowDot=false): PNode =
-  #| identVis = symbol opr?  # postfix position
-  #| identVisDot = symbol '.' optInd symbol opr?
-  var a = parseSymbol(p)
-  if p.tok.tokType == tkOpr:
-    result = newNodeP(nkPostfix, p)
-    addSon(result, newIdentNodeP(p.tok.ident, p))
-    addSon(result, a)
-    getTok(p)
-  elif p.tok.tokType == tkDot and allowDot:
-    result = dotExpr(p, a)
-  else:
-    result = a
-
-proc identWithPragma(p: var TParser; allowDot=false): PNode =
-  #| identWithPragma = identVis pragma?
-  #| identWithPragmaDot = identVisDot pragma?
-  var a = identVis(p, allowDot)
-  if p.tok.tokType == tkCurlyDotLe or isAt(p.tok):
-    result = newNodeP(nkPragmaExpr, p)
-    addSon(result, a)
-    addSon(result, parsePragma(p))
-  else:
-    result = a
-
-type
-  TDeclaredIdentFlag = enum
-    withPragma,               # identifier may have pragma
-    withBothOptional          # both ':' and '=' parts are optional
-  TDeclaredIdentFlags = set[TDeclaredIdentFlag]
-
-proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
-  #| declColonEquals = identWithPragma (comma identWithPragma)* comma?
-  #|                   (':' optInd typeDesc)? ('=' optInd expr)?
-  #| identColonEquals = ident (comma ident)* comma?
-  #|      (':' optInd typeDesc)? ('=' optInd expr)?)
-  var a: PNode
-  result = newNodeP(nkIdentDefs, p)
-  while true:
-    case p.tok.tokType
-    of tkSymbol, tkAccent:
-      if withPragma in flags: a = identWithPragma(p)
-      else: a = parseSymbol(p)
-      if a.kind == nkEmpty: return
-    else: break
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-  if p.tok.tokType == tkColon:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseTypeDesc(p))
-  else:
-    addSon(result, ast.emptyNode)
-    if p.tok.tokType != tkEquals and withBothOptional notin flags:
-      parMessage(p, errColonOrEqualsExpected, p.tok)
-  if p.tok.tokType == tkEquals:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseExpr(p))
-  else:
-    addSon(result, ast.emptyNode)
-
-proc parseTuple(p: var TParser): PNode =
-  result = newNodeP(nkTupleTy, p)
-  getTok(p)
-  if p.tok.tokType in {tkBracketLe, tkCurlyLe}:
-    let usedCurly = p.tok.tokType == tkCurlyLe
-    getTok(p)
-    optInd(p, result)
-    while p.tok.tokType in {tkSymbol, tkAccent}:
-      var a = parseIdentColonEquals(p, {})
-      addSon(result, a)
-      if p.tok.tokType notin {tkComma, tkSemiColon}: break
-      getTok(p)
-      skipComment(p, a)
-    optPar(p)
-    if usedCurly: eat(p, tkCurlyRi)
-    else: eat(p, tkBracketRi)
-  else:
-    result = newNodeP(nkTupleClassTy, p)
-
-proc parseParamList(p: var TParser, retColon = true): PNode =
-  #| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
-  #| paramListArrow = paramList? ('->' optInd typeDesc)?
-  #| paramListColon = paramList? (':' optInd typeDesc)?
-  var a: PNode
-  result = newNodeP(nkFormalParams, p)
-  addSon(result, ast.emptyNode) # return type
-  let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
-  if hasParLe:
-    getTok(p)
-    optInd(p, result)
-    while true:
-      case p.tok.tokType
-      of tkSymbol, tkAccent:
-        a = parseIdentColonEquals(p, {withBothOptional, withPragma})
-      of tkParRi:
-        break
-      else:
-        parMessage(p, errTokenExpected, ")")
-        break
-      addSon(result, a)
-      if p.tok.tokType notin {tkComma, tkSemiColon}: break
-      getTok(p)
-      skipComment(p, a)
-    optPar(p)
-    eat(p, tkParRi)
-  let hasRet = if retColon: p.tok.tokType == tkColon
-               else: p.tok.tokType == tkOpr and p.tok.ident.s == "->"
-  if hasRet and p.tok.indent < 0:
-    getTok(p)
-    optInd(p, result)
-    result.sons[0] = parseTypeDesc(p)
-  elif not retColon and not hasParle:
-    # Mark as "not there" in order to mark for deprecation in the semantic pass:
-    result = ast.emptyNode
-
-proc optPragmas(p: var TParser): PNode =
-  if p.tok.tokType == tkCurlyDotLe or isAt(p.tok):
-    result = parsePragma(p)
-  else:
-    result = ast.emptyNode
-
-proc parseDoBlock(p: var TParser): PNode =
-  #| doBlock = 'do' paramListArrow pragmas? colcom stmt
-  let info = parLineInfo(p)
-  getTok(p)
-  let params = parseParamList(p, retColon=false)
-  let pragmas = optPragmas(p)
-  colcom(p, result)
-  result = newProcNode(nkDo, info, parseStmt(p),
-                       params = params,
-                       pragmas = pragmas)
-
-proc parseDoBlocks(p: var TParser, call: PNode) =
-  #| doBlocks = doBlock ^* IND{=}
-  while p.tok.tokType == tkDo:
-    addSon(call, parseDoBlock(p))
-
-proc parseCurlyStmt(p: var TParser): PNode =
-  result = newNodeP(nkStmtList, p)
-  eat(p, tkCurlyLe)
-  result.add parseStmt(p)
-  while p.tok.tokType notin {tkEof, tkCurlyRi}:
-    if p.tok.tokType == tkSemicolon: getTok(p)
-    elif p.tok.indent < 0: break
-    result.add parseStmt(p)
-  eat(p, tkCurlyRi)
-
-proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
-  #| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
-  # either a proc type or a anonymous proc
-  let info = parLineInfo(p)
-  getTok(p)
-  let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0
-  let params = parseParamList(p)
-  let pragmas = optPragmas(p)
-  if p.tok.tokType == tkCurlyLe and isExpr:
-    result = newProcNode(nkLambda, info, parseCurlyStmt(p),
-                         params = params,
-                         pragmas = pragmas)
-  else:
-    result = newNodeI(nkProcTy, info)
-    if hasSignature:
-      addSon(result, params)
-      addSon(result, pragmas)
-
-proc isExprStart(p: TParser): bool =
-  case p.tok.tokType
-  of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
-     tkProc, tkIterator, tkBind, tkAddr,
-     tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
-     tkTuple, tkObject, tkType, tkWhen, tkCase, tkOut:
-    result = true
-  else: result = false
-
-proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
-  while true:
-    var s = parseSymbol(p, allowNil)
-    if s.kind == nkEmpty: break
-    addSon(result, s)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, s)
-
-proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
-                       mode: TPrimaryMode): PNode =
-  #| distinct = 'distinct' optInd typeDesc
-  result = newNodeP(kind, p)
-  getTok(p)
-  optInd(p, result)
-  if not isOperator(p.tok) and isExprStart(p):
-    addSon(result, primary(p, mode))
-  if kind == nkDistinctTy and p.tok.tokType == tkSymbol:
-    var nodeKind: TNodeKind
-    if p.tok.ident.s == "with":
-      nodeKind = nkWith
-    elif p.tok.ident.s == "without":
-      nodeKind = nkWithout
-    else:
-      return result
-    getTok(p)
-    let list = newNodeP(nodeKind, p)
-    result.addSon list
-    parseSymbolList(p, list, allowNil = true)
-
-proc parseExpr(p: var TParser): PNode =
-  #| expr = (ifExpr
-  #|       | whenExpr
-  #|       | caseExpr
-  #|       | tryExpr)
-  #|       / simpleExpr
-  case p.tok.tokType:
-  of tkIf: result = parseIfExpr(p, nkIfExpr)
-  of tkWhen: result = parseIfExpr(p, nkWhenExpr)
-  of tkCase: result = parseCase(p)
-  of tkTry: result = parseTry(p)
-  else: result = simpleExpr(p)
-
-proc parseEnum(p: var TParser): PNode
-proc parseObject(p: var TParser): PNode
-proc parseTypeClass(p: var TParser): PNode
-
-proc primary(p: var TParser, mode: TPrimaryMode): PNode =
-  #| typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple'
-  #|          | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
-  #| primary = typeKeyw typeDescK
-  #|         /  prefixOperator* identOrLiteral primarySuffix*
-  #|         / 'static' primary
-  #|         / 'bind' primary
-  if isOperator(p.tok):
-    let isSigil = isSigilLike(p.tok)
-    result = newNodeP(nkPrefix, p)
-    var a = newIdentNodeP(p.tok.ident, p)
-    addSon(result, a)
-    getTok(p)
-    optInd(p, a)
-    if isSigil:
-      #XXX prefix operators
-      addSon(result, primary(p, pmSkipSuffix))
-      result = primarySuffix(p, result)
-    else:
-      addSon(result, primary(p, pmNormal))
-    return
-
-  case p.tok.tokType:
-  of tkTuple: result = parseTuple(p)
-  of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
-  of tkIterator:
-    result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
-    if result.kind == nkLambda: result.kind = nkIteratorDef
-    else: result.kind = nkIteratorTy
-  of tkEnum:
-    if mode == pmTypeDef:
-      result = parseEnum(p)
-    else:
-      result = newNodeP(nkEnumTy, p)
-      getTok(p)
-  of tkObject:
-    if mode == pmTypeDef:
-      result = parseObject(p)
-    else:
-      result = newNodeP(nkObjectTy, p)
-      getTok(p)
-  of tkConcept:
-    if mode == pmTypeDef:
-      result = parseTypeClass(p)
-    else:
-      parMessage(p, errInvalidToken, p.tok)
-  of tkStatic:
-    let info = parLineInfo(p)
-    getTokNoInd(p)
-    let next = primary(p, pmNormal)
-    if next.kind == nkBracket and next.sonsLen == 1:
-      result = newNode(nkStaticTy, info, @[next.sons[0]])
-    else:
-      result = newNode(nkStaticExpr, info, @[next])
-  of tkBind:
-    result = newNodeP(nkBind, p)
-    getTok(p)
-    optInd(p, result)
-    addSon(result, primary(p, pmNormal))
-  of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
-  of tkOut: result = parseTypeDescKAux(p, nkVarTy, mode)
-  of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
-  of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
-  of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
-  else:
-    result = identOrLiteral(p, mode)
-    if mode != pmSkipSuffix:
-      result = primarySuffix(p, result)
-
-proc parseTypeDesc(p: var TParser): PNode =
-  #| typeDesc = simpleExpr
-  result = simpleExpr(p, pmTypeDesc)
-
-proc parseTypeDefAux(p: var TParser): PNode =
-  #| typeDefAux = simpleExpr
-  #|            | 'concept' typeClass
-  result = simpleExpr(p, pmTypeDef)
-
-proc makeCall(n: PNode): PNode =
-  ## Creates a call if the given node isn't already a call.
-  if n.kind in nkCallKinds:
-    result = n
-  else:
-    result = newNodeI(nkCall, n.info)
-    result.add n
-
-proc parseMacroColon(p: var TParser, x: PNode): PNode =
-  #| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
-  #|                        | IND{=} 'elif' expr ':' stmt
-  #|                        | IND{=} 'except' exprList ':' stmt
-  #|                        | IND{=} 'else' ':' stmt )*
-  result = x
-  if p.tok.tokType == tkColon and p.tok.indent < 0:
-    result = makeCall(result)
-    getTok(p)
-    skipComment(p, result)
-    let stmtList = newNodeP(nkStmtList, p)
-    if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
-      let body = parseStmt(p)
-      stmtList.add body
-      #addSon(result, makeStmtList(body))
-    while true:
-      var b: PNode
-      case p.tok.tokType
-      of tkOf:
-        b = newNodeP(nkOfBranch, p)
-        exprList(p, tkCurlyLe, b)
-      of tkElif:
-        b = newNodeP(nkElifBranch, p)
-        getTok(p)
-        optInd(p, b)
-        addSon(b, parseExpr(p))
-      of tkExcept:
-        b = newNodeP(nkExceptBranch, p)
-        exprList(p, tkCurlyLe, b)
-      of tkElse:
-        b = newNodeP(nkElse, p)
-        getTok(p)
-      else: break
-      addSon(b, parseCurlyStmt(p))
-      addSon(stmtList, b)
-      if b.kind == nkElse: break
-    if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
-      # to keep backwards compatibility (see tests/vm/tstringnil)
-      result.add stmtList[0]
-    else:
-      result.add stmtList
-
-proc parseExprStmt(p: var TParser): PNode =
-  #| exprStmt = simpleExpr
-  #|          (( '=' optInd expr )
-  #|          / ( expr ^+ comma
-  #|              doBlocks
-  #|               / macroColon
-  #|            ))?
-  var a = simpleExpr(p)
-  if p.tok.tokType == tkEquals:
-    getTok(p)
-    optInd(p, result)
-    var b = parseExpr(p)
-    result = newNodeI(nkAsgn, a.info)
-    addSon(result, a)
-    addSon(result, b)
-  else:
-    # simpleExpr parsed 'p a' from 'p a, b'?
-    if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand:
-      result = a
-      while true:
-        getTok(p)
-        optInd(p, result)
-        var e = parseExpr(p)
-        addSon(result, e)
-        if p.tok.tokType != tkComma: break
-    elif p.tok.indent < 0 and isExprStart(p):
-      if a.kind == nkCommand:
-        result = a
-      else:
-        result = newNode(nkCommand, a.info, @[a])
-      while true:
-        var e = parseExpr(p)
-        addSon(result, e)
-        if p.tok.tokType != tkComma: break
-        getTok(p)
-        optInd(p, result)
-    else:
-      result = a
-    if p.tok.tokType == tkDo and p.tok.indent < 0:
-      result = makeCall(result)
-      parseDoBlocks(p, result)
-      return result
-    result = parseMacroColon(p, result)
-
-proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
-  result = parseExpr(p)
-
-proc parseImport(p: var TParser, kind: TNodeKind): PNode =
-  #| importStmt = 'import' optInd expr
-  #|               ((comma expr)*
-  #|               / 'except' optInd (expr ^+ comma))
-  result = newNodeP(kind, p)
-  getTok(p)                   # skip `import` or `export`
-  optInd(p, result)
-  var a = parseModuleName(p, kind)
-  addSon(result, a)
-  if p.tok.tokType in {tkComma, tkExcept}:
-    if p.tok.tokType == tkExcept:
-      result.kind = succ(kind)
-    getTok(p)
-    optInd(p, result)
-    while true:
-      # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
-      a = parseModuleName(p, kind)
-      if a.kind == nkEmpty: break
-      addSon(result, a)
-      if p.tok.tokType != tkComma: break
-      getTok(p)
-      optInd(p, a)
-  #expectNl(p)
-
-proc parseIncludeStmt(p: var TParser): PNode =
-  #| includeStmt = 'include' optInd expr ^+ comma
-  result = newNodeP(nkIncludeStmt, p)
-  getTok(p)                   # skip `import` or `include`
-  optInd(p, result)
-  while true:
-    # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
-    var a = parseExpr(p)
-    if a.kind == nkEmpty: break
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-  #expectNl(p)
-
-proc parseFromStmt(p: var TParser): PNode =
-  #| fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
-  result = newNodeP(nkFromStmt, p)
-  getTok(p)                   # skip `from`
-  optInd(p, result)
-  var a = parseModuleName(p, nkImportStmt)
-  addSon(result, a)           #optInd(p, a);
-  eat(p, tkImport)
-  optInd(p, result)
-  while true:
-    # p.tok.tokType notin {tkEof, tkSad, tkDed}:
-    a = parseExpr(p)
-    if a.kind == nkEmpty: break
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-  #expectNl(p)
-
-proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
-  #| returnStmt = 'return' optInd expr?
-  #| raiseStmt = 'raise' optInd expr?
-  #| yieldStmt = 'yield' optInd expr?
-  #| discardStmt = 'discard' optInd expr?
-  #| breakStmt = 'break' optInd expr?
-  #| continueStmt = 'break' optInd expr?
-  result = newNodeP(kind, p)
-  getTok(p)
-  if p.tok.tokType == tkComment:
-    skipComment(p, result)
-    addSon(result, ast.emptyNode)
-  elif p.tok.indent >= 0 or not isExprStart(p):
-    # NL terminates:
-    addSon(result, ast.emptyNode)
-  else:
-    addSon(result, parseExpr(p))
-
-proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
-  #| condStmt = expr colcom stmt COMMENT?
-  #|            (IND{=} 'elif' expr colcom stmt)*
-  #|            (IND{=} 'else' colcom stmt)?
-  #| ifStmt = 'if' condStmt
-  #| whenStmt = 'when' condStmt
-  result = newNodeP(kind, p)
-  while true:
-    getTok(p)                 # skip `if`, `when`, `elif`
-    var branch = newNodeP(nkElifBranch, p)
-    optInd(p, branch)
-    addSon(branch, parseExpr(p))
-    colcom(p, branch)
-    addSon(branch, parseCurlyStmt(p))
-    skipComment(p, branch)
-    addSon(result, branch)
-    if p.tok.tokType != tkElif: break
-  if p.tok.tokType == tkElse:
-    var branch = newNodeP(nkElse, p)
-    eat(p, tkElse)
-    addSon(branch, parseCurlyStmt(p))
-    addSon(result, branch)
-
-proc parseWhile(p: var TParser): PNode =
-  #| whileStmt = 'while' expr colcom stmt
-  result = newNodeP(nkWhileStmt, p)
-  getTok(p)
-  optInd(p, result)
-  addSon(result, parseExpr(p))
-  colcom(p, result)
-  addSon(result, parseCurlyStmt(p))
-
-proc parseCase(p: var TParser): PNode =
-  #| ofBranch = 'of' exprList colcom stmt
-  #| ofBranches = ofBranch (IND{=} ofBranch)*
-  #|                       (IND{=} 'elif' expr colcom stmt)*
-  #|                       (IND{=} 'else' colcom stmt)?
-  #| caseStmt = 'case' expr ':'? COMMENT?
-  #|             (IND{>} ofBranches DED
-  #|             | IND{=} ofBranches)
-  var
-    b: PNode
-    inElif= false
-  result = newNodeP(nkCaseStmt, p)
-  getTok(p)
-  addSon(result, parseExpr(p))
-  eat(p, tkCurlyLe)
-  skipComment(p, result)
-
-  while true:
-    case p.tok.tokType
-    of tkOf:
-      if inElif: break
-      b = newNodeP(nkOfBranch, p)
-      exprList(p, tkCurlyLe, b)
-    of tkElif:
-      inElif = true
-      b = newNodeP(nkElifBranch, p)
-      getTok(p)
-      optInd(p, b)
-      addSon(b, parseExpr(p))
-    of tkElse:
-      b = newNodeP(nkElse, p)
-      getTok(p)
-    else: break
-    skipComment(p, b)
-    addSon(b, parseCurlyStmt(p))
-    addSon(result, b)
-    if b.kind == nkElse: break
-  eat(p, tkCurlyRi)
-
-proc parseTry(p: var TParser): PNode =
-  #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
-  #|            (IND{=}? 'except' exprList colcom stmt)*
-  #|            (IND{=}? 'finally' colcom stmt)?
-  #| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
-  #|            (optInd 'except' exprList colcom stmt)*
-  #|            (optInd 'finally' colcom stmt)?
-  result = newNodeP(nkTryStmt, p)
-  getTok(p)
-  colcom(p, result)
-  addSon(result, parseCurlyStmt(p))
-  var b: PNode = nil
-  while true:
-    case p.tok.tokType
-    of tkExcept:
-      b = newNodeP(nkExceptBranch, p)
-      exprList(p, tkCurlyLe, b)
-    of tkFinally:
-      b = newNodeP(nkFinally, p)
-      getTok(p)
-    else: break
-    skipComment(p, b)
-    addSon(b, parseCurlyStmt(p))
-    addSon(result, b)
-    if b.kind == nkFinally: break
-  if b == nil: parMessage(p, errTokenExpected, "except")
-
-proc parseFor(p: var TParser): PNode =
-  #| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
-  result = newNodeP(nkForStmt, p)
-  getTokNoInd(p)
-  var a = identWithPragma(p)
-  addSon(result, a)
-  while p.tok.tokType == tkComma:
-    getTok(p)
-    optInd(p, a)
-    a = identWithPragma(p)
-    addSon(result, a)
-  eat(p, tkIn)
-  addSon(result, parseExpr(p))
-  colcom(p, result)
-  addSon(result, parseCurlyStmt(p))
-
-proc parseBlock(p: var TParser): PNode =
-  #| blockStmt = 'block' symbol? colcom stmt
-  result = newNodeP(nkBlockStmt, p)
-  getTokNoInd(p)
-  if p.tok.tokType == tkCurlyLe: addSon(result, ast.emptyNode)
-  else: addSon(result, parseSymbol(p))
-  colcom(p, result)
-  addSon(result, parseCurlyStmt(p))
-
-proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
-  #| staticStmt = 'static' colcom stmt
-  #| deferStmt = 'defer' colcom stmt
-  result = newNodeP(k, p)
-  getTok(p)
-  colcom(p, result)
-  addSon(result, parseCurlyStmt(p))
-
-proc parseAsm(p: var TParser): PNode =
-  #| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT)
-  result = newNodeP(nkAsmStmt, p)
-  getTokNoInd(p)
-  if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): addSon(result, parsePragma(p))
-  else: addSon(result, ast.emptyNode)
-  case p.tok.tokType
-  of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p))
-  of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
-  of tkTripleStrLit: addSon(result,
-                            newStrNodeP(nkTripleStrLit, p.tok.literal, p))
-  else:
-    parMessage(p, errStringLiteralExpected)
-    addSon(result, ast.emptyNode)
-    return
-  getTok(p)
-
-proc parseGenericParam(p: var TParser): PNode =
-  #| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
-  var a: PNode
-  result = newNodeP(nkIdentDefs, p)
-  while true:
-    case p.tok.tokType
-    of tkIn, tkOut:
-      let t = p.tok.tokType
-      getTok(p)
-      expectIdent(p)
-      a = parseSymbol(p)
-    of tkSymbol, tkAccent:
-      a = parseSymbol(p)
-      if a.kind == nkEmpty: return
-    else: break
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-  if p.tok.tokType == tkColon:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseExpr(p))
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkEquals:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseExpr(p))
-  else:
-    addSon(result, ast.emptyNode)
-
-proc parseGenericParamList(p: var TParser): PNode =
-  #| genericParamList = '[' optInd
-  #|   genericParam ^* (comma/semicolon) optPar ']'
-  result = newNodeP(nkGenericParams, p)
-  getTok(p)
-  optInd(p, result)
-  while p.tok.tokType in {tkSymbol, tkAccent}:
-    var a = parseGenericParam(p)
-    addSon(result, a)
-    if p.tok.tokType notin {tkComma, tkSemiColon}: break
-    getTok(p)
-    skipComment(p, a)
-  optPar(p)
-  eat(p, tkBracketRi)
-
-proc parsePattern(p: var TParser): PNode =
-  eat(p, tkBracketDotLe)
-  result = parseStmt(p)
-  eat(p, tkBracketDotRi)
-
-proc validInd(p: TParser): bool = p.tok.indent < 0
-
-proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
-  #| indAndComment = (IND{>} COMMENT)? | COMMENT?
-  #| routine = optInd identVis pattern? genericParamList?
-  #|   paramListColon pragma? ('=' COMMENT? stmt)? indAndComment
-  result = newNodeP(kind, p)
-  getTok(p)
-  optInd(p, result)
-  addSon(result, identVis(p))
-  if p.tok.tokType == tkBracketDotLe and p.validInd:
-    addSon(result, p.parsePattern)
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkBracketLe and p.validInd:
-    result.add(p.parseGenericParamList)
-  else:
-    addSon(result, ast.emptyNode)
-  addSon(result, p.parseParamList)
-  if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd:
-    addSon(result, p.parsePragma)
-  else:
-    addSon(result, ast.emptyNode)
-  # empty exception tracking:
-  addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkCurlyLe:
-    addSon(result, parseCurlyStmt(p))
-  else:
-    addSon(result, ast.emptyNode)
-  indAndComment(p, result)
-
-proc newCommentStmt(p: var TParser): PNode =
-  #| commentStmt = COMMENT
-  result = newNodeP(nkCommentStmt, p)
-  result.comment = p.tok.literal
-  getTok(p)
-
-type
-  TDefParser = proc (p: var TParser): PNode {.nimcall.}
-
-proc parseSection(p: var TParser, kind: TNodeKind,
-                  defparser: TDefParser): PNode =
-  #| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
-  result = newNodeP(kind, p)
-  if kind != nkTypeSection: getTok(p)
-  skipComment(p, result)
-  if p.tok.tokType == tkParLe:
-    getTok(p)
-    skipComment(p, result)
-    while true:
-      case p.tok.tokType
-      of tkSymbol, tkAccent, tkParLe:
-        var a = defparser(p)
-        skipComment(p, a)
-        addSon(result, a)
-      of tkComment:
-        var a = newCommentStmt(p)
-        addSon(result, a)
-      of tkParRi: break
-      else:
-        parMessage(p, errIdentifierExpected, p.tok)
-        break
-    eat(p, tkParRi)
-    if result.len == 0: parMessage(p, errIdentifierExpected, p.tok)
-  elif p.tok.tokType in {tkSymbol, tkAccent, tkBracketLe}:
-    # tkBracketLe is allowed for ``var [x, y] = ...`` tuple parsing
-    addSon(result, defparser(p))
-  else:
-    parMessage(p, errIdentifierExpected, p.tok)
-
-proc parseConstant(p: var TParser): PNode =
-  #| constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment
-  result = newNodeP(nkConstDef, p)
-  addSon(result, identWithPragma(p))
-  if p.tok.tokType == tkColon:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseTypeDesc(p))
-  else:
-    addSon(result, ast.emptyNode)
-  eat(p, tkEquals)
-  optInd(p, result)
-  addSon(result, parseExpr(p))
-  indAndComment(p, result)
-
-proc parseEnum(p: var TParser): PNode =
-  #| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
-  result = newNodeP(nkEnumTy, p)
-  getTok(p)
-  addSon(result, ast.emptyNode)
-  optInd(p, result)
-  flexComment(p, result)
-  eat(p, tkCurlyLe)
-  optInd(p, result)
-  while p.tok.tokType notin {tkEof, tkCurlyRi}:
-    var a = parseSymbol(p)
-    if a.kind == nkEmpty: return
-    if p.tok.tokType == tkEquals:
-      getTok(p)
-      optInd(p, a)
-      var b = a
-      a = newNodeP(nkEnumFieldDef, p)
-      addSon(a, b)
-      addSon(a, parseExpr(p))
-      if p.tok.indent < 0:
-        rawSkipComment(p, a)
-    if p.tok.tokType == tkComma:
-      getTok(p)
-      rawSkipComment(p, a)
-    addSon(result, a)
-  eat(p, tkCurlyRi)
-  if result.len <= 1:
-    lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok))
-
-proc parseObjectPart(p: var TParser; needsCurly: bool): PNode
-proc parseObjectWhen(p: var TParser): PNode =
-  result = newNodeP(nkRecWhen, p)
-  while true:
-    getTok(p)                 # skip `when`, `elif`
-    var branch = newNodeP(nkElifBranch, p)
-    optInd(p, branch)
-    addSon(branch, parseExpr(p))
-    colcom(p, branch)
-    addSon(branch, parseObjectPart(p, true))
-    flexComment(p, branch)
-    addSon(result, branch)
-    if p.tok.tokType != tkElif: break
-  if p.tok.tokType == tkElse:
-    var branch = newNodeP(nkElse, p)
-    eat(p, tkElse)
-    colcom(p, branch)
-    addSon(branch, parseObjectPart(p, true))
-    flexComment(p, branch)
-    addSon(result, branch)
-
-proc parseObjectCase(p: var TParser): PNode =
-  result = newNodeP(nkRecCase, p)
-  getTokNoInd(p)
-  var a = newNodeP(nkIdentDefs, p)
-  addSon(a, identWithPragma(p))
-  eat(p, tkColon)
-  addSon(a, parseTypeDesc(p))
-  addSon(a, ast.emptyNode)
-  addSon(result, a)
-  eat(p, tkCurlyLe)
-  flexComment(p, result)
-  while true:
-    var b: PNode
-    case p.tok.tokType
-    of tkOf:
-      b = newNodeP(nkOfBranch, p)
-      exprList(p, tkColon, b)
-    of tkElse:
-      b = newNodeP(nkElse, p)
-      getTok(p)
-    else: break
-    colcom(p, b)
-    var fields = parseObjectPart(p, true)
-    if fields.kind == nkEmpty:
-      parMessage(p, errIdentifierExpected, p.tok)
-      fields = newNodeP(nkNilLit, p) # don't break further semantic checking
-    addSon(b, fields)
-    addSon(result, b)
-    if b.kind == nkElse: break
-  eat(p, tkCurlyRi)
-
-proc parseObjectPart(p: var TParser; needsCurly: bool): PNode =
-  if p.tok.tokType == tkCurlyLe:
-    result = newNodeP(nkRecList, p)
-    getTok(p)
-    rawSkipComment(p, result)
-    while true:
-      case p.tok.tokType
-      of tkCase, tkWhen, tkSymbol, tkAccent, tkNil, tkDiscard:
-        addSon(result, parseObjectPart(p, false))
-      of tkCurlyRi: break
-      else:
-        parMessage(p, errIdentifierExpected, p.tok)
-        break
-    eat(p, tkCurlyRi)
-  else:
-    if needsCurly:
-      parMessage(p, errTokenExpected, "{")
-    case p.tok.tokType
-    of tkWhen:
-      result = parseObjectWhen(p)
-    of tkCase:
-      result = parseObjectCase(p)
-    of tkSymbol, tkAccent:
-      result = parseIdentColonEquals(p, {withPragma})
-      if p.tok.indent < 0: rawSkipComment(p, result)
-    of tkNil, tkDiscard:
-      result = newNodeP(nkNilLit, p)
-      getTok(p)
-    else:
-      result = ast.emptyNode
-
-proc parseObject(p: var TParser): PNode =
-  result = newNodeP(nkObjectTy, p)
-  getTok(p)
-  if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd:
-    addSon(result, parsePragma(p))
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkOf and p.tok.indent < 0:
-    var a = newNodeP(nkOfInherit, p)
-    getTok(p)
-    addSon(a, parseTypeDesc(p))
-    addSon(result, a)
-  else:
-    addSon(result, ast.emptyNode)
-  skipComment(p, result)
-  # an initial IND{>} HAS to follow:
-  addSon(result, parseObjectPart(p, true))
-
-proc parseTypeClassParam(p: var TParser): PNode =
-  if p.tok.tokType in {tkOut, tkVar}:
-    result = newNodeP(nkVarTy, p)
-    getTok(p)
-    result.addSon(p.parseSymbol)
-  else:
-    result = p.parseSymbol
-
-proc parseTypeClass(p: var TParser): PNode =
-  #| typeClassParam = ('var' | 'out')? symbol
-  #| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
-  #|               &IND{>} stmt
-  result = newNodeP(nkTypeClassTy, p)
-  getTok(p)
-  var args = newNodeP(nkArgList, p)
-  addSon(result, args)
-  addSon(args, p.parseTypeClassParam)
-  while p.tok.tokType == tkComma:
-    getTok(p)
-    addSon(args, p.parseTypeClassParam)
-  if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd:
-    addSon(result, parsePragma(p))
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkOf and p.tok.indent < 0:
-    var a = newNodeP(nkOfInherit, p)
-    getTok(p)
-    while true:
-      addSon(a, parseTypeDesc(p))
-      if p.tok.tokType != tkComma: break
-      getTok(p)
-    addSon(result, a)
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkComment:
-    skipComment(p, result)
-  addSon(result, parseCurlyStmt(p))
-
-proc parseTypeDef(p: var TParser): PNode =
-  #|
-  #| typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux
-  #|             indAndComment?
-  result = newNodeP(nkTypeDef, p)
-  addSon(result, identWithPragma(p, allowDot=true))
-  if p.tok.tokType == tkBracketLe and p.validInd:
-    addSon(result, parseGenericParamList(p))
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkEquals:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseTypeDefAux(p))
-  else:
-    addSon(result, ast.emptyNode)
-  indAndComment(p, result)    # special extension!
-
-proc parseVarTuple(p: var TParser): PNode =
-  #| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
-  result = newNodeP(nkVarTuple, p)
-  getTok(p)                   # skip '('
-  optInd(p, result)
-  while p.tok.tokType in {tkSymbol, tkAccent}:
-    var a = identWithPragma(p)
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    skipComment(p, a)
-  addSon(result, ast.emptyNode)         # no type desc
-  optPar(p)
-  eat(p, tkBracketRi)
-  eat(p, tkEquals)
-  optInd(p, result)
-  addSon(result, parseExpr(p))
-
-proc parseVariable(p: var TParser): PNode =
-  #| variable = (varTuple / identColonEquals) indAndComment
-  if p.tok.tokType == tkBracketLe: result = parseVarTuple(p)
-  else: result = parseIdentColonEquals(p, {withPragma})
-  indAndComment(p, result)
-
-proc parseBind(p: var TParser, k: TNodeKind): PNode =
-  #| bindStmt = 'bind' optInd qualifiedIdent ^+ comma
-  #| mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma
-  result = newNodeP(k, p)
-  getTok(p)
-  optInd(p, result)
-  while true:
-    var a = qualifiedIdent(p)
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-
-proc parseStmtPragma(p: var TParser): PNode =
-  result = parsePragma(p)
-  if p.tok.tokType == tkCurlyLe:
-    let a = result
-    result = newNodeI(nkPragmaBlock, a.info)
-    getTok(p)
-    skipComment(p, result)
-    result.add a
-    result.add parseStmt(p)
-    eat(p, tkCurlyRi)
-
-proc simpleStmt(p: var TParser): PNode =
-  case p.tok.tokType
-  of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt)
-  of tkRaise: result = parseReturnOrRaise(p, nkRaiseStmt)
-  of tkYield: result = parseReturnOrRaise(p, nkYieldStmt)
-  of tkDiscard: result = parseReturnOrRaise(p, nkDiscardStmt)
-  of tkBreak: result = parseReturnOrRaise(p, nkBreakStmt)
-  of tkContinue: result = parseReturnOrRaise(p, nkContinueStmt)
-  of tkCurlyDotLe: result = parseStmtPragma(p)
-  of tkImport: result = parseImport(p, nkImportStmt)
-  of tkExport: result = parseImport(p, nkExportStmt)
-  of tkFrom: result = parseFromStmt(p)
-  of tkInclude: result = parseIncludeStmt(p)
-  of tkComment: result = newCommentStmt(p)
-  else:
-    if isExprStart(p): result = parseExprStmt(p)
-    else: result = ast.emptyNode
-  if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result)
-
-proc complexOrSimpleStmt(p: var TParser): PNode =
-  case p.tok.tokType
-  of tkIf: result = parseIfOrWhen(p, nkIfStmt)
-  of tkWhile: result = parseWhile(p)
-  of tkCase: result = parseCase(p)
-  of tkTry: result = parseTry(p)
-  of tkFor: result = parseFor(p)
-  of tkBlock: result = parseBlock(p)
-  of tkStatic: result = parseStaticOrDefer(p, nkStaticStmt)
-  of tkDefer: result = parseStaticOrDefer(p, nkDefer)
-  of tkAsm: result = parseAsm(p)
-  of tkProc: result = parseRoutine(p, nkProcDef)
-  of tkMethod: result = parseRoutine(p, nkMethodDef)
-  of tkIterator: result = parseRoutine(p, nkIteratorDef)
-  of tkMacro: result = parseRoutine(p, nkMacroDef)
-  of tkTemplate: result = parseRoutine(p, nkTemplateDef)
-  of tkConverter: result = parseRoutine(p, nkConverterDef)
-  of tkType:
-    getTok(p)
-    if p.tok.tokType == tkBracketLe:
-      getTok(p)
-      result = newNodeP(nkTypeOfExpr, p)
-      result.addSon(primary(p, pmTypeDesc))
-      eat(p, tkBracketRi)
-      result = parseOperators(p, result, -1, pmNormal)
-    else:
-      result = parseSection(p, nkTypeSection, parseTypeDef)
-  of tkConst: result = parseSection(p, nkConstSection, parseConstant)
-  of tkLet: result = parseSection(p, nkLetSection, parseVariable)
-  of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
-  of tkVar: result = parseSection(p, nkVarSection, parseVariable)
-  of tkBind: result = parseBind(p, nkBindStmt)
-  of tkMixin: result = parseBind(p, nkMixinStmt)
-  of tkUsing: result = parseSection(p, nkUsingStmt, parseVariable)
-  else: result = simpleStmt(p)
-
-proc parseStmt(p: var TParser): PNode =
-  result = complexOrSimpleStmt(p)
-
-proc parseAll*(p: var TParser): PNode =
-  ## Parses the rest of the input stream held by the parser into a PNode.
-  result = newNodeP(nkStmtList, p)
-  while p.tok.tokType != tkEof:
-    var a = complexOrSimpleStmt(p)
-    if a.kind != nkEmpty:
-      addSon(result, a)
-    else:
-      parMessage(p, errExprExpected, p.tok)
-      # bugfix: consume a token here to prevent an endless loop:
-      getTok(p)
-
-proc parseTopLevelStmt*(p: var TParser): PNode =
-  ## Implements an iterator which, when called repeatedly, returns the next
-  ## top-level statement or emptyNode if end of stream.
-  result = ast.emptyNode
-  while true:
-    case p.tok.tokType
-    of tkSemiColon: getTok(p)
-    of tkEof: break
-    else:
-      result = complexOrSimpleStmt(p)
-      if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
-      break