summary refs log tree commit diff stats
path: root/nim/pnimsyn.pas
diff options
context:
space:
mode:
Diffstat (limited to 'nim/pnimsyn.pas')
-rwxr-xr-xnim/pnimsyn.pas1802
1 files changed, 0 insertions, 1802 deletions
diff --git a/nim/pnimsyn.pas b/nim/pnimsyn.pas
deleted file mode 100755
index 260d1e5a5..000000000
--- a/nim/pnimsyn.pas
+++ /dev/null
@@ -1,1802 +0,0 @@
-//
-//
-//           The Nimrod Compiler
-//        (c) Copyright 2009 Andreas Rumpf
-//
-//    See the file "copying.txt", included in this
-//    distribution, for details about the copyright.
-//
-unit pnimsyn;
-
-// This module implements the parser of the standard Nimrod representation.
-// The parser strictly reflects the grammar ("doc/grammar.txt"); however
-// it uses several helper routines to keep the parser small. A special
-// efficient algorithm is used for the precedence levels. The parser here can
-// be seen as a refinement of the grammar, as it specifies how the AST is build
-// from the grammar and how comments belong to the AST.
-
-{$include config.inc}
-
-interface
-
-uses
-  nsystem, llstream, scanner, idents, strutils, ast, msgs;
-
-// function ParseFile(const filename: string): PNode;
-
-type
-  TParser = record               // a TParser object represents a module that
-                                 // is being parsed
-    lex: PLexer;                 // the lexer that is used for parsing
-    tok: PToken;                 // the current token
-  end;
-
-function ParseAll(var p: TParser): PNode;
-
-procedure openParser(var p: TParser; const filename: string;
-                     inputstream: PLLStream);
-procedure closeParser(var p: TParser);
-
-function parseTopLevelStmt(var p: TParser): PNode;
-// implements an iterator. Returns the next top-level statement or nil if end
-// of stream.
-
-
-// helpers for the other parsers
-function getPrecedence(tok: PToken): int;
-function isOperator(tok: PToken): bool;
-
-procedure getTok(var p: TParser);
-
-procedure parMessage(const p: TParser; const msg: TMsgKind;
-                     const arg: string = '');
-procedure skipComment(var p: TParser; node: PNode);
-
-function newNodeP(kind: TNodeKind; const p: TParser): PNode;
-function newIntNodeP(kind: TNodeKind; const intVal: BiggestInt;
-                     const p: TParser): PNode;
-function newFloatNodeP(kind: TNodeKind; const floatVal: BiggestFloat;
-                       const p: TParser): PNode;
-function newStrNodeP(kind: TNodeKind; const strVal: string;
-                     const p: TParser): PNode;
-function newIdentNodeP(ident: PIdent; const p: TParser): PNode;
-
-procedure expectIdentOrKeyw(const p: TParser);
-procedure ExpectIdent(const p: TParser);
-procedure expectIdentOrOpr(const p: TParser);
-function parLineInfo(const p: TParser): TLineInfo;
-procedure Eat(var p: TParser; TokType: TTokType);
-
-procedure skipInd(var p: TParser);
-procedure optSad(var p: TParser);
-procedure optInd(var p: TParser; n: PNode);
-procedure indAndComment(var p: TParser; n: PNode);
-
-procedure setBaseFlags(n: PNode; base: TNumericalBase);
-
-function parseSymbol(var p: TParser): PNode;
-function accExpr(var p: TParser): PNode;
-
-
-implementation
-
-procedure initParser(var p: TParser);
-begin
-{@ignore}
-  FillChar(p, sizeof(p), 0);
-{@emit}
-  new(p.lex);
-{@ignore}
-  fillChar(p.lex^, sizeof(p.lex^), 0);
-{@emit}
-  new(p.tok);
-{@ignore}
-  fillChar(p.tok^, sizeof(p.tok^), 0);
-{@emit}
-end;
-
-procedure getTok(var p: TParser);
-begin
-  rawGetTok(p.lex^, p.tok^);
-end;
-
-procedure OpenParser(var p: TParser; const filename: string;
-                     inputStream: PLLStream);
-begin
-  initParser(p);
-  OpenLexer(p.lex^, filename, inputstream);
-  getTok(p); // read the first token
-end;
-
-procedure CloseParser(var p: TParser);
-begin
-  CloseLexer(p.lex^);
-{@ignore}
-  dispose(p.lex);
-{@emit}
-end;
-
-// ---------------- parser helpers --------------------------------------------
-
-procedure parMessage(const p: TParser; const msg: TMsgKind;
-                     const arg: string = '');
-begin
-  lexMessage(p.lex^, msg, arg);
-end;
-
-procedure skipComment(var p: TParser; node: PNode);
-begin
-  if p.tok.tokType = tkComment then begin
-    if node <> nil then begin
-      if node.comment = snil then node.comment := '';
-      add(node.comment, p.tok.literal);
-    end
-    else
-      parMessage(p, errInternal, 'skipComment');
-    getTok(p);
-  end
-end;
-
-procedure skipInd(var p: TParser);
-begin
-  if p.tok.tokType = tkInd then getTok(p)
-end;
-
-procedure optSad(var p: TParser);
-begin
-  if p.tok.tokType = tkSad then getTok(p)
-end;
-
-procedure optInd(var p: TParser; n: PNode);
-begin
-  skipComment(p, n);
-  skipInd(p);
-end;
-
-procedure expectIdentOrKeyw(const p: TParser);
-begin
-  if (p.tok.tokType <> tkSymbol) and not isKeyword(p.tok.tokType) then
-    lexMessage(p.lex^, errIdentifierExpected, tokToStr(p.tok));
-end;
-
-procedure ExpectIdent(const p: TParser);
-begin
-  if p.tok.tokType <> tkSymbol then
-    lexMessage(p.lex^, errIdentifierExpected, tokToStr(p.tok));
-end;
-
-procedure expectIdentOrOpr(const p: TParser);
-begin
-  if not (p.tok.tokType in tokOperators) then
-    lexMessage(p.lex^, errOperatorExpected, tokToStr(p.tok));
-end;
-
-procedure Eat(var p: TParser; TokType: TTokType);
-begin
-  if p.tok.TokType = TokType then getTok(p)
-  else lexMessage(p.lex^, errTokenExpected, TokTypeToStr[tokType])
-end;
-
-function parLineInfo(const p: TParser): TLineInfo;
-begin
-  result := getLineInfo(p.lex^)
-end;
-
-procedure indAndComment(var p: TParser; n: PNode);
-var
-  info: TLineInfo;
-begin
-  if p.tok.tokType = tkInd then begin
-    info := parLineInfo(p);
-    getTok(p);
-    if p.tok.tokType = tkComment then skipComment(p, n)
-    else liMessage(info, errInvalidIndentation);
-  end
-  else skipComment(p, n);
-end;
-
-// ----------------------------------------------------------------------------
-
-function newNodeP(kind: TNodeKind; const p: TParser): PNode;
-begin
-  result := newNodeI(kind, getLineInfo(p.lex^));
-end;
-
-function newIntNodeP(kind: TNodeKind; const intVal: BiggestInt;
-                     const p: TParser): PNode;
-begin
-  result := newNodeP(kind, p);
-  result.intVal := intVal;
-end;
-
-function newFloatNodeP(kind: TNodeKind; const floatVal: BiggestFloat;
-                       const p: TParser): PNode;
-begin
-  result := newNodeP(kind, p);
-  result.floatVal := floatVal;
-end;
-
-function newStrNodeP(kind: TNodeKind; const strVal: string;
-                     const p: TParser): PNode;
-begin
-  result := newNodeP(kind, p);
-  result.strVal := strVal;
-end;
-
-function newIdentNodeP(ident: PIdent; const p: TParser): PNode;
-begin
-  result := newNodeP(nkIdent, p);
-  result.ident := ident;
-end;
-
-// ------------------- Expression parsing ------------------------------------
-
-function parseExpr(var p: TParser): PNode; forward;
-function parseStmt(var p: TParser): PNode; forward;
-
-function parseTypeDesc(var p: TParser): PNode; forward;
-function parseParamList(var p: TParser): PNode; forward;
-
-function getPrecedence(tok: PToken): int;
-begin
-  case tok.tokType of
-    tkOpr: begin
-      case tok.ident.s[strStart] of
-        '$': result := 7;
-        '*', '%', '/', '\': result := 6;
-        '+', '-', '~', '|': result := 5;
-        '&': result := 4;
-        '=', '<', '>', '!': result := 3;
-        else result := 0
-      end
-    end;
-    tkDiv, tkMod, tkShl, tkShr: result := 6;
-    tkIn, tkNotIn, tkIs, tkIsNot: result := 3;
-    tkAnd: result := 2;
-    tkOr, tkXor: result := 1;
-    else result := -1;
-  end;
-end;
-
-function isOperator(tok: PToken): bool;
-begin
-  result := getPrecedence(tok) >= 0
-end;
-
-function parseSymbol(var p: TParser): PNode;
-var
-  s: string;
-  id: PIdent;
-begin
-  case p.tok.tokType of
-    tkSymbol: begin
-      result := newIdentNodeP(p.tok.ident, p);
-      getTok(p);
-    end;
-    tkAccent: begin
-      result := newNodeP(nkAccQuoted, p);
-      getTok(p);
-      case p.tok.tokType of
-        tkBracketLe: begin
-          s := '['+'';
-          getTok(p);
-          if (p.tok.tokType = tkOpr) and (p.tok.ident.s = '$'+'') then begin
-            s := s + '$..';
-            getTok(p);
-            eat(p, tkDotDot);
-            if (p.tok.tokType = tkOpr) and (p.tok.ident.s = '$'+'') then begin
-              addChar(s, '$');
-              getTok(p);
-            end;
-          end
-          else if p.tok.tokType = tkDotDot then begin
-            s := s + '..';
-            getTok(p);
-            if (p.tok.tokType = tkOpr) and (p.tok.ident.s = '$'+'') then begin
-              addChar(s, '$');
-              getTok(p);
-            end;
-          end;
-          eat(p, tkBracketRi);
-          addChar(s, ']');
-          if p.tok.tokType = tkEquals then begin
-            addChar(s, '='); getTok(p);
-          end;
-          addSon(result, newIdentNodeP(getIdent(s), p));
-        end;
-        tkParLe: begin
-          addSon(result, newIdentNodeP(getIdent('()'), p));
-          getTok(p);
-          eat(p, tkParRi);
-        end;
-        tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr: begin
-          id := p.tok.ident;
-          getTok(p);
-          if p.tok.tokType = tkEquals then begin
-            addSon(result, newIdentNodeP(getIdent(id.s + '='), p));
-            getTok(p);
-          end
-          else
-            addSon(result, newIdentNodeP(id, p));
-        end;
-        else begin
-          parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-          result := nil
-        end
-      end;
-      eat(p, tkAccent);
-    end
-    else begin
-      parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-      result := nil
-    end
-  end
-end;
-
-function accExpr(var p: TParser): PNode;
-var
-  x, y: PNode;
-begin
-  result := newNodeP(nkAccQuoted, p);
-  getTok(p); // skip `
-  x := nil;
-  y := nil;
-  case p.tok.tokType of
-    tkSymbol, tkOpr, tokKeywordLow..tokKeywordHigh: begin
-      x := newIdentNodeP(p.tok.ident, p);
-      getTok(p);
-    end
-    else begin
-      parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-    end
-  end;
-  if p.tok.tokType = tkDot then begin
-    getTok(p);
-    case p.tok.tokType of
-      tkSymbol, tkOpr, tokKeywordLow..tokKeywordHigh: begin
-        y := newNodeP(nkDotExpr, p);
-        addSon(y, x);
-        addSon(y, newIdentNodeP(p.tok.ident, p));
-        getTok(p);
-        x := y;
-      end
-      else begin
-        parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-      end
-    end;
-  end;
-  addSon(result, x);
-  eat(p, tkAccent);
-end;
-
-function optExpr(var p: TParser): PNode; // [expr]
-begin
-  if (p.tok.tokType <> tkComma) and (p.tok.tokType <> tkBracketRi)
-  and (p.tok.tokType <> tkDotDot) then
-    result := parseExpr(p)
-  else
-    result := nil;
-end;
-
-function dotdotExpr(var p: TParser; first: PNode = nil): PNode;
-begin
-  result := newNodeP(nkRange, p);
-  addSon(result, first);
-  getTok(p);
-  optInd(p, result);
-  addSon(result, optExpr(p));
-end;
-
-function indexExpr(var p: TParser): PNode;
-// indexExpr ::= '..' [expr] | expr ['=' expr | '..' expr]
-var
-  a, b: PNode;
-begin
-  if p.tok.tokType = tkDotDot then
-    result := dotdotExpr(p)
-  else begin
-    a := parseExpr(p);
-    case p.tok.tokType of
-      tkEquals: begin
-        result := newNodeP(nkExprEqExpr, p);
-        addSon(result, a);
-        getTok(p);
-        if p.tok.tokType = tkDotDot then
-          addSon(result, dotdotExpr(p))
-        else begin
-          b := parseExpr(p);
-          if p.tok.tokType = tkDotDot then b := dotdotExpr(p, b);
-          addSon(result, b);
-        end
-      end;
-      tkDotDot: result := dotdotExpr(p, a);
-      else result := a
-    end
-  end
-end;
-
-function indexExprList(var p: TParser; first: PNode): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkBracketExpr, p);
-  addSon(result, first);
-  getTok(p);
-  optInd(p, result);
-  while (p.tok.tokType <> tkBracketRi) and (p.tok.tokType <> tkEof)
-  and (p.tok.tokType <> tkSad) do begin
-    a := indexExpr(p);
-    addSon(result, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-  optSad(p);
-  eat(p, tkBracketRi);
-end;
-
-function exprColonEqExpr(var p: TParser; kind: TNodeKind;
-                         tok: TTokType): PNode;
-var
-  a: PNode;
-begin
-  a := parseExpr(p);
-  if p.tok.tokType = tok then begin
-    result := newNodeP(kind, p);
-    getTok(p);
-    //optInd(p, result);
-    addSon(result, a);
-    addSon(result, parseExpr(p));
-  end
-  else
-    result := a
-end;
-
-procedure exprListAux(var p: TParser; elemKind: TNodeKind;
-                      endTok, sepTok: TTokType; result: PNode);
-var
-  a: PNode;
-begin
-  getTok(p);
-  optInd(p, result);
-  while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) do begin
-    a := exprColonEqExpr(p, elemKind, sepTok);
-    addSon(result, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-  eat(p, endTok);
-end;
-
-function qualifiedIdent(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := parseSymbol(p);
-  //optInd(p, result);
-  if p.tok.tokType = tkDot then begin
-    getTok(p);
-    optInd(p, result);
-    a := result;
-    result := newNodeI(nkDotExpr, a.info);
-    addSon(result, a);
-    addSon(result, parseSymbol(p));
-  end;
-end;
-
-procedure qualifiedIdentListAux(var p: TParser; endTok: TTokType;
-                                result: PNode);
-var
-  a: PNode;
-begin
-  getTok(p);
-  optInd(p, result);
-  while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) do begin
-    a := qualifiedIdent(p);
-    addSon(result, a);
-    //optInd(p, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-  eat(p, endTok);
-end;
-
-procedure exprColonEqExprListAux(var p: TParser; elemKind: TNodeKind;
-                                 endTok, sepTok: TTokType; result: PNode);
-var
-  a: PNode;
-begin
-  getTok(p);
-  optInd(p, result);
-  while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof)
-  and (p.tok.tokType <> tkSad) do begin
-    a := exprColonEqExpr(p, elemKind, sepTok);
-    addSon(result, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-  optSad(p);
-  eat(p, endTok);
-end;
-
-function exprColonEqExprList(var p: TParser; kind, elemKind: TNodeKind;
-                             endTok, sepTok: TTokType): PNode;
-begin
-  result := newNodeP(kind, p);
-  exprColonEqExprListAux(p, elemKind, endTok, sepTok, result);
-end;
-
-function parseCast(var p: TParser): PNode;
-begin
-  result := newNodeP(nkCast, p);
-  getTok(p);
-  eat(p, tkBracketLe);
-  optInd(p, result);
-  addSon(result, parseTypeDesc(p));
-  optSad(p);
-  eat(p, tkBracketRi);
-  eat(p, tkParLe);
-  optInd(p, result);
-  addSon(result, parseExpr(p));
-  optSad(p);
-  eat(p, tkParRi);
-end;
-
-function parseAddr(var p: TParser): PNode;
-begin
-  result := newNodeP(nkAddr, p);
-  getTok(p);
-  eat(p, tkParLe);
-  optInd(p, result);
-  addSon(result, parseExpr(p));
-  optSad(p);
-  eat(p, tkParRi);
-end;
-
-procedure setBaseFlags(n: PNode; base: TNumericalBase);
-begin
-  case base of
-    base10: begin end;
-    base2: include(n.flags, nfBase2);
-    base8: include(n.flags, nfBase8);
-    base16: include(n.flags, nfBase16);
-  end
-end;
-
-function identOrLiteral(var p: TParser): PNode;
-begin
-  case p.tok.tokType of
-    tkSymbol: begin
-      result := newIdentNodeP(p.tok.ident, p);
-      getTok(p)
-    end;
-    tkAccent: result := accExpr(p);
-    // literals
-    tkIntLit: begin
-      result := newIntNodeP(nkIntLit, p.tok.iNumber, p);
-      setBaseFlags(result, p.tok.base);
-      getTok(p);
-    end;
-    tkInt8Lit: begin
-      result := newIntNodeP(nkInt8Lit, p.tok.iNumber, p);
-      setBaseFlags(result, p.tok.base);
-      getTok(p);
-    end;
-    tkInt16Lit: begin
-      result := newIntNodeP(nkInt16Lit, p.tok.iNumber, p);
-      setBaseFlags(result, p.tok.base);
-      getTok(p);
-    end;
-    tkInt32Lit: begin
-      result := newIntNodeP(nkInt32Lit, p.tok.iNumber, p);
-      setBaseFlags(result, p.tok.base);
-      getTok(p);
-    end;
-    tkInt64Lit: begin
-      result := newIntNodeP(nkInt64Lit, p.tok.iNumber, p);
-      setBaseFlags(result, p.tok.base);
-      getTok(p);
-    end;
-    tkFloatLit: begin
-      result := newFloatNodeP(nkFloatLit, p.tok.fNumber, p);
-      setBaseFlags(result, p.tok.base);
-      getTok(p);
-    end;
-    tkFloat32Lit: begin
-      result := newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p);
-      setBaseFlags(result, p.tok.base);
-      getTok(p);
-    end;
-    tkFloat64Lit: begin
-      result := newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p);
-      setBaseFlags(result, p.tok.base);
-      getTok(p);
-    end;
-    tkStrLit: begin
-      result := newStrNodeP(nkStrLit, p.tok.literal, p);
-      getTok(p);
-    end;
-    tkRStrLit: begin
-      result := newStrNodeP(nkRStrLit, p.tok.literal, p);
-      getTok(p);
-    end;
-    tkTripleStrLit: begin
-      result := newStrNodeP(nkTripleStrLit, p.tok.literal, p);
-      getTok(p);
-    end;
-    tkCallRStrLit: begin
-      result := newNodeP(nkCallStrLit, p);
-      addSon(result, newIdentNodeP(p.tok.ident, p));
-      addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p));
-      getTok(p);
-    end;
-    tkCallTripleStrLit: begin
-      result := newNodeP(nkCallStrLit, p);
-      addSon(result, newIdentNodeP(p.tok.ident, p));
-      addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p));
-      getTok(p);
-    end;
-    tkCharLit: begin
-      result := newIntNodeP(nkCharLit, ord(p.tok.literal[strStart]), p);
-      getTok(p);
-    end;
-    tkNil: begin
-      result := newNodeP(nkNilLit, p);
-      getTok(p);
-    end;
-    tkParLe: begin // () constructor
-      result := exprColonEqExprList(p, nkPar, nkExprColonExpr, tkParRi,
-                                    tkColon);
-    end;
-    tkCurlyLe: begin // {} constructor
-      result := exprColonEqExprList(p, nkCurly, nkRange, tkCurlyRi, tkDotDot);
-    end;
-    tkBracketLe: begin // [] constructor
-      result := exprColonEqExprList(p, nkBracket, nkExprColonExpr, tkBracketRi,
-                                    tkColon);
-    end;
-    tkCast: result := parseCast(p);
-    tkAddr: result := parseAddr(p);
-    else begin
-      parMessage(p, errExprExpected, tokToStr(p.tok));
-      getTok(p); // we must consume a token here to prevend endless loops!
-      result := nil
-    end
-  end
-end;
-
-function primary(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  // prefix operator?
-  if (p.tok.tokType = tkNot) or (p.tok.tokType = tkOpr) then begin
-    result := newNodeP(nkPrefix, p);
-    a := newIdentNodeP(p.tok.ident, p);
-    addSon(result, a);
-    getTok(p);
-    optInd(p, a);
-    addSon(result, primary(p));
-    exit
-  end
-  else if p.tok.tokType = tkBind then begin
-    result := newNodeP(nkBind, p);
-    getTok(p);
-    optInd(p, result);
-    addSon(result, primary(p));
-    exit
-  end;
-  result := identOrLiteral(p);
-  while true do begin
-    case p.tok.tokType of
-      tkParLe: begin
-        a := result;
-        result := newNodeP(nkCall, p);
-        addSon(result, a);
-        exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result);
-      end;
-      tkDot: begin
-        a := result;
-        result := newNodeP(nkDotExpr, p);
-        addSon(result, a);
-        getTok(p); // skip '.'
-        optInd(p, result);
-        addSon(result, parseSymbol(p));
-      end;
-      tkHat: begin
-        a := result;
-        result := newNodeP(nkDerefExpr, p);
-        addSon(result, a);
-        getTok(p);
-      end;
-      tkBracketLe: result := indexExprList(p, result);
-      else break
-    end
-  end
-end;
-
-function lowestExprAux(var p: TParser; out v: PNode; limit: int): PToken;
-var
-  op, nextop: PToken;
-  opPred: int;
-  v2, node, opNode: PNode;
-begin
-  v := primary(p);
-  // expand while operators have priorities higher than 'limit'
-  op := p.tok;
-  opPred := getPrecedence(p.tok);
-  while (opPred > limit) do begin
-    node := newNodeP(nkInfix, p);
-    opNode := newIdentNodeP(op.ident, p);
-    // skip operator:
-    getTok(p);
-    optInd(p, opNode);
-
-    // read sub-expression with higher priority
-    nextop := lowestExprAux(p, v2, opPred);
-    addSon(node, opNode);
-    addSon(node, v);
-    addSon(node, v2);
-    v := node;
-    op := nextop;
-    opPred := getPrecedence(nextop);
-  end;
-  result := op;  // return first untreated operator
-end;
-
-function lowestExpr(var p: TParser): PNode;
-begin
-{@discard} lowestExprAux(p, result, -1);
-end;
-
-function parseIfExpr(var p: TParser): PNode;
-var
-  branch: PNode;
-begin
-  result := newNodeP(nkIfExpr, p);
-  while true do begin
-    getTok(p); // skip `if`, `elif`
-    branch := newNodeP(nkElifExpr, p);
-    addSon(branch, parseExpr(p));
-    eat(p, tkColon);
-    addSon(branch, parseExpr(p));
-    addSon(result, branch);
-    if p.tok.tokType <> tkElif then break
-  end;
-  branch := newNodeP(nkElseExpr, p);
-  eat(p, tkElse); eat(p, tkColon);
-  addSon(branch, parseExpr(p));
-  addSon(result, branch);
-end;
-
-function parsePragma(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkPragma, p);
-  getTok(p);
-  optInd(p, result);
-  while (p.tok.tokType <> tkCurlyDotRi) and (p.tok.tokType <> tkCurlyRi)
-  and (p.tok.tokType <> tkEof) and (p.tok.tokType <> tkSad) do begin
-    a := exprColonEqExpr(p, nkExprColonExpr, tkColon);
-    addSon(result, a);
-    if p.tok.tokType = tkComma then begin
-      getTok(p);
-      optInd(p, a)
-    end
-  end;
-  optSad(p);
-  if (p.tok.tokType = tkCurlyDotRi) or (p.tok.tokType = tkCurlyRi) then
-    getTok(p)
-  else
-    parMessage(p, errTokenExpected, '.}');
-end;
-
-function identVis(var p: TParser): PNode; // identifier with visability
-var
-  a: PNode;
-begin
-  a := parseSymbol(p);
-  if p.tok.tokType = tkOpr then begin
-    result := newNodeP(nkPostfix, p);
-    addSon(result, newIdentNodeP(p.tok.ident, p));
-    addSon(result, a);
-    getTok(p);
-  end
-  else
-    result := a;
-end;
-
-function identWithPragma(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  a := identVis(p);
-  if p.tok.tokType = tkCurlyDotLe then begin
-    result := newNodeP(nkPragmaExpr, p);
-    addSon(result, a);
-    addSon(result, parsePragma(p));
-  end
-  else
-    result := a
-end;
-
-type
-  TDeclaredIdentFlag = (
-    withPragma,                // identifier may have pragma
-    withBothOptional           // both ':' and '=' parts are optional
-  );
-  TDeclaredIdentFlags = set of TDeclaredIdentFlag;
-
-function parseIdentColonEquals(var p: TParser;
-                               flags: TDeclaredIdentFlags): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkIdentDefs, p);
-  while true do begin
-    case p.tok.tokType of
-      tkSymbol, tkAccent: begin
-        if withPragma in flags then
-          a := identWithPragma(p)
-        else
-          a := parseSymbol(p);
-        if a = nil then exit;
-      end;
-      else break;
-    end;
-    addSon(result, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-  if p.tok.tokType = tkColon then begin
-    getTok(p); optInd(p, result);
-    addSon(result, parseTypeDesc(p));
-  end
-  else begin
-    addSon(result, nil);
-    if (p.tok.tokType <> tkEquals) and not (withBothOptional in flags) then
-      parMessage(p, errColonOrEqualsExpected, tokToStr(p.tok))
-  end;
-  if p.tok.tokType = tkEquals then begin
-    getTok(p); optInd(p, result);
-    addSon(result, parseExpr(p));
-  end
-  else
-    addSon(result, nil);
-end;
-
-function parseTuple(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkTupleTy, p);
-  getTok(p);
-  eat(p, tkBracketLe);
-  optInd(p, result);
-  while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
-    a := parseIdentColonEquals(p, {@set}[]);
-    addSon(result, a);        
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-  optSad(p);
-  eat(p, tkBracketRi);
-end;
-
-function parseParamList(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkFormalParams, p);
-  addSon(result, nil); // return type
-  if p.tok.tokType = tkParLe then begin
-    getTok(p);
-    optInd(p, result);
-    while true do begin
-      case p.tok.tokType of
-        tkSymbol, tkAccent: a := parseIdentColonEquals(p, {@set}[]);
-        tkParRi: break;
-        else begin parMessage(p, errTokenExpected, ')'+''); break; end;
-      end;
-      //optInd(p, a);
-      addSon(result, a);
-      if p.tok.tokType <> tkComma then break;
-      getTok(p);
-      optInd(p, a)
-    end;
-    optSad(p);
-    eat(p, tkParRi);
-  end;
-  if p.tok.tokType = tkColon then begin
-    getTok(p);
-    optInd(p, result);
-    result.sons[0] := parseTypeDesc(p)
-  end
-end;
-
-function parseProcExpr(var p: TParser; isExpr: bool): PNode;
-// either a proc type or a anonymous proc
-var
-  pragmas, params: PNode;
-  info: TLineInfo;
-begin
-  info := parLineInfo(p);
-  getTok(p);
-  params := parseParamList(p);
-  if p.tok.tokType = tkCurlyDotLe then pragmas := parsePragma(p)
-  else pragmas := nil;
-  if (p.tok.tokType = tkEquals) and isExpr then begin
-    result := newNodeI(nkLambda, info);
-    addSon(result, nil); // no name part
-    addSon(result, nil); // no generic parameters
-    addSon(result, params);
-    addSon(result, pragmas);
-    getTok(p); skipComment(p, result);
-    addSon(result, parseStmt(p));
-  end
-  else begin
-    result := newNodeI(nkProcTy, info);
-    addSon(result, params);
-    addSon(result, pragmas);
-  end
-end;
-
-function parseTypeDescKAux(var p: TParser; kind: TNodeKind): PNode;
-begin
-  result := newNodeP(kind, p);
-  getTok(p);
-  optInd(p, result);
-  addSon(result, parseTypeDesc(p));
-end;
-
-function parseExpr(var p: TParser): PNode;
-(*
-expr ::= lowestExpr
-     | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
-     | 'var' expr
-     | 'ref' expr
-     | 'ptr' expr
-     | 'type' expr
-     | 'tuple' tupleDesc
-     | 'proc' paramList [pragma] ['=' stmt] 
-*)
-begin
-  case p.tok.toktype of
-    tkVar:   result := parseTypeDescKAux(p, nkVarTy);
-    tkRef:   result := parseTypeDescKAux(p, nkRefTy);
-    tkPtr:   result := parseTypeDescKAux(p, nkPtrTy);
-    tkType:  result := parseTypeDescKAux(p, nkTypeOfExpr);
-    tkTuple: result := parseTuple(p);
-    tkProc:  result := parseProcExpr(p, true);
-    tkIf:    result := parseIfExpr(p);
-    else     result := lowestExpr(p);
-  end
-end;
-
-function parseTypeDesc(var p: TParser): PNode;
-begin
-  if p.tok.toktype = tkProc then result := parseProcExpr(p, false)
-  else result := parseExpr(p);
-end;
-
-// ---------------------- statement parser ------------------------------------
-function isExprStart(const p: TParser): bool;
-begin
-  case p.tok.tokType of
-    tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind,
-    tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit,
-    tkVar, tkRef, tkPtr, tkTuple, tkType: result := true;
-    else result := false;
-  end;
-end;
-
-function parseExprStmt(var p: TParser): PNode;
-var
-  a, b, e: PNode;
-begin
-  a := lowestExpr(p);
-  if p.tok.tokType = tkEquals then begin
-    getTok(p);
-    optInd(p, result);
-    b := parseExpr(p);
-    result := newNodeI(nkAsgn, a.info);
-    addSon(result, a);
-    addSon(result, b);
-  end
-  else begin
-    result := newNodeP(nkCommand, p);
-    result.info := a.info;
-    addSon(result, a);
-    while true do begin
-      (*case p.tok.tokType of
-        tkColon, tkInd, tkSad, tkDed, tkEof, tkComment: break;
-        else begin end
-      end;*)
-      if not isExprStart(p) then break;
-      e := parseExpr(p);
-      addSon(result, e);
-      if p.tok.tokType <> tkComma then break;
-      getTok(p);
-      optInd(p, a);
-    end;
-    if sonsLen(result) <= 1 then result := a
-    else a := result;
-    if p.tok.tokType = tkColon then begin // macro statement
-      result := newNodeP(nkMacroStmt, p);
-      result.info := a.info;
-      addSon(result, a);
-      getTok(p);
-      skipComment(p, result);
-      if (p.tok.tokType = tkInd)
-           or not (p.tok.TokType in [tkOf, tkElif, tkElse, tkExcept]) then
-        addSon(result, parseStmt(p));
-      while true do begin
-        if p.tok.tokType = tkSad then getTok(p);
-        case p.tok.tokType of
-          tkOf: begin
-            b := newNodeP(nkOfBranch, p);
-            exprListAux(p, nkRange, tkColon, tkDotDot, b);
-          end;
-          tkElif: begin
-            b := newNodeP(nkElifBranch, p);
-            getTok(p);
-            optInd(p, b);
-            addSon(b, parseExpr(p));
-            eat(p, tkColon);
-          end;
-          tkExcept: begin
-            b := newNodeP(nkExceptBranch, p);
-            qualifiedIdentListAux(p, tkColon, b);
-            skipComment(p, b);
-          end;
-          tkElse: begin
-            b := newNodeP(nkElse, p);
-            getTok(p);
-            eat(p, tkColon);
-          end;
-          else break;
-        end;
-        addSon(b, parseStmt(p));
-        addSon(result, b);
-        if b.kind = nkElse then break;
-      end
-    end
-  end
-end;
-
-function parseImportOrIncludeStmt(var p: TParser; kind: TNodeKind): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(kind, p);
-  getTok(p); // skip `import` or `include`
-  optInd(p, result);
-  while true do begin
-    case p.tok.tokType of
-      tkEof, tkSad, tkDed: break;
-      tkSymbol, tkAccent: a := parseSymbol(p);
-      tkRStrLit: begin
-        a := newStrNodeP(nkRStrLit, p.tok.literal, p);
-        getTok(p)
-      end;
-      tkStrLit: begin
-        a := newStrNodeP(nkStrLit, p.tok.literal, p);
-        getTok(p);
-      end;
-      tkTripleStrLit: begin
-        a := newStrNodeP(nkTripleStrLit, p.tok.literal, p);
-        getTok(p)
-      end;
-      else begin
-        parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-        break
-      end
-    end;
-    addSon(result, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-end;
-
-function parseFromStmt(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkFromStmt, p);
-  getTok(p); // skip `from`
-  optInd(p, result);
-  case p.tok.tokType of
-    tkSymbol, tkAccent: a := parseSymbol(p);
-    tkRStrLit:  begin
-      a := newStrNodeP(nkRStrLit, p.tok.literal, p);
-      getTok(p)
-    end;
-    tkStrLit: begin
-      a := newStrNodeP(nkStrLit, p.tok.literal, p);
-      getTok(p);
-    end;
-    tkTripleStrLit: begin
-      a := newStrNodeP(nkTripleStrLit, p.tok.literal, p);
-      getTok(p)
-    end;
-    else begin
-      parMessage(p, errIdentifierExpected, tokToStr(p.tok)); exit
-    end
-  end;
-  addSon(result, a);
-  //optInd(p, a);
-  eat(p, tkImport);
-  optInd(p, result);
-  while true do begin
-    case p.tok.tokType of
-      tkEof, tkSad, tkDed: break;
-      tkSymbol, tkAccent: a := parseSymbol(p);
-      else begin
-        parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-        break
-      end;
-    end;
-    //optInd(p, a);
-    addSon(result, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-end;
-
-function parseReturnOrRaise(var p: TParser; kind: TNodeKind): PNode;
-begin
-  result := newNodeP(kind, p);
-  getTok(p);
-  optInd(p, result);
-  case p.tok.tokType of
-    tkEof, tkSad, tkDed: addSon(result, nil);
-    else addSon(result, parseExpr(p));
-  end;
-end;
-
-function parseYieldOrDiscard(var p: TParser; kind: TNodeKind): PNode;
-begin
-  result := newNodeP(kind, p);
-  getTok(p);
-  optInd(p, result);
-  addSon(result, parseExpr(p));
-end;
-
-function parseBreakOrContinue(var p: TParser; kind: TNodeKind): PNode;
-begin
-  result := newNodeP(kind, p);
-  getTok(p);
-  optInd(p, result);
-  case p.tok.tokType of
-    tkEof, tkSad, tkDed: addSon(result, nil);
-    else addSon(result, parseSymbol(p));
-  end;
-end;
-
-function parseIfOrWhen(var p: TParser; kind: TNodeKind): PNode;
-var
-  branch: PNode;
-begin
-  result := newNodeP(kind, p);
-  while true do begin
-    getTok(p); // skip `if`, `when`, `elif`
-    branch := newNodeP(nkElifBranch, p);
-    optInd(p, branch);
-    addSon(branch, parseExpr(p));
-    eat(p, tkColon);
-    skipComment(p, branch);
-    addSon(branch, parseStmt(p));
-    skipComment(p, branch);
-    addSon(result, branch);
-    if p.tok.tokType <> tkElif then break
-  end;
-  if p.tok.tokType = tkElse then begin
-    branch := newNodeP(nkElse, p);
-    eat(p, tkElse); eat(p, tkColon);
-    skipComment(p, branch);
-    addSon(branch, parseStmt(p));
-    addSon(result, branch);
-  end
-end;
-
-function parseWhile(var p: TParser): PNode;
-begin
-  result := newNodeP(nkWhileStmt, p);
-  getTok(p);
-  optInd(p, result);
-  addSon(result, parseExpr(p));
-  eat(p, tkColon);
-  skipComment(p, result);
-  addSon(result, parseStmt(p));
-end;
-
-function parseCase(var p: TParser): PNode;
-var
-  b: PNode;
-  inElif: bool;
-begin
-  result := newNodeP(nkCaseStmt, p);
-  getTok(p);
-  addSon(result, parseExpr(p));
-  if p.tok.tokType = tkColon then getTok(p);
-  skipComment(p, result);
-  inElif := false;
-  while true do begin
-    if p.tok.tokType = tkSad then getTok(p);
-    case p.tok.tokType of
-      tkOf: begin
-        if inElif then break;
-        b := newNodeP(nkOfBranch, p);
-        exprListAux(p, nkRange, tkColon, tkDotDot, b);
-      end;
-      tkElif: begin
-        inElif := true;
-        b := newNodeP(nkElifBranch, p);
-        getTok(p);
-        optInd(p, b);
-        addSon(b, parseExpr(p));
-        eat(p, tkColon);
-      end;
-      tkElse: begin
-        b := newNodeP(nkElse, p);
-        getTok(p);
-        eat(p, tkColon);
-      end;
-      else break;
-    end;
-    skipComment(p, b);
-    addSon(b, parseStmt(p));
-    addSon(result, b);
-    if b.kind = nkElse then break;
-  end
-end;
-
-function parseTry(var p: TParser): PNode;
-var
-  b: PNode;
-begin
-  result := newNodeP(nkTryStmt, p);
-  getTok(p);
-  eat(p, tkColon);
-  skipComment(p, result);
-  addSon(result, parseStmt(p));
-  b := nil;
-  while true do begin
-    if p.tok.tokType = tkSad then getTok(p);
-    case p.tok.tokType of
-      tkExcept: begin
-        b := newNodeP(nkExceptBranch, p);
-        qualifiedIdentListAux(p, tkColon, b);
-      end;
-      tkFinally: begin
-        b := newNodeP(nkFinally, p);
-        getTok(p);
-        eat(p, tkColon);
-      end;
-      else break;
-    end;
-    skipComment(p, b);
-    addSon(b, parseStmt(p));
-    addSon(result, b);
-    if b.kind = nkFinally then break;
-  end;
-  if b = nil then parMessage(p, errTokenExpected, 'except');
-end;
-
-function parseFor(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkForStmt, p);
-  getTok(p);
-  optInd(p, result);
-  a := parseSymbol(p);
-  addSon(result, a);
-  while p.tok.tokType = tkComma do begin
-    getTok(p);
-    optInd(p, a);
-    a := parseSymbol(p);
-    addSon(result, a);    
-  end;
-  eat(p, tkIn);
-  addSon(result, exprColonEqExpr(p, nkRange, tkDotDot));
-  eat(p, tkColon);
-  skipComment(p, result);
-  addSon(result, parseStmt(p))
-end;
-
-function parseBlock(var p: TParser): PNode;
-begin
-  result := newNodeP(nkBlockStmt, p);
-  getTok(p);
-  optInd(p, result);
-  case p.tok.tokType of
-    tkEof, tkSad, tkDed, tkColon: addSon(result, nil);
-    else addSon(result, parseSymbol(p));
-  end;
-  eat(p, tkColon);
-  skipComment(p, result);
-  addSon(result, parseStmt(p));
-end;
-
-function parseAsm(var p: TParser): PNode;
-begin
-  result := newNodeP(nkAsmStmt, p);
-  getTok(p);
-  optInd(p, result);
-  if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p))
-  else addSon(result, nil);
-  case p.tok.tokType of
-    tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p));
-    tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p));
-    tkTripleStrLit:
-      addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p));
-    else begin
-      parMessage(p, errStringLiteralExpected);
-      addSon(result, nil); exit
-    end;
-  end;
-  getTok(p);
-end;
-
-function parseGenericParamList(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkGenericParams, p);
-  getTok(p);
-  optInd(p, result);
-  while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
-    a := parseIdentColonEquals(p, {@set}[withBothOptional]);
-    addSon(result, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-  optSad(p);
-  eat(p, tkBracketRi);
-end;
-
-function parseRoutine(var p: TParser; kind: TNodeKind): PNode;
-begin
-  result := newNodeP(kind, p);
-  getTok(p);
-  optInd(p, result);
-  addSon(result, identVis(p));
-  if p.tok.tokType = tkBracketLe then addSon(result, parseGenericParamList(p))
-  else addSon(result, nil);
-  addSon(result, parseParamList(p));
-  if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p))
-  else addSon(result, nil);
-  if p.tok.tokType = tkEquals then begin
-    getTok(p); skipComment(p, result);
-    addSon(result, parseStmt(p));
-  end
-  else
-    addSon(result, nil);
-  indAndComment(p, result); // XXX: document this in the grammar!
-end;
-
-function newCommentStmt(var p: TParser): PNode;
-begin
-  result := newNodeP(nkCommentStmt, p);
-  result.info.line := result.info.line - int16(1);
-end;
-
-type
-  TDefParser = function (var p: TParser): PNode;
-
-function parseSection(var p: TParser; kind: TNodeKind;
-                      defparser: TDefParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(kind, p);
-  getTok(p);
-  skipComment(p, result);
-  case p.tok.tokType of
-    tkInd: begin
-      pushInd(p.lex^, p.tok.indent);
-      getTok(p); skipComment(p, result);
-      while true do begin
-        case p.tok.tokType of
-          tkSad: getTok(p);
-          tkSymbol, tkAccent: begin
-            a := defparser(p);
-            skipComment(p, a);
-            addSon(result, a);
-          end;
-          tkDed: begin getTok(p); break end;
-          tkEof: break; // BUGFIX
-          tkComment: begin
-            a := newCommentStmt(p);
-            skipComment(p, a);
-            addSon(result, a);
-          end;
-          else begin
-            parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-            break
-          end
-        end
-      end;
-      popInd(p.lex^);
-    end;
-    tkSymbol, tkAccent, tkParLe: begin
-      // tkParLe is allowed for ``var (x, y) = ...`` tuple parsing
-      addSon(result, defparser(p));
-    end
-    else parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-  end
-end;
-
-function parseConstant(var p: TParser): PNode;
-begin
-  result := newNodeP(nkConstDef, p);
-  addSon(result, identWithPragma(p));
-  if p.tok.tokType = tkColon then begin
-    getTok(p); optInd(p, result);
-    addSon(result, parseTypeDesc(p));
-  end
-  else
-    addSon(result, nil);
-  eat(p, tkEquals);
-  optInd(p, result);
-  addSon(result, parseExpr(p));
-  indAndComment(p, result); // XXX: special extension!
-end;
-
-function parseEnum(var p: TParser): PNode;
-var
-  a, b: PNode;
-begin
-  result := newNodeP(nkEnumTy, p);
-  a := nil;
-  getTok(p);
-  if p.tok.tokType = tkOf then begin
-    a := newNodeP(nkOfInherit, p);
-    getTok(p); optInd(p, a);
-    addSon(a, parseTypeDesc(p));
-    addSon(result, a)
-  end
-  else addSon(result, nil);
-  optInd(p, result);
-
-  while true do begin
-    case p.tok.tokType of
-      tkEof, tkSad, tkDed: break;
-      else a := parseSymbol(p);
-    end;
-    optInd(p, a);
-    if p.tok.tokType = tkEquals then begin
-      getTok(p);
-      optInd(p, a);
-      b := a;
-      a := newNodeP(nkEnumFieldDef, p);
-      addSon(a, b);
-      addSon(a, parseExpr(p));
-      skipComment(p, a);
-    end;
-    if p.tok.tokType = tkComma then begin
-      getTok(p);
-      optInd(p, a)
-    end;
-    addSon(result, a);
-  end
-end;
-
-function parseObjectPart(var p: TParser): PNode; forward;
-
-function parseObjectWhen(var p: TParser): PNode;
-var
-  branch: PNode;
-begin
-  result := newNodeP(nkRecWhen, p);
-  while true do begin
-    getTok(p); // skip `when`, `elif`
-    branch := newNodeP(nkElifBranch, p);
-    optInd(p, branch);
-    addSon(branch, parseExpr(p));
-    eat(p, tkColon);
-    skipComment(p, branch);
-    addSon(branch, parseObjectPart(p));
-    skipComment(p, branch);
-    addSon(result, branch);
-    if p.tok.tokType <> tkElif then break
-  end;
-  if p.tok.tokType = tkElse then begin
-    branch := newNodeP(nkElse, p);
-    eat(p, tkElse); eat(p, tkColon);
-    skipComment(p, branch);
-    addSon(branch, parseObjectPart(p));
-    addSon(result, branch);
-  end
-end;
-
-function parseObjectCase(var p: TParser): PNode;
-var
-  a, b: PNode;
-begin
-  result := newNodeP(nkRecCase, p);
-  getTok(p);
-  a := newNodeP(nkIdentDefs, p);
-  addSon(a, identWithPragma(p));
-  eat(p, tkColon);
-  addSon(a, parseTypeDesc(p));
-  addSon(a, nil);
-  addSon(result, a);
-  skipComment(p, result);
-  while true do begin
-    if p.tok.tokType = tkSad then getTok(p);
-    case p.tok.tokType of
-      tkOf: begin
-        b := newNodeP(nkOfBranch, p);
-        exprListAux(p, nkRange, tkColon, tkDotDot, b);
-      end;
-      tkElse: begin
-        b := newNodeP(nkElse, p);
-        getTok(p);
-        eat(p, tkColon);
-      end;
-      else break;
-    end;
-    skipComment(p, b);
-    addSon(b, parseObjectPart(p));
-    addSon(result, b);
-    if b.kind = nkElse then break;
-  end
-end;
-
-function parseObjectPart(var p: TParser): PNode;
-begin
-  case p.tok.tokType of
-    tkInd: begin
-      result := newNodeP(nkRecList, p);
-      pushInd(p.lex^, p.tok.indent);
-      getTok(p); skipComment(p, result);
-      while true do begin
-        case p.tok.tokType of
-          tkSad: getTok(p);
-          tkCase, tkWhen, tkSymbol, tkAccent, tkNil: begin
-            addSon(result, parseObjectPart(p));
-          end;
-          tkDed: begin getTok(p); break end;
-          tkEof: break;
-          else begin
-            parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-            break
-          end
-        end
-      end;
-      popInd(p.lex^);
-    end;
-    tkWhen: result := parseObjectWhen(p);
-    tkCase: result := parseObjectCase(p);
-    tkSymbol, tkAccent: begin
-      result := parseIdentColonEquals(p, {@set}[withPragma]);
-      skipComment(p, result);
-    end;
-    tkNil: begin
-      result := newNodeP(nkNilLit, p);
-      getTok(p);
-    end;
-    else result := nil
-  end
-end;
-
-function parseObject(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkObjectTy, p);
-  getTok(p);
-  if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p))
-  else addSon(result, nil);
-  if p.tok.tokType = tkOf then begin
-    a := newNodeP(nkOfInherit, p);
-    getTok(p);
-    addSon(a, parseTypeDesc(p));
-    addSon(result, a);
-  end
-  else addSon(result, nil);
-  skipComment(p, result);
-  addSon(result, parseObjectPart(p));
-end;
-
-function parseDistinct(var p: TParser): PNode;
-begin
-  result := newNodeP(nkDistinctTy, p);
-  getTok(p);
-  optInd(p, result);
-  addSon(result, parseTypeDesc(p));
-end;
-
-function parseTypeDef(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkTypeDef, p);
-  addSon(result, identWithPragma(p));
-  if p.tok.tokType = tkBracketLe then addSon(result, parseGenericParamList(p))
-  else addSon(result, nil);
-  if p.tok.tokType = tkEquals then begin
-    getTok(p); optInd(p, result);
-    case p.tok.tokType of
-      tkObject: a := parseObject(p);
-      tkEnum: a := parseEnum(p);
-      tkDistinct: a := parseDistinct(p);
-      else a := parseTypeDesc(p);
-    end;
-    addSon(result, a);
-  end
-  else
-    addSon(result, nil);
-  indAndComment(p, result); // special extension!
-end;
-
-function parseVarTuple(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkVarTuple, p);
-  getTok(p); // skip '('
-  optInd(p, result);
-  while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
-    a := identWithPragma(p);
-    addSon(result, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-  addSon(result, nil); // no type desc
-  optSad(p);
-  eat(p, tkParRi);
-  eat(p, tkEquals);
-  optInd(p, result);
-  addSon(result, parseExpr(p));
-end;
-
-function parseVariable(var p: TParser): PNode;
-begin
-  if p.tok.tokType = tkParLe then 
-    result := parseVarTuple(p)
-  else
-    result := parseIdentColonEquals(p, {@set}[withPragma]);
-  indAndComment(p, result); // special extension!
-end;
-
-function simpleStmt(var p: TParser): PNode;
-begin
-  case p.tok.tokType of
-    tkReturn:   result := parseReturnOrRaise(p, nkReturnStmt);
-    tkRaise:    result := parseReturnOrRaise(p, nkRaiseStmt);
-    tkYield:    result := parseYieldOrDiscard(p, nkYieldStmt);
-    tkDiscard:  result := parseYieldOrDiscard(p, nkDiscardStmt);
-    tkBreak:    result := parseBreakOrContinue(p, nkBreakStmt);
-    tkContinue: result := parseBreakOrContinue(p, nkContinueStmt);
-    tkCurlyDotLe: result := parsePragma(p);
-    tkImport: result := parseImportOrIncludeStmt(p, nkImportStmt);
-    tkFrom: result := parseFromStmt(p);
-    tkInclude: result := parseImportOrIncludeStmt(p, nkIncludeStmt);
-    tkComment: result := newCommentStmt(p);
-    else begin
-      if isExprStart(p) then 
-        result := parseExprStmt(p)
-      else 
-        result := nil;
-    end
-  end;
-  if result <> nil then
-    skipComment(p, result);
-end;
-
-function complexOrSimpleStmt(var p: TParser): PNode;
-begin
-  case p.tok.tokType of
-    tkIf:        result := parseIfOrWhen(p, nkIfStmt);
-    tkWhile:     result := parseWhile(p);
-    tkCase:      result := parseCase(p);
-    tkTry:       result := parseTry(p);
-    tkFor:       result := parseFor(p);
-    tkBlock:     result := parseBlock(p);
-    tkAsm:       result := parseAsm(p);
-    tkProc:      result := parseRoutine(p, nkProcDef);
-    tkMethod:    result := parseRoutine(p, nkMethodDef);
-    tkIterator:  result := parseRoutine(p, nkIteratorDef);
-    tkMacro:     result := parseRoutine(p, nkMacroDef);
-    tkTemplate:  result := parseRoutine(p, nkTemplateDef);
-    tkConverter: result := parseRoutine(p, nkConverterDef);
-    tkType:      result := parseSection(p, nkTypeSection, parseTypeDef);
-    tkConst:     result := parseSection(p, nkConstSection, parseConstant);
-    tkWhen:      result := parseIfOrWhen(p, nkWhenStmt);
-    tkVar:       result := parseSection(p, nkVarSection, parseVariable);
-    else         result := simpleStmt(p);
-  end
-end;
-
-function parseStmt(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  if p.tok.tokType = tkInd then begin
-    result := newNodeP(nkStmtList, p);
-    pushInd(p.lex^, p.tok.indent);
-    getTok(p);
-    while true do begin
-      case p.tok.tokType of
-        tkSad: getTok(p);
-        tkEof: break;
-        tkDed: begin getTok(p); break end;
-        else begin
-          a := complexOrSimpleStmt(p);
-          if a = nil then break;
-          addSon(result, a);
-        end
-      end
-    end;
-    popInd(p.lex^);
-  end
-  else begin
-    // the case statement is only needed for better error messages:
-    case p.tok.tokType of
-      tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm,
-      tkProc, tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar: begin
-        parMessage(p, errComplexStmtRequiresInd);
-        result := nil
-      end
-      else begin
-        result := simpleStmt(p);
-        if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
-        if p.tok.tokType = tkSad then getTok(p);
-      end
-    end
-  end
-end;
-
-function parseAll(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkStmtList, p);
-  while true do begin
-    case p.tok.tokType of
-      tkSad: getTok(p);
-      tkDed, tkInd: parMessage(p, errInvalidIndentation);
-      tkEof: break;
-      else begin
-        a := complexOrSimpleStmt(p);
-        if a = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
-        addSon(result, a);
-      end
-    end
-  end
-end;
-
-function parseTopLevelStmt(var p: TParser): PNode;
-begin
-  result := nil;
-  while true do begin
-    case p.tok.tokType of
-      tkSad: getTok(p);
-      tkDed, tkInd: begin
-        parMessage(p, errInvalidIndentation);
-        break;
-      end;
-      tkEof: break;
-      else begin
-        result := complexOrSimpleStmt(p);
-        if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
-        break
-      end
-    end
-  end
-end;
-
-end.