first steps to the new parser/grammar
This commit is contained in:
parent
4f09794be9
commit
04216fc750
5 changed files with 330 additions and 250 deletions
|
|
@ -196,8 +196,10 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
|||
of "patterns": result = contains(gOptions, optPatterns)
|
||||
else: InvalidCmdLineOption(passCmd1, switch, info)
|
||||
|
||||
proc processPath(path: string): string =
|
||||
result = UnixToNativePath(path % ["nimrod", getPrefixDir(), "lib", libpath,
|
||||
proc processPath(path: string, notRelativeToProj = false): string =
|
||||
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()),
|
||||
"projectname", options.gProjectName,
|
||||
"projectpath", options.gProjectPath])
|
||||
|
|
@ -229,7 +231,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
|||
of "babelpath":
|
||||
if pass in {passCmd2, passPP}:
|
||||
expectArg(switch, arg, pass, info)
|
||||
let path = processPath(arg)
|
||||
let path = processPath(arg, notRelativeToProj=true)
|
||||
babelpath(path, info)
|
||||
of "excludepath":
|
||||
expectArg(switch, arg, pass, info)
|
||||
|
|
@ -453,7 +455,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
|||
incl(gGlobalOptions, optGenScript)
|
||||
of "lib":
|
||||
expectArg(switch, arg, pass, info)
|
||||
libpath = processPath(arg)
|
||||
libpath = processPath(arg, notRelativeToProj=true)
|
||||
of "putenv":
|
||||
expectArg(switch, arg, pass, info)
|
||||
splitSwitch(arg, key, val, pass, info)
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
|||
of tkSymbol:
|
||||
dispA(result, "<span class=\"Identifier\">$1</span>",
|
||||
"\\spanIdentifier{$1}", [toRope(esc(d.target, literal))])
|
||||
of tkInd, tkSad, tkDed, tkSpaces, tkInvalid:
|
||||
of tkInd, tkSpaces, tkInvalid:
|
||||
app(result, literal)
|
||||
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
|
||||
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -58,8 +58,7 @@ type
|
|||
tkParDotLe, tkParDotRi, # (. and .)
|
||||
tkComma, tkSemiColon,
|
||||
tkColon, tkColonColon, tkEquals, tkDot, tkDotDot,
|
||||
tkOpr, tkComment, tkAccent, tkInd, tkSad,
|
||||
tkDed, # pseudo token types used by the source renderers:
|
||||
tkOpr, tkComment, tkAccent, tkInd,
|
||||
tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
|
||||
|
||||
TTokTypes* = set[TTokType]
|
||||
|
|
@ -92,7 +91,7 @@ const
|
|||
",", ";",
|
||||
":", "::", "=", ".", "..",
|
||||
"tkOpr", "tkComment", "`", "[new indentation]",
|
||||
"[same indentation]", "[dedentation]", "tkSpaces", "tkInfixOpr",
|
||||
"tkSpaces", "tkInfixOpr",
|
||||
"tkPrefixOpr", "tkPostfixOpr"]
|
||||
|
||||
type
|
||||
|
|
@ -102,7 +101,8 @@ type
|
|||
base2, base8, base16
|
||||
TToken* = object # a Nimrod 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
|
||||
iNumber*: BiggestInt # the parsed integer literal
|
||||
fNumber*: BiggestFloat # the parsed floating point literal
|
||||
|
|
@ -113,8 +113,6 @@ type
|
|||
|
||||
TLexer* = object of TBaseLexer
|
||||
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
|
||||
# this is needed because scanning comments
|
||||
# needs so much look-ahead
|
||||
|
|
@ -122,9 +120,6 @@ type
|
|||
|
||||
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 openLexer*(lex: var TLexer, fileidx: int32, inputstream: PLLStream)
|
||||
proc rawGetTok*(L: var TLexer, tok: var TToken)
|
||||
|
|
@ -154,29 +149,12 @@ proc isNimrodIdentifier*(s: string): bool =
|
|||
inc(i)
|
||||
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 =
|
||||
case tok.tokType
|
||||
of tkIntLit..tkInt64Lit: result = $tok.iNumber
|
||||
of tkFloatLit..tkFloat64Lit: result = $tok.fNumber
|
||||
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]
|
||||
else:
|
||||
if tok.ident != nil:
|
||||
|
|
@ -216,7 +194,6 @@ proc fillToken(L: var TToken) =
|
|||
|
||||
proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
|
||||
openBaseLexer(lex, inputstream)
|
||||
lex.indentStack = @[0]
|
||||
lex.fileIdx = fileIdx
|
||||
lex.indentAhead = - 1
|
||||
inc(lex.Linenumber, inputstream.lineOffset)
|
||||
|
|
@ -651,23 +628,9 @@ proc getOperator(L: var TLexer, tok: var TToken) =
|
|||
Inc(pos)
|
||||
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
|
||||
var i = high(L.indentStack)
|
||||
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)
|
||||
tok.tokType = tkInd
|
||||
|
||||
proc scanComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
|
|
@ -705,7 +668,6 @@ proc scanComment(L: var TLexer, tok: var TToken) =
|
|||
else:
|
||||
if buf[pos] > ' ':
|
||||
L.indentAhead = indent
|
||||
inc(L.dedent)
|
||||
break
|
||||
L.bufpos = pos
|
||||
|
||||
|
|
@ -727,7 +689,7 @@ proc skip(L: var TLexer, tok: var TToken) =
|
|||
Inc(pos)
|
||||
Inc(indent)
|
||||
if (buf[pos] > ' '):
|
||||
handleIndentation(L, tok, indent)
|
||||
handleIndentation(tok, indent)
|
||||
break
|
||||
else:
|
||||
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) =
|
||||
fillToken(tok)
|
||||
if L.dedent > 0:
|
||||
dec(L.dedent)
|
||||
if L.indentAhead >= 0:
|
||||
handleIndentation(L, tok, L.indentAhead)
|
||||
L.indentAhead = - 1
|
||||
else:
|
||||
tok.tokType = tkDed
|
||||
if L.indentAhead >= 0:
|
||||
handleIndentation(tok, L.indentAhead)
|
||||
L.indentAhead = - 1
|
||||
return
|
||||
skip(L, tok)
|
||||
# got an documentation comment or tkIndent, return that:
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import
|
|||
proc ppGetTok(L: var TLexer, tok: var TToken) =
|
||||
# simple filter
|
||||
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 parseAtom(L: var TLexer, tok: var TToken): bool =
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# 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
|
||||
# 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
|
||||
llstream, lexer, idents, strutils, ast, msgs
|
||||
|
||||
|
|
@ -22,7 +32,7 @@ type
|
|||
# is being parsed
|
||||
lex*: TLexer # the lexer that is used for parsing
|
||||
tok*: TToken # the current token
|
||||
|
||||
currInd: int # current indentation (for skipInd)
|
||||
|
||||
proc ParseAll*(p: var TParser): PNode
|
||||
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) =
|
||||
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) =
|
||||
if p.tok.tokType == tkComment:
|
||||
if node != nil:
|
||||
|
|
@ -91,17 +110,17 @@ proc skipComment(p: var TParser, node: PNode) =
|
|||
getTok(p)
|
||||
|
||||
proc skipInd(p: var TParser) =
|
||||
if p.tok.tokType == tkInd: getTok(p)
|
||||
if realInd(p): getTok(p)
|
||||
|
||||
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) =
|
||||
skipComment(p, n)
|
||||
skipInd(p)
|
||||
|
||||
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))
|
||||
|
||||
proc expectIdentOrKeyw(p: TParser) =
|
||||
|
|
@ -120,7 +139,7 @@ proc parLineInfo(p: TParser): TLineInfo =
|
|||
result = getLineInfo(p.lex)
|
||||
|
||||
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)
|
||||
getTok(p)
|
||||
if p.tok.tokType == tkComment: skipComment(p, n)
|
||||
|
|
@ -195,7 +214,37 @@ proc getPrecedence(tok: TToken): int =
|
|||
proc isOperator(tok: TToken): bool =
|
||||
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 =
|
||||
#| symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`'
|
||||
#| | IDENT
|
||||
case p.tok.tokType
|
||||
of tkSymbol:
|
||||
result = newIdentNodeP(p.tok.ident, p)
|
||||
|
|
@ -237,15 +286,17 @@ proc parseSymbol(p: var TParser): PNode =
|
|||
result = ast.emptyNode
|
||||
|
||||
proc indexExpr(p: var TParser): PNode =
|
||||
#| indexExpr = expr
|
||||
result = parseExpr(p)
|
||||
|
||||
proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
|
||||
endToken: TTokType): PNode =
|
||||
#| indexExprList = indexExpr (comma indexExpr)* comma?
|
||||
result = newNodeP(k, p)
|
||||
addSon(result, first)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
while p.tok.tokType notin {endToken, tkEof, tkSad}:
|
||||
while p.tok.tokType notin {endToken, tkEof}:
|
||||
var a = indexExpr(p)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType != tkComma: break
|
||||
|
|
@ -255,6 +306,7 @@ proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
|
|||
eat(p, endToken)
|
||||
|
||||
proc exprColonEqExpr(p: var TParser): PNode =
|
||||
#| exprColonEqExpr = expr (':'|'=' expr)?
|
||||
var a = parseExpr(p)
|
||||
if p.tok.tokType == tkColon:
|
||||
result = newNodeP(nkExprColonExpr, p)
|
||||
|
|
@ -272,6 +324,7 @@ proc exprColonEqExpr(p: var TParser): PNode =
|
|||
result = a
|
||||
|
||||
proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
|
||||
#| exprList = expr (comma expr)* comma?
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
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)
|
||||
|
||||
proc dotExpr(p: var TParser, a: PNode): PNode =
|
||||
#| dotExpr = expr '.' optInd ('type' | 'addr' | symbol)
|
||||
var info = p.lex.getlineInfo
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
|
|
@ -301,26 +355,16 @@ proc dotExpr(p: var TParser, a: PNode): PNode =
|
|||
addSon(result, parseSymbol(p))
|
||||
|
||||
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)
|
||||
|
||||
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) =
|
||||
assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof) and
|
||||
(p.tok.tokType != tkSad) and (p.tok.tokType != tkInd):
|
||||
while p.tok.tokType != endTok and p.tok.tokType != tkEof and
|
||||
not (p.tok.tokType == tkInd and p.tok.indent >= p.currInd):
|
||||
var a = exprColonEqExpr(p)
|
||||
addSon(result, a)
|
||||
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,
|
||||
endTok: TTokType): PNode =
|
||||
#| exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
|
||||
result = newNodeP(kind, p)
|
||||
exprColonEqExprListAux(p, endTok, result)
|
||||
|
||||
proc setOrTableConstr(p: var TParser): PNode =
|
||||
#| setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
|
||||
result = newNodeP(nkCurly, p)
|
||||
getTok(p) # skip '{'
|
||||
optInd(p, result)
|
||||
|
|
@ -342,7 +388,7 @@ proc setOrTableConstr(p: var TParser): PNode =
|
|||
getTok(p) # skip ':'
|
||||
result.kind = nkTableConstr
|
||||
else:
|
||||
while p.tok.tokType notin {tkCurlyRi, tkEof, tkSad, tkInd}:
|
||||
while p.tok.tokType notin {tkCurlyRi, tkEof, tkInd}:
|
||||
var a = exprColonEqExpr(p)
|
||||
if a.kind == nkExprColonExpr: result.kind = nkTableConstr
|
||||
addSon(result, a)
|
||||
|
|
@ -353,6 +399,7 @@ proc setOrTableConstr(p: var TParser): PNode =
|
|||
eat(p, tkCurlyRi) # skip '}'
|
||||
|
||||
proc parseCast(p: var TParser): PNode =
|
||||
#| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
|
||||
result = newNodeP(nkCast, p)
|
||||
getTok(p)
|
||||
eat(p, tkBracketLe)
|
||||
|
|
@ -366,15 +413,6 @@ proc parseCast(p: var TParser): PNode =
|
|||
optPar(p)
|
||||
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) =
|
||||
case base
|
||||
of base10: nil
|
||||
|
|
@ -398,6 +436,18 @@ proc parseGStrLit(p: var TParser, a: PNode): PNode =
|
|||
result = a
|
||||
|
||||
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
|
||||
of tkSymbol:
|
||||
result = newIdentNodeP(p.tok.ident, p)
|
||||
|
|
@ -493,6 +543,11 @@ proc identOrLiteral(p: var TParser): PNode =
|
|||
result = ast.emptyNode
|
||||
|
||||
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
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
|
|
@ -547,6 +602,11 @@ proc lowestExpr(p: var TParser, mode = pmNormal): PNode =
|
|||
result = lowestExprAux(p, -1, mode)
|
||||
|
||||
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)
|
||||
while true:
|
||||
getTok(p) # skip `if`, `elif`
|
||||
|
|
@ -566,11 +626,11 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
|
|||
addSon(result, branch)
|
||||
|
||||
proc parsePragma(p: var TParser): PNode =
|
||||
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
|
||||
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):
|
||||
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
|
||||
var a = exprColonEqExpr(p)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType == tkComma:
|
||||
|
|
@ -581,7 +641,7 @@ proc parsePragma(p: var TParser): PNode =
|
|||
else: parMessage(p, errTokenExpected, ".}")
|
||||
|
||||
proc identVis(p: var TParser): PNode =
|
||||
# identifier with visability
|
||||
#| identVis = symbol opr? # postfix position
|
||||
var a = parseSymbol(p)
|
||||
if p.tok.tokType == tkOpr:
|
||||
result = newNodeP(nkPostfix, p)
|
||||
|
|
@ -592,6 +652,7 @@ proc identVis(p: var TParser): PNode =
|
|||
result = a
|
||||
|
||||
proc identWithPragma(p: var TParser): PNode =
|
||||
#| identWithPragma = identVis pragma?
|
||||
var a = identVis(p)
|
||||
if p.tok.tokType == tkCurlyDotLe:
|
||||
result = newNodeP(nkPragmaExpr, p)
|
||||
|
|
@ -607,6 +668,10 @@ type
|
|||
TDeclaredIdentFlags = set[TDeclaredIdentFlag]
|
||||
|
||||
proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
||||
#| declColonEquals = identWithPragma (comma identWithPragma)* comma?
|
||||
#| (':' optInd typeDesc)? ('=' optInd expr)?
|
||||
#| identColonEquals = ident (comma ident)* comma?
|
||||
#| (':' optInd typeDesc)? ('=' optInd expr)?)
|
||||
var a: PNode
|
||||
result = newNodeP(nkIdentDefs, p)
|
||||
while true:
|
||||
|
|
@ -636,12 +701,16 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
|||
addSon(result, ast.emptyNode)
|
||||
|
||||
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)
|
||||
getTok(p)
|
||||
if p.tok.tokType == tkBracketLe:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent):
|
||||
while p.tok.tokType in {tkSymbol, tkAccent}:
|
||||
var a = parseIdentColonEquals(p, {})
|
||||
addSon(result, a)
|
||||
if p.tok.tokType notin {tkComma, tkSemicolon}: break
|
||||
|
|
@ -651,29 +720,27 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
|||
eat(p, tkBracketRi)
|
||||
elif indentAllowed:
|
||||
skipComment(p, result)
|
||||
if p.tok.tokType == tkInd:
|
||||
pushInd(p.lex, p.tok.indent)
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
of tkSad:
|
||||
if realInd(p):
|
||||
withInd(p):
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
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)
|
||||
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 =
|
||||
#| paramList = '(' (identColonEquals (comma/semicolon identColonEquals)*)? ')'
|
||||
#| paramListArrow = paramList? ('->' optInd typeDesc)?
|
||||
#| paramListColon = paramList? (':' optInd typeDesc)?
|
||||
var a: PNode
|
||||
result = newNodeP(nkFormalParams, p)
|
||||
addSon(result, ast.emptyNode) # return type
|
||||
|
|
@ -681,7 +748,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
|
|||
getTok(p)
|
||||
optInd(p, result)
|
||||
while true:
|
||||
case p.tok.tokType #optInd(p, a);
|
||||
case p.tok.tokType
|
||||
of tkSymbol, tkAccent:
|
||||
a = parseIdentColonEquals(p, {withBothOptional})
|
||||
of tkParRi:
|
||||
|
|
@ -707,6 +774,7 @@ proc optPragmas(p: var TParser): PNode =
|
|||
else: result = ast.emptyNode
|
||||
|
||||
proc parseDoBlock(p: var TParser): PNode =
|
||||
#| doBlock = 'do' paramListArrow pragmas? colcom stmt
|
||||
let info = parLineInfo(p)
|
||||
getTok(p)
|
||||
let params = parseParamList(p, retColon=false)
|
||||
|
|
@ -718,10 +786,12 @@ proc parseDoBlock(p: var TParser): PNode =
|
|||
pragmas = pragmas)
|
||||
|
||||
proc parseDoBlocks(p: var TParser, call: PNode) =
|
||||
#| doBlocks = doBlock*
|
||||
while p.tok.tokType == tkDo:
|
||||
addSon(call, parseDoBlock(p))
|
||||
|
||||
proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
|
||||
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
||||
# either a proc type or a anonymous proc
|
||||
var
|
||||
pragmas, params: PNode
|
||||
|
|
@ -752,7 +822,8 @@ proc isExprStart(p: TParser): bool =
|
|||
result = true
|
||||
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)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
|
|
@ -760,11 +831,10 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, mode: TPrimaryMode): PNo
|
|||
addSon(result, primary(p, mode))
|
||||
|
||||
proc parseExpr(p: var TParser): PNode =
|
||||
#
|
||||
#expr ::= lowestExpr
|
||||
# | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
|
||||
# | 'when' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
|
||||
#
|
||||
#| expr = lowestExpr
|
||||
#| | ifExpr
|
||||
#| | whenExpr
|
||||
#| | caseExpr
|
||||
case p.tok.tokType:
|
||||
of tkIf: result = parseIfExpr(p, nkIfExpr)
|
||||
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
|
||||
|
|
@ -778,7 +848,13 @@ proc parseDistinct(p: var TParser): PNode
|
|||
proc parseEnum(p: var TParser): 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):
|
||||
let isSigil = IsSigilLike(p.tok)
|
||||
result = newNodeP(nkPrefix, p)
|
||||
|
|
@ -854,6 +930,14 @@ proc parseTypeDefAux(p: var TParser): PNode =
|
|||
result = lowestExpr(p, pmTypeDef)
|
||||
|
||||
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)
|
||||
if p.tok.tokType == tkEquals:
|
||||
getTok(p)
|
||||
|
|
@ -865,6 +949,7 @@ proc parseExprStmt(p: var TParser): PNode =
|
|||
else:
|
||||
var call = if a.kind == nkCall: 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:
|
||||
if not isExprStart(p): break
|
||||
var e = parseExpr(p)
|
||||
|
|
@ -881,12 +966,12 @@ proc parseExprStmt(p: var TParser): PNode =
|
|||
result = call
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
if p.tok.tokType == tkSad: getTok(p)
|
||||
if sameInd(p): getTok(p)
|
||||
if p.tok.TokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||
let body = parseStmt(p)
|
||||
addSon(result, newProcNode(nkDo, body.info, body))
|
||||
while true:
|
||||
if p.tok.tokType == tkSad: getTok(p)
|
||||
if sameInd(p): getTok(p)
|
||||
var b: PNode
|
||||
case p.tok.tokType
|
||||
of tkOf:
|
||||
|
|
@ -900,7 +985,7 @@ proc parseExprStmt(p: var TParser): PNode =
|
|||
eat(p, tkColon)
|
||||
of tkExcept:
|
||||
b = newNodeP(nkExceptBranch, p)
|
||||
qualifiedIdentListAux(p, tkColon, b)
|
||||
exprList(p, tkColon, b)
|
||||
skipComment(p, b)
|
||||
of tkElse:
|
||||
b = newNodeP(nkElse, p)
|
||||
|
|
@ -912,6 +997,9 @@ proc parseExprStmt(p: var TParser): PNode =
|
|||
if b.kind == nkElse: break
|
||||
|
||||
proc parseImport(p: var TParser, kind: TNodeKind): PNode =
|
||||
#| importStmt = 'import' optInd expr
|
||||
#| ((comma expr)*
|
||||
#| / 'except' optInd expr (comma expr)*)
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p) # skip `import` or `export`
|
||||
optInd(p, result)
|
||||
|
|
@ -922,7 +1010,8 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
|
|||
result.kind = succ(kind)
|
||||
getTok(p)
|
||||
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)
|
||||
if a.kind == nkEmpty: break
|
||||
addSon(result, a)
|
||||
|
|
@ -932,10 +1021,12 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
|
|||
expectNl(p)
|
||||
|
||||
proc parseIncludeStmt(p: var TParser): PNode =
|
||||
#| includeStmt = 'include' optInd expr (comma expr)*
|
||||
result = newNodeP(nkIncludeStmt, p)
|
||||
getTok(p) # skip `import` or `include`
|
||||
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)
|
||||
if a.kind == nkEmpty: break
|
||||
addSon(result, a)
|
||||
|
|
@ -945,6 +1036,7 @@ proc parseIncludeStmt(p: var TParser): PNode =
|
|||
expectNl(p)
|
||||
|
||||
proc parseFromStmt(p: var TParser): PNode =
|
||||
#| fromStmt = 'from' expr 'import' optInd expr (comma expr)*
|
||||
result = newNodeP(nkFromStmt, p)
|
||||
getTok(p) # skip `from`
|
||||
optInd(p, result)
|
||||
|
|
@ -952,7 +1044,8 @@ proc parseFromStmt(p: var TParser): PNode =
|
|||
addSon(result, a) #optInd(p, a);
|
||||
eat(p, tkImport)
|
||||
optInd(p, result)
|
||||
while p.tok.tokType notin {tkEof, tkSad, tkDed}:
|
||||
while true:
|
||||
# p.tok.tokType notin {tkEof, tkSad, tkDed}:
|
||||
a = parseExpr(p)
|
||||
if a.kind == nkEmpty: break
|
||||
addSon(result, a)
|
||||
|
|
@ -962,28 +1055,25 @@ proc parseFromStmt(p: var TParser): PNode =
|
|||
expectNl(p)
|
||||
|
||||
proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
|
||||
#| returnStmt = 'return' optInd expr?
|
||||
#| raiseStmt = 'raise' optInd expr?
|
||||
#| yieldStmt = 'yield' optInd expr?
|
||||
#| discardStmt = 'discard' optInd expr?
|
||||
#| breakStmt = 'break' optInd expr?
|
||||
#| continueStmt = 'break' optInd expr?
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
case p.tok.tokType
|
||||
of tkEof, tkSad, tkDed: addSon(result, ast.emptyNode)
|
||||
of tkEof, tkInd: addSon(result, ast.emptyNode)
|
||||
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 =
|
||||
#| condStmt = expr colcom stmt COMMENT?
|
||||
#| ('elif' expr colcom stmt)*
|
||||
#| ('else' colcom stmt)?
|
||||
#| ifStmt = 'if' condStmt
|
||||
#| whenStmt = 'when' condStmt
|
||||
result = newNodeP(kind, p)
|
||||
while true:
|
||||
getTok(p) # skip `if`, `when`, `elif`
|
||||
|
|
@ -1005,6 +1095,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
|
|||
addSon(result, branch)
|
||||
|
||||
proc parseWhile(p: var TParser): PNode =
|
||||
#| whileStmt = 'while' expr colcom stmt
|
||||
result = newNodeP(nkWhileStmt, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
|
|
@ -1014,6 +1105,13 @@ proc parseWhile(p: var TParser): PNode =
|
|||
addSon(result, parseStmt(p))
|
||||
|
||||
proc parseCase(p: var TParser): PNode =
|
||||
#| ofBranch = 'of' exprList colcom stmt
|
||||
#| ofBranches = ofBranch (IND{=} ofBranch)*
|
||||
#| (IND{=} 'elif' expr colcom stmt)*
|
||||
#| (IND{=} 'else' colcom stmt)?
|
||||
#| caseStmt = 'case' expr ':'? COMMENT?
|
||||
#| (IND{>} ofBranches
|
||||
#| | IND{=} ofBranches)
|
||||
var
|
||||
b: PNode
|
||||
inElif= false
|
||||
|
|
@ -1024,13 +1122,14 @@ proc parseCase(p: var TParser): PNode =
|
|||
if p.tok.tokType == tkColon: getTok(p)
|
||||
skipComment(p, result)
|
||||
|
||||
if p.tok.tokType == tkInd:
|
||||
pushInd(p.lex, p.tok.indent)
|
||||
let oldInd = p.currInd
|
||||
if realInd(p):
|
||||
p.currInd = p.tok.indent
|
||||
getTok(p)
|
||||
wasIndented = true
|
||||
|
||||
while true:
|
||||
if p.tok.tokType == tkSad: getTok(p)
|
||||
if sameInd(p): getTok(p)
|
||||
case p.tok.tokType
|
||||
of tkOf:
|
||||
if inElif: break
|
||||
|
|
@ -1054,10 +1153,12 @@ proc parseCase(p: var TParser): PNode =
|
|||
if b.kind == nkElse: break
|
||||
|
||||
if wasIndented:
|
||||
if p.tok.tokType != tkEof: eat(p, tkDed)
|
||||
popInd(p.lex)
|
||||
p.currInd = oldInd
|
||||
|
||||
proc parseTry(p: var TParser): PNode =
|
||||
#| tryStmt = 'try' colcom stmt &('except'|'finally')
|
||||
#| ('except' exprList colcom stmt)*
|
||||
#| ('finally' colcom stmt)?
|
||||
result = newNodeP(nkTryStmt, p)
|
||||
getTok(p)
|
||||
eat(p, tkColon)
|
||||
|
|
@ -1069,7 +1170,7 @@ proc parseTry(p: var TParser): PNode =
|
|||
case p.tok.tokType
|
||||
of tkExcept:
|
||||
b = newNodeP(nkExceptBranch, p)
|
||||
qualifiedIdentListAux(p, tkColon, b)
|
||||
exprList(p, tkColon, b)
|
||||
of tkFinally:
|
||||
b = newNodeP(nkFinally, p)
|
||||
getTok(p)
|
||||
|
|
@ -1082,6 +1183,7 @@ proc parseTry(p: var TParser): PNode =
|
|||
if b == nil: parMessage(p, errTokenExpected, "except")
|
||||
|
||||
proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
|
||||
#| exceptBlock = 'except' colcom stmt
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
eat(p, tkColon)
|
||||
|
|
@ -1089,9 +1191,9 @@ proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
|
|||
addSon(result, parseStmt(p))
|
||||
|
||||
proc parseFor(p: var TParser): PNode =
|
||||
#| forStmt = 'for' symbol (comma symbol)* 'in' expr colcom stmt
|
||||
result = newNodeP(nkForStmt, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
var a = parseSymbol(p)
|
||||
addSon(result, a)
|
||||
while p.tok.tokType == tkComma:
|
||||
|
|
@ -1106,28 +1208,27 @@ proc parseFor(p: var TParser): PNode =
|
|||
addSon(result, parseStmt(p))
|
||||
|
||||
proc parseBlock(p: var TParser): PNode =
|
||||
#| blockStmt = 'block' symbol? colcom stmt
|
||||
result = newNodeP(nkBlockStmt, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
case p.tok.tokType
|
||||
of tkEof, tkSad, tkDed, tkColon: addSon(result, ast.emptyNode)
|
||||
if p.tok.tokType = tkColon: addSon(result, ast.emptyNode)
|
||||
else: addSon(result, parseSymbol(p))
|
||||
eat(p, tkColon)
|
||||
skipComment(p, result)
|
||||
addSon(result, parseStmt(p))
|
||||
|
||||
proc parseStatic(p: var TParser): PNode =
|
||||
#| staticStmt = 'static' colcom stmt
|
||||
result = newNodeP(nkStaticStmt, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
eat(p, tkColon)
|
||||
skipComment(p, result)
|
||||
addSon(result, parseStmt(p))
|
||||
|
||||
proc parseAsm(p: var TParser): PNode =
|
||||
#| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT)
|
||||
result = newNodeP(nkAsmStmt, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p))
|
||||
else: addSon(result, ast.emptyNode)
|
||||
case p.tok.tokType
|
||||
|
|
@ -1142,6 +1243,7 @@ proc parseAsm(p: var TParser): PNode =
|
|||
getTok(p)
|
||||
|
||||
proc parseGenericParam(p: var TParser): PNode =
|
||||
#| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
|
||||
var a: PNode
|
||||
result = newNodeP(nkIdentDefs, p)
|
||||
while true:
|
||||
|
|
@ -1168,6 +1270,8 @@ proc parseGenericParam(p: var TParser): PNode =
|
|||
addSon(result, ast.emptyNode)
|
||||
|
||||
proc parseGenericParamList(p: var TParser): PNode =
|
||||
#| genericParamList = '[' optInd
|
||||
#| (genericParam (comma/semicolon genericParam)*)? optPar ']'
|
||||
result = newNodeP(nkGenericParams, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
|
|
@ -1181,11 +1285,15 @@ proc parseGenericParamList(p: var TParser): PNode =
|
|||
eat(p, tkBracketRi)
|
||||
|
||||
proc parsePattern(p: var TParser): PNode =
|
||||
#| pattern = '{' stmt '}'
|
||||
eat(p, tkCurlyLe)
|
||||
result = parseStmt(p)
|
||||
eat(p, tkCurlyRi)
|
||||
|
||||
proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
|
||||
#| indAndComment = (IND{>} COMMENT)? | COMMENT?
|
||||
#| routine = optInd identVis pattern? genericParamList?
|
||||
#| paramListColon pragma? ('=' COMMENT? stmt)? indAndComment
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
|
|
@ -1205,9 +1313,10 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
|
|||
addSon(result, parseStmt(p))
|
||||
else:
|
||||
addSon(result, ast.emptyNode)
|
||||
indAndComment(p, result) # XXX: document this in the grammar!
|
||||
indAndComment(p, result)
|
||||
|
||||
proc newCommentStmt(p: var TParser): PNode =
|
||||
#| commentStmt = COMMENT
|
||||
result = newNodeP(nkCommentStmt, p)
|
||||
result.info.line = result.info.line - int16(1) - int16(p.tok.iNumber)
|
||||
|
||||
|
|
@ -1216,41 +1325,40 @@ type
|
|||
|
||||
proc parseSection(p: var TParser, kind: TNodeKind,
|
||||
defparser: TDefParser): PNode =
|
||||
#| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
case p.tok.tokType
|
||||
of tkInd:
|
||||
pushInd(p.lex, p.tok.indent)
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
of tkSad:
|
||||
getTok(p)
|
||||
of tkSymbol, tkAccent:
|
||||
var a = defparser(p)
|
||||
skipComment(p, a)
|
||||
addSon(result, a)
|
||||
of tkDed:
|
||||
getTok(p)
|
||||
break
|
||||
of tkEof:
|
||||
break # BUGFIX
|
||||
of tkComment:
|
||||
var a = newCommentStmt(p)
|
||||
skipComment(p, a)
|
||||
addSon(result, a)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
break
|
||||
popInd(p.lex)
|
||||
if not realInd(p): parMessage(p, errInvalidIndentation)
|
||||
withInd(p):
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
of tkSad:
|
||||
getTok(p)
|
||||
of tkSymbol, tkAccent:
|
||||
var a = defparser(p)
|
||||
skipComment(p, a)
|
||||
addSon(result, a)
|
||||
of tkEof:
|
||||
break
|
||||
of tkComment:
|
||||
var a = newCommentStmt(p)
|
||||
skipComment(p, a)
|
||||
addSon(result, a)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
break
|
||||
of tkSymbol, tkAccent, tkParLe:
|
||||
# tkParLe is allowed for ``var (x, y) = ...`` tuple parsing
|
||||
addSon(result, defparser(p))
|
||||
else: parMessage(p, errIdentifierExpected, p.tok)
|
||||
|
||||
proc parseConstant(p: var TParser): PNode =
|
||||
#| constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment
|
||||
result = newNodeP(nkConstDef, p)
|
||||
addSon(result, identWithPragma(p))
|
||||
if p.tok.tokType == tkColon:
|
||||
|
|
@ -1262,24 +1370,21 @@ proc parseConstant(p: var TParser): PNode =
|
|||
eat(p, tkEquals)
|
||||
optInd(p, result)
|
||||
addSon(result, parseExpr(p))
|
||||
indAndComment(p, result) # XXX: special extension!
|
||||
indAndComment(p, result)
|
||||
|
||||
proc parseEnum(p: var TParser): PNode =
|
||||
var a, b: PNode
|
||||
#| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
|
||||
result = newNodeP(nkEnumTy, p)
|
||||
a = nil
|
||||
getTok(p)
|
||||
addSon(result, ast.emptyNode)
|
||||
optInd(p, result)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
of tkEof, tkSad, tkDed: break
|
||||
else: a = parseSymbol(p)
|
||||
while p.tok.tokType notin {tkEof, tkInd}:
|
||||
var a = parseSymbol(p)
|
||||
optInd(p, a)
|
||||
if p.tok.tokType == tkEquals:
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
b = a
|
||||
var b = a
|
||||
a = newNodeP(nkEnumFieldDef, p)
|
||||
addSon(a, b)
|
||||
addSon(a, parseExpr(p))
|
||||
|
|
@ -1293,6 +1398,9 @@ proc parseEnum(p: var TParser): PNode =
|
|||
|
||||
proc parseObjectPart(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)
|
||||
while true:
|
||||
getTok(p) # skip `when`, `elif`
|
||||
|
|
@ -1311,9 +1419,17 @@ proc parseObjectWhen(p: var TParser): PNode =
|
|||
eat(p, tkColon)
|
||||
skipComment(p, branch)
|
||||
addSon(branch, parseObjectPart(p))
|
||||
# XXX no skipComment(p, branch) here?
|
||||
addSon(result, branch)
|
||||
|
||||
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)
|
||||
getTok(p)
|
||||
var a = newNodeP(nkIdentDefs, p)
|
||||
|
|
@ -1403,6 +1519,7 @@ proc parseObject(p: var TParser): PNode =
|
|||
addSon(result, parseObjectPart(p))
|
||||
|
||||
proc parseDistinct(p: var TParser): PNode =
|
||||
#| distinct = 'distinct' optInd typeDesc
|
||||
result = newNodeP(nkDistinctTy, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
|
|
@ -1444,6 +1561,7 @@ proc parseVariable(p: var TParser): PNode =
|
|||
indAndComment(p, result) # special extension!
|
||||
|
||||
proc parseBind(p: var TParser, k: TNodeKind): PNode =
|
||||
#| bindStmt = 'bind' optInd qualifiedIdent (comma qualifiedIdent)*
|
||||
result = newNodeP(k, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
|
|
@ -1456,11 +1574,13 @@ proc parseBind(p: var TParser, k: TNodeKind): PNode =
|
|||
expectNl(p)
|
||||
|
||||
proc parseStmtPragma(p: var TParser): PNode =
|
||||
#| pragmaStmt = pragma (':' COMMENT? stmt)?
|
||||
result = parsePragma(p)
|
||||
if p.tok.tokType == tkColon:
|
||||
let a = result
|
||||
result = newNodeI(nkPragmaBlock, a.info)
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
result.add a
|
||||
result.add parseStmt(p)
|
||||
|
||||
|
|
@ -1470,8 +1590,8 @@ proc simpleStmt(p: var TParser): PNode =
|
|||
of tkRaise: result = parseReturnOrRaise(p, nkRaiseStmt)
|
||||
of tkYield: result = parseReturnOrRaise(p, nkYieldStmt)
|
||||
of tkDiscard: result = parseReturnOrRaise(p, nkDiscardStmt)
|
||||
of tkBreak: result = parseBreakOrContinue(p, nkBreakStmt)
|
||||
of tkContinue: result = parseBreakOrContinue(p, nkContinueStmt)
|
||||
of tkBreak: result = parseReturnOrRaise(p, nkBreakStmt)
|
||||
of tkContinue: result = parseReturnOrRaise(p, nkContinueStmt)
|
||||
of tkCurlyDotLe: result = parseStmtPragma(p)
|
||||
of tkImport: result = parseImport(p, nkImportStmt)
|
||||
of tkExport: result = parseImport(p, nkExportStmt)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue