parser enhancement: allow keywords after dots

This commit is contained in:
Andreas Rumpf 2017-07-11 00:54:47 +02:00
commit 76cf4f4c1b
2 changed files with 34 additions and 24 deletions

View file

@ -39,6 +39,9 @@ type
inPragma*: int # Pragma level inPragma*: int # Pragma level
inSemiStmtList*: int inSemiStmtList*: int
SymbolMode = enum
smNormal, smAllowNil, smAfterDot
proc parseAll*(p: var TParser): PNode proc parseAll*(p: var TParser): PNode
proc closeParser*(p: var TParser) proc closeParser*(p: var TParser)
proc parseTopLevelStmt*(p: var TParser): PNode proc parseTopLevelStmt*(p: var TParser): PNode
@ -62,7 +65,7 @@ proc optPar*(p: var TParser)
proc optInd*(p: var TParser, n: PNode) proc optInd*(p: var TParser, n: PNode)
proc indAndComment*(p: var TParser, n: PNode) proc indAndComment*(p: var TParser, n: PNode)
proc setBaseFlags*(n: PNode, base: TNumericalBase) proc setBaseFlags*(n: PNode, base: TNumericalBase)
proc parseSymbol*(p: var TParser, allowNil = false): PNode proc parseSymbol*(p: var TParser, mode = smNormal): PNode
proc parseTry(p: var TParser; isExpr: bool): PNode proc parseTry(p: var TParser; isExpr: bool): PNode
proc parseCase(p: var TParser): PNode proc parseCase(p: var TParser): PNode
proc parseStmtPragma(p: var TParser): PNode proc parseStmtPragma(p: var TParser): PNode
@ -304,13 +307,24 @@ proc colcom(p: var TParser, n: PNode) =
eat(p, tkColon) eat(p, tkColon)
skipComment(p, n) skipComment(p, n)
proc parseSymbol(p: var TParser, allowNil = false): PNode = proc parseSymbol(p: var TParser, mode = smNormal): PNode =
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
#| | IDENT | 'addr' | 'type' #| | IDENT | KEYW
case p.tok.tokType case p.tok.tokType
of tkSymbol, tkAddr, tkType: of tkSymbol:
result = newIdentNodeP(p.tok.ident, p) result = newIdentNodeP(p.tok.ident, p)
getTok(p) getTok(p)
of tokKeywordLow..tokKeywordHigh:
if p.tok.tokType == tkAddr or p.tok.tokType == tkType or mode == smAfterDot:
# for backwards compatibility these 2 are always valid:
result = newIdentNodeP(p.tok.ident, p)
getTok(p)
elif p.tok.tokType == tkNil and mode == smAllowNil:
result = newNodeP(nkNilLit, p)
getTok(p)
else:
parMessage(p, errIdentifierExpected, p.tok)
result = ast.emptyNode
of tkAccent: of tkAccent:
result = newNodeP(nkAccQuoted, p) result = newNodeP(nkAccQuoted, p)
getTok(p) getTok(p)
@ -336,16 +350,12 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
break break
eat(p, tkAccent) eat(p, tkAccent)
else: else:
if allowNil and p.tok.tokType == tkNil: parMessage(p, errIdentifierExpected, p.tok)
result = newNodeP(nkNilLit, p) # BUGFIX: We must consume a token here to prevent endless loops!
getTok(p) # But: this really sucks for idetools and keywords, so we don't do it
else: # if it is a keyword:
parMessage(p, errIdentifierExpected, p.tok) #if not isKeyword(p.tok.tokType): getTok(p)
# BUGFIX: We must consume a token here to prevent endless loops! result = ast.emptyNode
# But: this really sucks for idetools and keywords, so we don't do it
# if it is a keyword:
#if not isKeyword(p.tok.tokType): getTok(p)
result = ast.emptyNode
proc colonOrEquals(p: var TParser, a: PNode): PNode = proc colonOrEquals(p: var TParser, a: PNode): PNode =
if p.tok.tokType == tkColon: if p.tok.tokType == tkColon:
@ -390,7 +400,7 @@ proc dotExpr(p: var TParser, a: PNode): PNode =
result = newNodeI(nkDotExpr, info) result = newNodeI(nkDotExpr, info)
optInd(p, result) optInd(p, result)
addSon(result, a) addSon(result, a)
addSon(result, parseSymbol(p)) addSon(result, parseSymbol(p, smAfterDot))
proc qualifiedIdent(p: var TParser): PNode = proc qualifiedIdent(p: var TParser): PNode =
#| qualifiedIdent = symbol ('.' optInd symbol)? #| qualifiedIdent = symbol ('.' optInd symbol)?
@ -1005,10 +1015,10 @@ proc isExprStart(p: TParser): bool =
result = true result = true
else: result = false else: result = false
proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) = proc parseSymbolList(p: var TParser, result: PNode) =
# progress guaranteed # progress guaranteed
while true: while true:
var s = parseSymbol(p, allowNil) var s = parseSymbol(p, smAllowNil)
if s.kind == nkEmpty: break if s.kind == nkEmpty: break
addSon(result, s) addSon(result, s)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
@ -1029,7 +1039,7 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
getTok(p) getTok(p)
let list = newNodeP(nodeKind, p) let list = newNodeP(nodeKind, p)
result.addSon list result.addSon list
parseSymbolList(p, list, allowNil = true) parseSymbolList(p, list)
proc parseExpr(p: var TParser): PNode = proc parseExpr(p: var TParser): PNode =
#| expr = (ifExpr #| expr = (ifExpr

View file

@ -22,7 +22,7 @@ plusExpr = mulExpr (OP8 optInd mulExpr)*
mulExpr = dollarExpr (OP9 optInd dollarExpr)* mulExpr = dollarExpr (OP9 optInd dollarExpr)*
dollarExpr = primary (OP10 optInd primary)* dollarExpr = primary (OP10 optInd primary)*
symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
| IDENT | 'addr' | 'type' | IDENT | KEYW
exprColonEqExpr = expr (':'|'=' expr)? exprColonEqExpr = expr (':'|'=' expr)?
exprList = expr ^+ comma exprList = expr ^+ comma
dotExpr = expr '.' optInd symbol dotExpr = expr '.' optInd symbol
@ -81,7 +81,6 @@ paramList = '(' declColonEquals ^* (comma/semicolon) ')'
paramListArrow = paramList? ('->' optInd typeDesc)? paramListArrow = paramList? ('->' optInd typeDesc)?
paramListColon = paramList? (':' optInd typeDesc)? paramListColon = paramList? (':' optInd typeDesc)?
doBlock = 'do' paramListArrow pragmas? colcom stmt doBlock = 'do' paramListArrow pragmas? colcom stmt
doBlocks = doBlock ^* IND{=}
procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)? procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
distinct = 'distinct' optInd typeDesc distinct = 'distinct' optInd typeDesc
expr = (ifExpr expr = (ifExpr
@ -98,10 +97,11 @@ primary = typeKeyw typeDescK
typeDesc = simpleExpr typeDesc = simpleExpr
typeDefAux = simpleExpr typeDefAux = simpleExpr
| 'concept' typeClass | 'concept' typeClass
macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt postExprBlocks = ':' stmt? ( IND{=} doBlock
| IND{=} 'elif' expr ':' stmt | IND{=} 'of' exprList ':' stmt
| IND{=} 'except' exprList ':' stmt | IND{=} 'elif' expr ':' stmt
| IND{=} 'else' ':' stmt )* | IND{=} 'except' exprList ':' stmt
| IND{=} 'else' ':' stmt )*
exprStmt = simpleExpr exprStmt = simpleExpr
(( '=' optInd expr colonBody? ) (( '=' optInd expr colonBody? )
/ ( expr ^+ comma / ( expr ^+ comma