first steps to the new parser/grammar

This commit is contained in:
Araq 2013-04-19 09:07:01 +02:00
commit 04216fc750
5 changed files with 330 additions and 250 deletions

View file

@ -196,8 +196,10 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "patterns": result = contains(gOptions, optPatterns) of "patterns": result = contains(gOptions, optPatterns)
else: InvalidCmdLineOption(passCmd1, switch, info) else: InvalidCmdLineOption(passCmd1, switch, info)
proc processPath(path: string): string = proc processPath(path: string, notRelativeToProj = false): string =
result = UnixToNativePath(path % ["nimrod", getPrefixDir(), "lib", libpath, let p = if notRelativeToProj or os.isAbsolute(path) or '$' in path: path
else: options.gProjectPath / path
result = UnixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
"home", removeTrailingDirSep(os.getHomeDir()), "home", removeTrailingDirSep(os.getHomeDir()),
"projectname", options.gProjectName, "projectname", options.gProjectName,
"projectpath", options.gProjectPath]) "projectpath", options.gProjectPath])
@ -229,7 +231,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "babelpath": of "babelpath":
if pass in {passCmd2, passPP}: if pass in {passCmd2, passPP}:
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
let path = processPath(arg) let path = processPath(arg, notRelativeToProj=true)
babelpath(path, info) babelpath(path, info)
of "excludepath": of "excludepath":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
@ -453,7 +455,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
incl(gGlobalOptions, optGenScript) incl(gGlobalOptions, optGenScript)
of "lib": of "lib":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
libpath = processPath(arg) libpath = processPath(arg, notRelativeToProj=true)
of "putenv": of "putenv":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
splitSwitch(arg, key, val, pass, info) splitSwitch(arg, key, val, pass, info)

View file

@ -237,7 +237,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
of tkSymbol: of tkSymbol:
dispA(result, "<span class=\"Identifier\">$1</span>", dispA(result, "<span class=\"Identifier\">$1</span>",
"\\spanIdentifier{$1}", [toRope(esc(d.target, literal))]) "\\spanIdentifier{$1}", [toRope(esc(d.target, literal))])
of tkInd, tkSad, tkDed, tkSpaces, tkInvalid: of tkInd, tkSpaces, tkInvalid:
app(result, literal) app(result, literal)
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi, of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe, tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -58,8 +58,7 @@ type
tkParDotLe, tkParDotRi, # (. and .) tkParDotLe, tkParDotRi, # (. and .)
tkComma, tkSemiColon, tkComma, tkSemiColon,
tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkColon, tkColonColon, tkEquals, tkDot, tkDotDot,
tkOpr, tkComment, tkAccent, tkInd, tkSad, tkOpr, tkComment, tkAccent, tkInd,
tkDed, # pseudo token types used by the source renderers:
tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr, tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
TTokTypes* = set[TTokType] TTokTypes* = set[TTokType]
@ -92,7 +91,7 @@ const
",", ";", ",", ";",
":", "::", "=", ".", "..", ":", "::", "=", ".", "..",
"tkOpr", "tkComment", "`", "[new indentation]", "tkOpr", "tkComment", "`", "[new indentation]",
"[same indentation]", "[dedentation]", "tkSpaces", "tkInfixOpr", "tkSpaces", "tkInfixOpr",
"tkPrefixOpr", "tkPostfixOpr"] "tkPrefixOpr", "tkPostfixOpr"]
type type
@ -102,7 +101,8 @@ type
base2, base8, base16 base2, base8, base16
TToken* = object # a Nimrod token TToken* = object # a Nimrod token
tokType*: TTokType # the type of the token tokType*: TTokType # the type of the token
indent*: int # the indentation; only valid if tokType = tkIndent indent*: int # the indentation; != -1 if the token has been
# preceeded with indentation
ident*: PIdent # the parsed identifier ident*: PIdent # the parsed identifier
iNumber*: BiggestInt # the parsed integer literal iNumber*: BiggestInt # the parsed integer literal
fNumber*: BiggestFloat # the parsed floating point literal fNumber*: BiggestFloat # the parsed floating point literal
@ -113,8 +113,6 @@ type
TLexer* = object of TBaseLexer TLexer* = object of TBaseLexer
fileIdx*: int32 fileIdx*: int32
indentStack*: seq[int] # the indentation stack
dedent*: int # counter for DED token generation
indentAhead*: int # if > 0 an indendation has already been read indentAhead*: int # if > 0 an indendation has already been read
# this is needed because scanning comments # this is needed because scanning comments
# needs so much look-ahead # needs so much look-ahead
@ -122,9 +120,6 @@ type
var gLinesCompiled*: int # all lines that have been compiled var gLinesCompiled*: int # all lines that have been compiled
proc pushInd*(L: var TLexer, indent: int)
proc popInd*(L: var TLexer)
proc isKeyword*(kind: TTokType): bool proc isKeyword*(kind: TTokType): bool
proc openLexer*(lex: var TLexer, fileidx: int32, inputstream: PLLStream) proc openLexer*(lex: var TLexer, fileidx: int32, inputstream: PLLStream)
proc rawGetTok*(L: var TLexer, tok: var TToken) proc rawGetTok*(L: var TLexer, tok: var TToken)
@ -154,29 +149,12 @@ proc isNimrodIdentifier*(s: string): bool =
inc(i) inc(i)
result = true result = true
proc pushInd(L: var TLexer, indent: int) =
var length = len(L.indentStack)
setlen(L.indentStack, length + 1)
if (indent > L.indentStack[length - 1]):
L.indentstack[length] = indent
else:
InternalError("pushInd")
proc popInd(L: var TLexer) =
var length = len(L.indentStack)
setlen(L.indentStack, length - 1)
proc findIdent(L: TLexer, indent: int): bool =
for i in countdown(len(L.indentStack) - 1, 0):
if L.indentStack[i] == indent:
return true
proc tokToStr*(tok: TToken): string = proc tokToStr*(tok: TToken): string =
case tok.tokType case tok.tokType
of tkIntLit..tkInt64Lit: result = $tok.iNumber of tkIntLit..tkInt64Lit: result = $tok.iNumber
of tkFloatLit..tkFloat64Lit: result = $tok.fNumber of tkFloatLit..tkFloat64Lit: result = $tok.fNumber
of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal
of tkParLe..tkColon, tkEof, tkInd, tkSad, tkDed, tkAccent: of tkParLe..tkColon, tkEof, tkInd, tkAccent:
result = tokTypeToStr[tok.tokType] result = tokTypeToStr[tok.tokType]
else: else:
if tok.ident != nil: if tok.ident != nil:
@ -216,7 +194,6 @@ proc fillToken(L: var TToken) =
proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) = proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
openBaseLexer(lex, inputstream) openBaseLexer(lex, inputstream)
lex.indentStack = @[0]
lex.fileIdx = fileIdx lex.fileIdx = fileIdx
lex.indentAhead = - 1 lex.indentAhead = - 1
inc(lex.Linenumber, inputstream.lineOffset) inc(lex.Linenumber, inputstream.lineOffset)
@ -651,23 +628,9 @@ proc getOperator(L: var TLexer, tok: var TToken) =
Inc(pos) Inc(pos)
endOperator(L, tok, pos, h) endOperator(L, tok, pos, h)
proc handleIndentation(L: var TLexer, tok: var TToken, indent: int) = proc handleIndentation(tok: var TToken, indent: int) {.inline.} =
tok.indent = indent tok.indent = indent
var i = high(L.indentStack) tok.tokType = tkInd
if indent > L.indentStack[i]:
tok.tokType = tkInd
elif indent == L.indentStack[i]:
tok.tokType = tkSad
else:
# check we have the indentation somewhere in the stack:
while (i >= 0) and (indent != L.indentStack[i]):
dec(i)
inc(L.dedent)
dec(L.dedent)
tok.tokType = tkDed
if i < 0:
tok.tokType = tkSad # for the parser it is better as SAD
lexMessage(L, errInvalidIndentation)
proc scanComment(L: var TLexer, tok: var TToken) = proc scanComment(L: var TLexer, tok: var TToken) =
var pos = L.bufpos var pos = L.bufpos
@ -705,7 +668,6 @@ proc scanComment(L: var TLexer, tok: var TToken) =
else: else:
if buf[pos] > ' ': if buf[pos] > ' ':
L.indentAhead = indent L.indentAhead = indent
inc(L.dedent)
break break
L.bufpos = pos L.bufpos = pos
@ -727,7 +689,7 @@ proc skip(L: var TLexer, tok: var TToken) =
Inc(pos) Inc(pos)
Inc(indent) Inc(indent)
if (buf[pos] > ' '): if (buf[pos] > ' '):
handleIndentation(L, tok, indent) handleIndentation(tok, indent)
break break
else: else:
break # EndOfFile also leaves the loop break # EndOfFile also leaves the loop
@ -735,13 +697,9 @@ proc skip(L: var TLexer, tok: var TToken) =
proc rawGetTok(L: var TLexer, tok: var TToken) = proc rawGetTok(L: var TLexer, tok: var TToken) =
fillToken(tok) fillToken(tok)
if L.dedent > 0: if L.indentAhead >= 0:
dec(L.dedent) handleIndentation(tok, L.indentAhead)
if L.indentAhead >= 0: L.indentAhead = - 1
handleIndentation(L, tok, L.indentAhead)
L.indentAhead = - 1
else:
tok.tokType = tkDed
return return
skip(L, tok) skip(L, tok)
# got an documentation comment or tkIndent, return that: # got an documentation comment or tkIndent, return that:

View file

@ -19,7 +19,7 @@ import
proc ppGetTok(L: var TLexer, tok: var TToken) = proc ppGetTok(L: var TLexer, tok: var TToken) =
# simple filter # simple filter
rawGetTok(L, tok) rawGetTok(L, tok)
while tok.tokType in {tkInd, tkSad, tkDed, tkComment}: rawGetTok(L, tok) while tok.tokType in {tkInd, tkComment}: rawGetTok(L, tok)
proc parseExpr(L: var TLexer, tok: var TToken): bool proc parseExpr(L: var TLexer, tok: var TToken): bool
proc parseAtom(L: var TLexer, tok: var TToken): bool = proc parseAtom(L: var TLexer, tok: var TToken): bool =

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -14,6 +14,16 @@
# be seen as a refinement of the grammar, as it specifies how the AST is built # be seen as a refinement of the grammar, as it specifies how the AST is built
# from the grammar and how comments belong to the AST. # from the grammar and how comments belong to the AST.
# In fact the grammar is generated from this file:
when isMainModule:
import pegs
var outp = open("compiler/grammar.txt", fmWrite)
for line in lines("compiler/parser.nim"):
if line =~ peg" \s* '#| ' {.*}":
outp.writeln matches[0]
outp.close
import import
llstream, lexer, idents, strutils, ast, msgs llstream, lexer, idents, strutils, ast, msgs
@ -22,7 +32,7 @@ type
# is being parsed # is being parsed
lex*: TLexer # the lexer that is used for parsing lex*: TLexer # the lexer that is used for parsing
tok*: TToken # the current token tok*: TToken # the current token
currInd: int # current indentation (for skipInd)
proc ParseAll*(p: var TParser): PNode proc ParseAll*(p: var TParser): PNode
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream) proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
@ -81,6 +91,15 @@ proc parMessage(p: TParser, msg: TMsgKind, arg: string = "") =
proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) = proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
lexMessage(p.lex, msg, prettyTok(tok)) lexMessage(p.lex, msg, prettyTok(tok))
template withInd(p: expr, body: stmt) {.immediate.} =
let oldInd = p.currInd
p.currInd = p.tok.indent
body
p.currInd = oldInd
template realInd(p): bool = p.tok.tokType == tkInd and p.tok.ident > p.currInd
template sameInd(p): bool = p.tok.tokType == tkInd and p.tok.ident == p.currInd
proc skipComment(p: var TParser, node: PNode) = proc skipComment(p: var TParser, node: PNode) =
if p.tok.tokType == tkComment: if p.tok.tokType == tkComment:
if node != nil: if node != nil:
@ -91,17 +110,17 @@ proc skipComment(p: var TParser, node: PNode) =
getTok(p) getTok(p)
proc skipInd(p: var TParser) = proc skipInd(p: var TParser) =
if p.tok.tokType == tkInd: getTok(p) if realInd(p): getTok(p)
proc optPar(p: var TParser) = proc optPar(p: var TParser) =
if p.tok.tokType == tkSad or p.tok.tokType == tkInd: getTok(p) if p.tok.tokType == tkInd and p.tok.indent >= p.currInd: getTok(p)
proc optInd(p: var TParser, n: PNode) = proc optInd(p: var TParser, n: PNode) =
skipComment(p, n) skipComment(p, n)
skipInd(p) skipInd(p)
proc ExpectNl(p: TParser) = proc ExpectNl(p: TParser) =
if p.tok.tokType notin {tkEof, tkSad, tkInd, tkDed, tkComment}: if p.tok.tokType notin {tkEof, tkInd, tkComment}:
lexMessage(p.lex, errNewlineExpected, prettyTok(p.tok)) lexMessage(p.lex, errNewlineExpected, prettyTok(p.tok))
proc expectIdentOrKeyw(p: TParser) = proc expectIdentOrKeyw(p: TParser) =
@ -120,7 +139,7 @@ proc parLineInfo(p: TParser): TLineInfo =
result = getLineInfo(p.lex) result = getLineInfo(p.lex)
proc indAndComment(p: var TParser, n: PNode) = proc indAndComment(p: var TParser, n: PNode) =
if p.tok.tokType == tkInd: if p.tok.tokType == tkInd and p.tok.indent > p.currInd:
var info = parLineInfo(p) var info = parLineInfo(p)
getTok(p) getTok(p)
if p.tok.tokType == tkComment: skipComment(p, n) if p.tok.tokType == tkComment: skipComment(p, n)
@ -195,7 +214,37 @@ proc getPrecedence(tok: TToken): int =
proc isOperator(tok: TToken): bool = proc isOperator(tok: TToken): bool =
result = getPrecedence(tok) >= 0 result = getPrecedence(tok) >= 0
#| module = stmt? (IND{=} stmt)*
#|
#| comma = ',' COMMENT? IND?
#| semicolon = ';' COMMENT IND?
#| colon = ':' COMMENT? IND?
#| 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' | 'addr' | 'static' | '..'
#|
#| prefixOperator = operator
#|
#| optInd = COMMENT? IND?
#| optPar = IND{>} | IND{=}
#|
#| lowestExpr = assignExpr (OP0 optInd assignExpr)*
#| assignExpr = orExpr (OP1 optInd orExpr)*
#| orExpr = andExpr (OP2 optInd andExpr)*
#| andExpr = cmpExpr (OP3 optInd cmpExpr)*
#| cmpExpr = sliceExpr (OP4 optInd sliceExpr)*
#| sliceExpr = ampExpr (OP5 optInd ampExpr)*
#| ampExpr = plusExpr (OP6 optInd plusExpr)*
#| plusExpr = mulExpr (OP7 optInd mulExpr)*
#| mulExpr = dollarExpr (OP8 optInd dollarExpr)*
#| dollarExpr = primary (OP9 optInd primary)*
proc parseSymbol(p: var TParser): PNode = proc parseSymbol(p: var TParser): PNode =
#| symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`'
#| | IDENT
case p.tok.tokType case p.tok.tokType
of tkSymbol: of tkSymbol:
result = newIdentNodeP(p.tok.ident, p) result = newIdentNodeP(p.tok.ident, p)
@ -237,15 +286,17 @@ proc parseSymbol(p: var TParser): PNode =
result = ast.emptyNode result = ast.emptyNode
proc indexExpr(p: var TParser): PNode = proc indexExpr(p: var TParser): PNode =
#| indexExpr = expr
result = parseExpr(p) result = parseExpr(p)
proc indexExprList(p: var TParser, first: PNode, k: TNodeKind, proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
endToken: TTokType): PNode = endToken: TTokType): PNode =
#| indexExprList = indexExpr (comma indexExpr)* comma?
result = newNodeP(k, p) result = newNodeP(k, p)
addSon(result, first) addSon(result, first)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while p.tok.tokType notin {endToken, tkEof, tkSad}: while p.tok.tokType notin {endToken, tkEof}:
var a = indexExpr(p) var a = indexExpr(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
@ -255,6 +306,7 @@ proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
eat(p, endToken) eat(p, endToken)
proc exprColonEqExpr(p: var TParser): PNode = proc exprColonEqExpr(p: var TParser): PNode =
#| exprColonEqExpr = expr (':'|'=' expr)?
var a = parseExpr(p) var a = parseExpr(p)
if p.tok.tokType == tkColon: if p.tok.tokType == tkColon:
result = newNodeP(nkExprColonExpr, p) result = newNodeP(nkExprColonExpr, p)
@ -272,6 +324,7 @@ proc exprColonEqExpr(p: var TParser): PNode =
result = a result = a
proc exprList(p: var TParser, endTok: TTokType, result: PNode) = proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
#| exprList = expr (comma expr)* comma?
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof): while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
@ -283,6 +336,7 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
eat(p, endTok) eat(p, endTok)
proc dotExpr(p: var TParser, a: PNode): PNode = proc dotExpr(p: var TParser, a: PNode): PNode =
#| dotExpr = expr '.' optInd ('type' | 'addr' | symbol)
var info = p.lex.getlineInfo var info = p.lex.getlineInfo
getTok(p) getTok(p)
optInd(p, a) optInd(p, a)
@ -301,26 +355,16 @@ proc dotExpr(p: var TParser, a: PNode): PNode =
addSon(result, parseSymbol(p)) addSon(result, parseSymbol(p))
proc qualifiedIdent(p: var TParser): PNode = proc qualifiedIdent(p: var TParser): PNode =
result = parseSymbol(p) #optInd(p, result); #| qualifiedIdent = symbol ('.' optInd ('type' | 'addr' | symbol))?
result = parseSymbol(p)
if p.tok.tokType == tkDot: result = dotExpr(p, result) if p.tok.tokType == tkDot: result = dotExpr(p, result)
proc qualifiedIdentListAux(p: var TParser, endTok: TTokType, result: PNode) =
getTok(p)
optInd(p, result)
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
var a = qualifiedIdent(p)
addSon(result, a) #optInd(p, a);
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
eat(p, endTok)
proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof) and while p.tok.tokType != endTok and p.tok.tokType != tkEof and
(p.tok.tokType != tkSad) and (p.tok.tokType != tkInd): not (p.tok.tokType == tkInd and p.tok.indent >= p.currInd):
var a = exprColonEqExpr(p) var a = exprColonEqExpr(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
@ -331,10 +375,12 @@ proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
proc exprColonEqExprList(p: var TParser, kind: TNodeKind, proc exprColonEqExprList(p: var TParser, kind: TNodeKind,
endTok: TTokType): PNode = endTok: TTokType): PNode =
#| exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
result = newNodeP(kind, p) result = newNodeP(kind, p)
exprColonEqExprListAux(p, endTok, result) exprColonEqExprListAux(p, endTok, result)
proc setOrTableConstr(p: var TParser): PNode = proc setOrTableConstr(p: var TParser): PNode =
#| setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
result = newNodeP(nkCurly, p) result = newNodeP(nkCurly, p)
getTok(p) # skip '{' getTok(p) # skip '{'
optInd(p, result) optInd(p, result)
@ -342,7 +388,7 @@ proc setOrTableConstr(p: var TParser): PNode =
getTok(p) # skip ':' getTok(p) # skip ':'
result.kind = nkTableConstr result.kind = nkTableConstr
else: else:
while p.tok.tokType notin {tkCurlyRi, tkEof, tkSad, tkInd}: while p.tok.tokType notin {tkCurlyRi, tkEof, tkInd}:
var a = exprColonEqExpr(p) var a = exprColonEqExpr(p)
if a.kind == nkExprColonExpr: result.kind = nkTableConstr if a.kind == nkExprColonExpr: result.kind = nkTableConstr
addSon(result, a) addSon(result, a)
@ -353,6 +399,7 @@ proc setOrTableConstr(p: var TParser): PNode =
eat(p, tkCurlyRi) # skip '}' eat(p, tkCurlyRi) # skip '}'
proc parseCast(p: var TParser): PNode = proc parseCast(p: var TParser): PNode =
#| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
result = newNodeP(nkCast, p) result = newNodeP(nkCast, p)
getTok(p) getTok(p)
eat(p, tkBracketLe) eat(p, tkBracketLe)
@ -366,15 +413,6 @@ proc parseCast(p: var TParser): PNode =
optPar(p) optPar(p)
eat(p, tkParRi) eat(p, tkParRi)
proc parseAddr(p: var TParser): PNode =
result = newNodeP(nkAddr, p)
getTok(p)
eat(p, tkParLe)
optInd(p, result)
addSon(result, parseExpr(p))
optPar(p)
eat(p, tkParRi)
proc setBaseFlags(n: PNode, base: TNumericalBase) = proc setBaseFlags(n: PNode, base: TNumericalBase) =
case base case base
of base10: nil of base10: nil
@ -398,6 +436,18 @@ proc parseGStrLit(p: var TParser, a: PNode): PNode =
result = a result = a
proc identOrLiteral(p: var TParser): PNode = proc identOrLiteral(p: var TParser): PNode =
#| generalizedLit ::= GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
#| identOrLiteral = generalizedLit | symbol
#| | 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
#| | tupleConstr | arrayConstr | setOrTableConstr
#| | castExpr
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
#| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
case p.tok.tokType case p.tok.tokType
of tkSymbol: of tkSymbol:
result = newIdentNodeP(p.tok.ident, p) result = newIdentNodeP(p.tok.ident, p)
@ -493,6 +543,11 @@ proc identOrLiteral(p: var TParser): PNode =
result = ast.emptyNode result = ast.emptyNode
proc primarySuffix(p: var TParser, r: PNode): PNode = proc primarySuffix(p: var TParser, r: PNode): PNode =
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
#| | doBlocks
#| | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
#| | '[' optInd indexExprList optPar ']'
#| | '{' optInd indexExprList optPar '}'
result = r result = r
while true: while true:
case p.tok.tokType case p.tok.tokType
@ -547,6 +602,11 @@ proc lowestExpr(p: var TParser, mode = pmNormal): PNode =
result = lowestExprAux(p, -1, mode) result = lowestExprAux(p, -1, mode)
proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
#| condExpr = expr ':' optInd expr optInd
#| ('elif' expr ':' optInd expr optInd)*
#| 'else' ':' optInd expr
#| ifExpr = 'if' condExpr
#| whenExpr = 'when' condExpr
result = newNodeP(kind, p) result = newNodeP(kind, p)
while true: while true:
getTok(p) # skip `if`, `elif` getTok(p) # skip `if`, `elif`
@ -566,11 +626,11 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
addSon(result, branch) addSon(result, branch)
proc parsePragma(p: var TParser): PNode = proc parsePragma(p: var TParser): PNode =
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
result = newNodeP(nkPragma, p) result = newNodeP(nkPragma, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while (p.tok.tokType != tkCurlyDotRi) and (p.tok.tokType != tkCurlyRi) and while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
(p.tok.tokType != tkEof) and (p.tok.tokType != tkSad):
var a = exprColonEqExpr(p) var a = exprColonEqExpr(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType == tkComma: if p.tok.tokType == tkComma:
@ -581,7 +641,7 @@ proc parsePragma(p: var TParser): PNode =
else: parMessage(p, errTokenExpected, ".}") else: parMessage(p, errTokenExpected, ".}")
proc identVis(p: var TParser): PNode = proc identVis(p: var TParser): PNode =
# identifier with visability #| identVis = symbol opr? # postfix position
var a = parseSymbol(p) var a = parseSymbol(p)
if p.tok.tokType == tkOpr: if p.tok.tokType == tkOpr:
result = newNodeP(nkPostfix, p) result = newNodeP(nkPostfix, p)
@ -592,6 +652,7 @@ proc identVis(p: var TParser): PNode =
result = a result = a
proc identWithPragma(p: var TParser): PNode = proc identWithPragma(p: var TParser): PNode =
#| identWithPragma = identVis pragma?
var a = identVis(p) var a = identVis(p)
if p.tok.tokType == tkCurlyDotLe: if p.tok.tokType == tkCurlyDotLe:
result = newNodeP(nkPragmaExpr, p) result = newNodeP(nkPragmaExpr, p)
@ -607,6 +668,10 @@ type
TDeclaredIdentFlags = set[TDeclaredIdentFlag] TDeclaredIdentFlags = set[TDeclaredIdentFlag]
proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode = 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 var a: PNode
result = newNodeP(nkIdentDefs, p) result = newNodeP(nkIdentDefs, p)
while true: while true:
@ -636,12 +701,16 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
addSon(result, ast.emptyNode) addSon(result, ast.emptyNode)
proc parseTuple(p: var TParser, indentAllowed = false): PNode = proc parseTuple(p: var TParser, indentAllowed = false): PNode =
#| inlTupleDecl = 'tuple'
#| [' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
#| extTupleDecl = 'tuple'
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
result = newNodeP(nkTupleTy, p) result = newNodeP(nkTupleTy, p)
getTok(p) getTok(p)
if p.tok.tokType == tkBracketLe: if p.tok.tokType == tkBracketLe:
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent): while p.tok.tokType in {tkSymbol, tkAccent}:
var a = parseIdentColonEquals(p, {}) var a = parseIdentColonEquals(p, {})
addSon(result, a) addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemicolon}: break if p.tok.tokType notin {tkComma, tkSemicolon}: break
@ -651,29 +720,27 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
eat(p, tkBracketRi) eat(p, tkBracketRi)
elif indentAllowed: elif indentAllowed:
skipComment(p, result) skipComment(p, result)
if p.tok.tokType == tkInd: if realInd(p):
pushInd(p.lex, p.tok.indent) withInd(p):
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
while true: while true:
case p.tok.tokType case p.tok.tokType
of tkSad: of tkSymbol, tkAccent:
var a = parseIdentColonEquals(p, {})
skipComment(p, a)
addSon(result, a)
of tkEof: break
else:
parMessage(p, errIdentifierExpected, p.tok)
break
if not sameInd(p): break
getTok(p) getTok(p)
of tkSymbol, tkAccent:
var a = parseIdentColonEquals(p, {})
skipComment(p, a)
addSon(result, a)
of tkDed:
getTok(p)
break
of tkEof:
break
else:
parMessage(p, errIdentifierExpected, p.tok)
break
popInd(p.lex)
proc parseParamList(p: var TParser, retColon = true): PNode = proc parseParamList(p: var TParser, retColon = true): PNode =
#| paramList = '(' (identColonEquals (comma/semicolon identColonEquals)*)? ')'
#| paramListArrow = paramList? ('->' optInd typeDesc)?
#| paramListColon = paramList? (':' optInd typeDesc)?
var a: PNode var a: PNode
result = newNodeP(nkFormalParams, p) result = newNodeP(nkFormalParams, p)
addSon(result, ast.emptyNode) # return type addSon(result, ast.emptyNode) # return type
@ -681,7 +748,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while true: while true:
case p.tok.tokType #optInd(p, a); case p.tok.tokType
of tkSymbol, tkAccent: of tkSymbol, tkAccent:
a = parseIdentColonEquals(p, {withBothOptional}) a = parseIdentColonEquals(p, {withBothOptional})
of tkParRi: of tkParRi:
@ -707,6 +774,7 @@ proc optPragmas(p: var TParser): PNode =
else: result = ast.emptyNode else: result = ast.emptyNode
proc parseDoBlock(p: var TParser): PNode = proc parseDoBlock(p: var TParser): PNode =
#| doBlock = 'do' paramListArrow pragmas? colcom stmt
let info = parLineInfo(p) let info = parLineInfo(p)
getTok(p) getTok(p)
let params = parseParamList(p, retColon=false) let params = parseParamList(p, retColon=false)
@ -718,10 +786,12 @@ proc parseDoBlock(p: var TParser): PNode =
pragmas = pragmas) pragmas = pragmas)
proc parseDoBlocks(p: var TParser, call: PNode) = proc parseDoBlocks(p: var TParser, call: PNode) =
#| doBlocks = doBlock*
while p.tok.tokType == tkDo: while p.tok.tokType == tkDo:
addSon(call, parseDoBlock(p)) addSon(call, parseDoBlock(p))
proc parseProcExpr(p: var TParser, isExpr: bool): PNode = proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
# either a proc type or a anonymous proc # either a proc type or a anonymous proc
var var
pragmas, params: PNode pragmas, params: PNode
@ -752,7 +822,8 @@ proc isExprStart(p: TParser): bool =
result = true result = true
else: result = false else: result = false
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, mode: TPrimaryMode): PNode = proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
mode: TPrimaryMode): PNode =
result = newNodeP(kind, p) result = newNodeP(kind, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
@ -760,11 +831,10 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, mode: TPrimaryMode): PNo
addSon(result, primary(p, mode)) addSon(result, primary(p, mode))
proc parseExpr(p: var TParser): PNode = proc parseExpr(p: var TParser): PNode =
# #| expr = lowestExpr
#expr ::= lowestExpr #| | ifExpr
# | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr #| | whenExpr
# | 'when' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr #| | caseExpr
#
case p.tok.tokType: case p.tok.tokType:
of tkIf: result = parseIfExpr(p, nkIfExpr) of tkIf: result = parseIfExpr(p, nkIfExpr)
of tkWhen: result = parseIfExpr(p, nkWhenExpr) of tkWhen: result = parseIfExpr(p, nkWhenExpr)
@ -778,7 +848,13 @@ proc parseDistinct(p: var TParser): PNode
proc parseEnum(p: var TParser): PNode proc parseEnum(p: var TParser): PNode
proc primary(p: var TParser, mode: TPrimaryMode): PNode = proc primary(p: var TParser, mode: TPrimaryMode): PNode =
# prefix operator? #| typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
#| | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
#| primary = typeKeyw typeDescK
#| / prefixOperator* identOrLiteral primarySuffix*
#| / 'addr' primary
#| / 'static' primary
#| / 'bind' primary
if isOperator(p.tok): if isOperator(p.tok):
let isSigil = IsSigilLike(p.tok) let isSigil = IsSigilLike(p.tok)
result = newNodeP(nkPrefix, p) result = newNodeP(nkPrefix, p)
@ -854,6 +930,14 @@ proc parseTypeDefAux(p: var TParser): PNode =
result = lowestExpr(p, pmTypeDef) result = lowestExpr(p, pmTypeDef)
proc parseExprStmt(p: var TParser): PNode = proc parseExprStmt(p: var TParser): PNode =
#| exprStmt = lowestExpr (
#| '=' optInd expr
#| / doBlocks
#| / ':' stmt? ('of' exprList ':' stmt
#| | 'elif' expr ':' stmt
#| | 'except' exprList ':' stmt
#| | 'else' ':' stmt )?
#| )
var a = lowestExpr(p) var a = lowestExpr(p)
if p.tok.tokType == tkEquals: if p.tok.tokType == tkEquals:
getTok(p) getTok(p)
@ -865,6 +949,7 @@ proc parseExprStmt(p: var TParser): PNode =
else: else:
var call = if a.kind == nkCall: a var call = if a.kind == nkCall: a
else: newNode(nkCommand, a.info, @[a]) else: newNode(nkCommand, a.info, @[a])
# XXX this is clearly a bug: p(a, b) c should not parse as p(a, b, c)!
while true: while true:
if not isExprStart(p): break if not isExprStart(p): break
var e = parseExpr(p) var e = parseExpr(p)
@ -881,12 +966,12 @@ proc parseExprStmt(p: var TParser): PNode =
result = call result = call
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
if p.tok.tokType == tkSad: getTok(p) if sameInd(p): getTok(p)
if p.tok.TokType notin {tkOf, tkElif, tkElse, tkExcept}: if p.tok.TokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p) let body = parseStmt(p)
addSon(result, newProcNode(nkDo, body.info, body)) addSon(result, newProcNode(nkDo, body.info, body))
while true: while true:
if p.tok.tokType == tkSad: getTok(p) if sameInd(p): getTok(p)
var b: PNode var b: PNode
case p.tok.tokType case p.tok.tokType
of tkOf: of tkOf:
@ -900,7 +985,7 @@ proc parseExprStmt(p: var TParser): PNode =
eat(p, tkColon) eat(p, tkColon)
of tkExcept: of tkExcept:
b = newNodeP(nkExceptBranch, p) b = newNodeP(nkExceptBranch, p)
qualifiedIdentListAux(p, tkColon, b) exprList(p, tkColon, b)
skipComment(p, b) skipComment(p, b)
of tkElse: of tkElse:
b = newNodeP(nkElse, p) b = newNodeP(nkElse, p)
@ -912,6 +997,9 @@ proc parseExprStmt(p: var TParser): PNode =
if b.kind == nkElse: break if b.kind == nkElse: break
proc parseImport(p: var TParser, kind: TNodeKind): PNode = proc parseImport(p: var TParser, kind: TNodeKind): PNode =
#| importStmt = 'import' optInd expr
#| ((comma expr)*
#| / 'except' optInd expr (comma expr)*)
result = newNodeP(kind, p) result = newNodeP(kind, p)
getTok(p) # skip `import` or `export` getTok(p) # skip `import` or `export`
optInd(p, result) optInd(p, result)
@ -922,7 +1010,8 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
result.kind = succ(kind) result.kind = succ(kind)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while p.tok.tokType notin {tkEof, tkSad, tkDed}: while true:
# was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
a = parseExpr(p) a = parseExpr(p)
if a.kind == nkEmpty: break if a.kind == nkEmpty: break
addSon(result, a) addSon(result, a)
@ -932,10 +1021,12 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
expectNl(p) expectNl(p)
proc parseIncludeStmt(p: var TParser): PNode = proc parseIncludeStmt(p: var TParser): PNode =
#| includeStmt = 'include' optInd expr (comma expr)*
result = newNodeP(nkIncludeStmt, p) result = newNodeP(nkIncludeStmt, p)
getTok(p) # skip `import` or `include` getTok(p) # skip `import` or `include`
optInd(p, result) optInd(p, result)
while p.tok.tokType notin {tkEof, tkSad, tkDed}: while true:
# was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
var a = parseExpr(p) var a = parseExpr(p)
if a.kind == nkEmpty: break if a.kind == nkEmpty: break
addSon(result, a) addSon(result, a)
@ -945,6 +1036,7 @@ proc parseIncludeStmt(p: var TParser): PNode =
expectNl(p) expectNl(p)
proc parseFromStmt(p: var TParser): PNode = proc parseFromStmt(p: var TParser): PNode =
#| fromStmt = 'from' expr 'import' optInd expr (comma expr)*
result = newNodeP(nkFromStmt, p) result = newNodeP(nkFromStmt, p)
getTok(p) # skip `from` getTok(p) # skip `from`
optInd(p, result) optInd(p, result)
@ -952,7 +1044,8 @@ proc parseFromStmt(p: var TParser): PNode =
addSon(result, a) #optInd(p, a); addSon(result, a) #optInd(p, a);
eat(p, tkImport) eat(p, tkImport)
optInd(p, result) optInd(p, result)
while p.tok.tokType notin {tkEof, tkSad, tkDed}: while true:
# p.tok.tokType notin {tkEof, tkSad, tkDed}:
a = parseExpr(p) a = parseExpr(p)
if a.kind == nkEmpty: break if a.kind == nkEmpty: break
addSon(result, a) addSon(result, a)
@ -962,28 +1055,25 @@ proc parseFromStmt(p: var TParser): PNode =
expectNl(p) expectNl(p)
proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode = 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) result = newNodeP(kind, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
case p.tok.tokType case p.tok.tokType
of tkEof, tkSad, tkDed: addSon(result, ast.emptyNode) of tkEof, tkInd: addSon(result, ast.emptyNode)
else: addSon(result, parseExpr(p)) else: addSon(result, parseExpr(p))
proc parseYieldOrDiscard(p: var TParser, kind: TNodeKind): PNode =
result = newNodeP(kind, p)
getTok(p)
optInd(p, result)
addSon(result, parseExpr(p))
proc parseBreakOrContinue(p: var TParser, kind: TNodeKind): PNode =
result = newNodeP(kind, p)
getTok(p)
optInd(p, result)
case p.tok.tokType
of tkEof, tkSad, tkDed: addSon(result, ast.emptyNode)
else: addSon(result, parseSymbol(p))
proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode = proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
#| condStmt = expr colcom stmt COMMENT?
#| ('elif' expr colcom stmt)*
#| ('else' colcom stmt)?
#| ifStmt = 'if' condStmt
#| whenStmt = 'when' condStmt
result = newNodeP(kind, p) result = newNodeP(kind, p)
while true: while true:
getTok(p) # skip `if`, `when`, `elif` getTok(p) # skip `if`, `when`, `elif`
@ -1005,6 +1095,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
addSon(result, branch) addSon(result, branch)
proc parseWhile(p: var TParser): PNode = proc parseWhile(p: var TParser): PNode =
#| whileStmt = 'while' expr colcom stmt
result = newNodeP(nkWhileStmt, p) result = newNodeP(nkWhileStmt, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
@ -1014,6 +1105,13 @@ proc parseWhile(p: var TParser): PNode =
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
proc parseCase(p: var TParser): PNode = 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
#| | IND{=} ofBranches)
var var
b: PNode b: PNode
inElif= false inElif= false
@ -1024,13 +1122,14 @@ proc parseCase(p: var TParser): PNode =
if p.tok.tokType == tkColon: getTok(p) if p.tok.tokType == tkColon: getTok(p)
skipComment(p, result) skipComment(p, result)
if p.tok.tokType == tkInd: let oldInd = p.currInd
pushInd(p.lex, p.tok.indent) if realInd(p):
p.currInd = p.tok.indent
getTok(p) getTok(p)
wasIndented = true wasIndented = true
while true: while true:
if p.tok.tokType == tkSad: getTok(p) if sameInd(p): getTok(p)
case p.tok.tokType case p.tok.tokType
of tkOf: of tkOf:
if inElif: break if inElif: break
@ -1054,10 +1153,12 @@ proc parseCase(p: var TParser): PNode =
if b.kind == nkElse: break if b.kind == nkElse: break
if wasIndented: if wasIndented:
if p.tok.tokType != tkEof: eat(p, tkDed) p.currInd = oldInd
popInd(p.lex)
proc parseTry(p: var TParser): PNode = proc parseTry(p: var TParser): PNode =
#| tryStmt = 'try' colcom stmt &('except'|'finally')
#| ('except' exprList colcom stmt)*
#| ('finally' colcom stmt)?
result = newNodeP(nkTryStmt, p) result = newNodeP(nkTryStmt, p)
getTok(p) getTok(p)
eat(p, tkColon) eat(p, tkColon)
@ -1069,7 +1170,7 @@ proc parseTry(p: var TParser): PNode =
case p.tok.tokType case p.tok.tokType
of tkExcept: of tkExcept:
b = newNodeP(nkExceptBranch, p) b = newNodeP(nkExceptBranch, p)
qualifiedIdentListAux(p, tkColon, b) exprList(p, tkColon, b)
of tkFinally: of tkFinally:
b = newNodeP(nkFinally, p) b = newNodeP(nkFinally, p)
getTok(p) getTok(p)
@ -1082,6 +1183,7 @@ proc parseTry(p: var TParser): PNode =
if b == nil: parMessage(p, errTokenExpected, "except") if b == nil: parMessage(p, errTokenExpected, "except")
proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode = proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
#| exceptBlock = 'except' colcom stmt
result = newNodeP(kind, p) result = newNodeP(kind, p)
getTok(p) getTok(p)
eat(p, tkColon) eat(p, tkColon)
@ -1089,9 +1191,9 @@ proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
proc parseFor(p: var TParser): PNode = proc parseFor(p: var TParser): PNode =
#| forStmt = 'for' symbol (comma symbol)* 'in' expr colcom stmt
result = newNodeP(nkForStmt, p) result = newNodeP(nkForStmt, p)
getTok(p) getTok(p)
optInd(p, result)
var a = parseSymbol(p) var a = parseSymbol(p)
addSon(result, a) addSon(result, a)
while p.tok.tokType == tkComma: while p.tok.tokType == tkComma:
@ -1106,28 +1208,27 @@ proc parseFor(p: var TParser): PNode =
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
proc parseBlock(p: var TParser): PNode = proc parseBlock(p: var TParser): PNode =
#| blockStmt = 'block' symbol? colcom stmt
result = newNodeP(nkBlockStmt, p) result = newNodeP(nkBlockStmt, p)
getTok(p) getTok(p)
optInd(p, result) if p.tok.tokType = tkColon: addSon(result, ast.emptyNode)
case p.tok.tokType
of tkEof, tkSad, tkDed, tkColon: addSon(result, ast.emptyNode)
else: addSon(result, parseSymbol(p)) else: addSon(result, parseSymbol(p))
eat(p, tkColon) eat(p, tkColon)
skipComment(p, result) skipComment(p, result)
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
proc parseStatic(p: var TParser): PNode = proc parseStatic(p: var TParser): PNode =
#| staticStmt = 'static' colcom stmt
result = newNodeP(nkStaticStmt, p) result = newNodeP(nkStaticStmt, p)
getTok(p) getTok(p)
optInd(p, result)
eat(p, tkColon) eat(p, tkColon)
skipComment(p, result) skipComment(p, result)
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
proc parseAsm(p: var TParser): PNode = proc parseAsm(p: var TParser): PNode =
#| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT)
result = newNodeP(nkAsmStmt, p) result = newNodeP(nkAsmStmt, p)
getTok(p) getTok(p)
optInd(p, result)
if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p)) if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p))
else: addSon(result, ast.emptyNode) else: addSon(result, ast.emptyNode)
case p.tok.tokType case p.tok.tokType
@ -1142,6 +1243,7 @@ proc parseAsm(p: var TParser): PNode =
getTok(p) getTok(p)
proc parseGenericParam(p: var TParser): PNode = proc parseGenericParam(p: var TParser): PNode =
#| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
var a: PNode var a: PNode
result = newNodeP(nkIdentDefs, p) result = newNodeP(nkIdentDefs, p)
while true: while true:
@ -1168,6 +1270,8 @@ proc parseGenericParam(p: var TParser): PNode =
addSon(result, ast.emptyNode) addSon(result, ast.emptyNode)
proc parseGenericParamList(p: var TParser): PNode = proc parseGenericParamList(p: var TParser): PNode =
#| genericParamList = '[' optInd
#| (genericParam (comma/semicolon genericParam)*)? optPar ']'
result = newNodeP(nkGenericParams, p) result = newNodeP(nkGenericParams, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
@ -1181,11 +1285,15 @@ proc parseGenericParamList(p: var TParser): PNode =
eat(p, tkBracketRi) eat(p, tkBracketRi)
proc parsePattern(p: var TParser): PNode = proc parsePattern(p: var TParser): PNode =
#| pattern = '{' stmt '}'
eat(p, tkCurlyLe) eat(p, tkCurlyLe)
result = parseStmt(p) result = parseStmt(p)
eat(p, tkCurlyRi) eat(p, tkCurlyRi)
proc parseRoutine(p: var TParser, kind: TNodeKind): PNode = 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) result = newNodeP(kind, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
@ -1205,9 +1313,10 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
else: else:
addSon(result, ast.emptyNode) addSon(result, ast.emptyNode)
indAndComment(p, result) # XXX: document this in the grammar! indAndComment(p, result)
proc newCommentStmt(p: var TParser): PNode = proc newCommentStmt(p: var TParser): PNode =
#| commentStmt = COMMENT
result = newNodeP(nkCommentStmt, p) result = newNodeP(nkCommentStmt, p)
result.info.line = result.info.line - int16(1) - int16(p.tok.iNumber) result.info.line = result.info.line - int16(1) - int16(p.tok.iNumber)
@ -1216,41 +1325,40 @@ type
proc parseSection(p: var TParser, kind: TNodeKind, proc parseSection(p: var TParser, kind: TNodeKind,
defparser: TDefParser): PNode = defparser: TDefParser): PNode =
#| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
result = newNodeP(kind, p) result = newNodeP(kind, p)
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
case p.tok.tokType case p.tok.tokType
of tkInd: of tkInd:
pushInd(p.lex, p.tok.indent) if not realInd(p): parMessage(p, errInvalidIndentation)
getTok(p) withInd(p):
skipComment(p, result) getTok(p)
while true: skipComment(p, result)
case p.tok.tokType while true:
of tkSad: case p.tok.tokType
getTok(p) of tkSad:
of tkSymbol, tkAccent: getTok(p)
var a = defparser(p) of tkSymbol, tkAccent:
skipComment(p, a) var a = defparser(p)
addSon(result, a) skipComment(p, a)
of tkDed: addSon(result, a)
getTok(p) of tkEof:
break break
of tkEof: of tkComment:
break # BUGFIX var a = newCommentStmt(p)
of tkComment: skipComment(p, a)
var a = newCommentStmt(p) addSon(result, a)
skipComment(p, a) else:
addSon(result, a) parMessage(p, errIdentifierExpected, p.tok)
else: break
parMessage(p, errIdentifierExpected, p.tok)
break
popInd(p.lex)
of tkSymbol, tkAccent, tkParLe: of tkSymbol, tkAccent, tkParLe:
# tkParLe is allowed for ``var (x, y) = ...`` tuple parsing # tkParLe is allowed for ``var (x, y) = ...`` tuple parsing
addSon(result, defparser(p)) addSon(result, defparser(p))
else: parMessage(p, errIdentifierExpected, p.tok) else: parMessage(p, errIdentifierExpected, p.tok)
proc parseConstant(p: var TParser): PNode = proc parseConstant(p: var TParser): PNode =
#| constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment
result = newNodeP(nkConstDef, p) result = newNodeP(nkConstDef, p)
addSon(result, identWithPragma(p)) addSon(result, identWithPragma(p))
if p.tok.tokType == tkColon: if p.tok.tokType == tkColon:
@ -1262,24 +1370,21 @@ proc parseConstant(p: var TParser): PNode =
eat(p, tkEquals) eat(p, tkEquals)
optInd(p, result) optInd(p, result)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
indAndComment(p, result) # XXX: special extension! indAndComment(p, result)
proc parseEnum(p: var TParser): PNode = proc parseEnum(p: var TParser): PNode =
var a, b: PNode #| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
result = newNodeP(nkEnumTy, p) result = newNodeP(nkEnumTy, p)
a = nil
getTok(p) getTok(p)
addSon(result, ast.emptyNode) addSon(result, ast.emptyNode)
optInd(p, result) optInd(p, result)
while true: while p.tok.tokType notin {tkEof, tkInd}:
case p.tok.tokType var a = parseSymbol(p)
of tkEof, tkSad, tkDed: break
else: a = parseSymbol(p)
optInd(p, a) optInd(p, a)
if p.tok.tokType == tkEquals: if p.tok.tokType == tkEquals:
getTok(p) getTok(p)
optInd(p, a) optInd(p, a)
b = a var b = a
a = newNodeP(nkEnumFieldDef, p) a = newNodeP(nkEnumFieldDef, p)
addSon(a, b) addSon(a, b)
addSon(a, parseExpr(p)) addSon(a, parseExpr(p))
@ -1293,6 +1398,9 @@ proc parseEnum(p: var TParser): PNode =
proc parseObjectPart(p: var TParser): PNode proc parseObjectPart(p: var TParser): PNode
proc parseObjectWhen(p: var TParser): PNode = proc parseObjectWhen(p: var TParser): PNode =
#| objectWhen = 'when' expr colcom objectPart COMMENT?
#| ('elif' expr colcom objectPart COMMENT?)*
#| ('else' colcom objectPart COMMENT?)?
result = newNodeP(nkRecWhen, p) result = newNodeP(nkRecWhen, p)
while true: while true:
getTok(p) # skip `when`, `elif` getTok(p) # skip `when`, `elif`
@ -1311,9 +1419,17 @@ proc parseObjectWhen(p: var TParser): PNode =
eat(p, tkColon) eat(p, tkColon)
skipComment(p, branch) skipComment(p, branch)
addSon(branch, parseObjectPart(p)) addSon(branch, parseObjectPart(p))
# XXX no skipComment(p, branch) here?
addSon(result, branch) addSon(result, branch)
proc parseObjectCase(p: var TParser): PNode = proc parseObjectCase(p: var TParser): PNode =
#| objectBranch = 'of' exprList colcom objectPart
#| objectBranches = objectBranch (IND{=} objectBranch)*
#| (IND{=} 'elif' expr colcom objectPart)*
#| (IND{=} 'else' colcom objectPart)?
#| objectCase = 'case' identWithPragma ':'? COMMENT?
#| (IND{>} objectBranches
#| | IND{=} objectBranches)
result = newNodeP(nkRecCase, p) result = newNodeP(nkRecCase, p)
getTok(p) getTok(p)
var a = newNodeP(nkIdentDefs, p) var a = newNodeP(nkIdentDefs, p)
@ -1403,6 +1519,7 @@ proc parseObject(p: var TParser): PNode =
addSon(result, parseObjectPart(p)) addSon(result, parseObjectPart(p))
proc parseDistinct(p: var TParser): PNode = proc parseDistinct(p: var TParser): PNode =
#| distinct = 'distinct' optInd typeDesc
result = newNodeP(nkDistinctTy, p) result = newNodeP(nkDistinctTy, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
@ -1444,6 +1561,7 @@ proc parseVariable(p: var TParser): PNode =
indAndComment(p, result) # special extension! indAndComment(p, result) # special extension!
proc parseBind(p: var TParser, k: TNodeKind): PNode = proc parseBind(p: var TParser, k: TNodeKind): PNode =
#| bindStmt = 'bind' optInd qualifiedIdent (comma qualifiedIdent)*
result = newNodeP(k, p) result = newNodeP(k, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
@ -1456,11 +1574,13 @@ proc parseBind(p: var TParser, k: TNodeKind): PNode =
expectNl(p) expectNl(p)
proc parseStmtPragma(p: var TParser): PNode = proc parseStmtPragma(p: var TParser): PNode =
#| pragmaStmt = pragma (':' COMMENT? stmt)?
result = parsePragma(p) result = parsePragma(p)
if p.tok.tokType == tkColon: if p.tok.tokType == tkColon:
let a = result let a = result
result = newNodeI(nkPragmaBlock, a.info) result = newNodeI(nkPragmaBlock, a.info)
getTok(p) getTok(p)
skipComment(p, result)
result.add a result.add a
result.add parseStmt(p) result.add parseStmt(p)
@ -1470,8 +1590,8 @@ proc simpleStmt(p: var TParser): PNode =
of tkRaise: result = parseReturnOrRaise(p, nkRaiseStmt) of tkRaise: result = parseReturnOrRaise(p, nkRaiseStmt)
of tkYield: result = parseReturnOrRaise(p, nkYieldStmt) of tkYield: result = parseReturnOrRaise(p, nkYieldStmt)
of tkDiscard: result = parseReturnOrRaise(p, nkDiscardStmt) of tkDiscard: result = parseReturnOrRaise(p, nkDiscardStmt)
of tkBreak: result = parseBreakOrContinue(p, nkBreakStmt) of tkBreak: result = parseReturnOrRaise(p, nkBreakStmt)
of tkContinue: result = parseBreakOrContinue(p, nkContinueStmt) of tkContinue: result = parseReturnOrRaise(p, nkContinueStmt)
of tkCurlyDotLe: result = parseStmtPragma(p) of tkCurlyDotLe: result = parseStmtPragma(p)
of tkImport: result = parseImport(p, nkImportStmt) of tkImport: result = parseImport(p, nkImportStmt)
of tkExport: result = parseImport(p, nkExportStmt) of tkExport: result = parseImport(p, nkExportStmt)