diff --git a/compiler/parser.nim b/compiler/parser.nim index 893644930c..82d2ad7d20 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -423,6 +423,24 @@ proc exprList(p: var Parser, endTok: TokType, result: PNode) = getTok(p) optInd(p, result) # progress guaranteed + var a = parseExpr(p) + result.add(a) + while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof): + if p.tok.tokType != tkComma: break + getTok(p) + optInd(p, a) + var a = parseExpr(p) + result.add(a) + when defined(nimpretty): + dec p.em.doIndentMore + +proc optionalExprList(p: var Parser, endTok: TokType, result: PNode) = + #| optionalExprList = expr ^* comma + when defined(nimpretty): + inc p.em.doIndentMore + getTok(p) + optInd(p, result) + # progress guaranteed while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof): var a = parseExpr(p) result.add(a) @@ -1383,7 +1401,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode = #| postExprBlocks = ':' stmt? ( IND{=} doBlock #| | IND{=} 'of' exprList ':' stmt #| | IND{=} 'elif' expr ':' stmt - #| | IND{=} 'except' exprList ':' stmt + #| | IND{=} 'except' optionalExprList ':' stmt #| | IND{=} 'finally' ':' stmt #| | IND{=} 'else' ':' stmt )* result = x @@ -1441,7 +1459,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode = nextBlock.add parseExpr(p) of tkExcept: nextBlock = newNodeP(nkExceptBranch, p) - exprList(p, tkColon, nextBlock) + optionalExprList(p, tkColon, nextBlock) of tkFinally: nextBlock = newNodeP(nkFinally, p) getTok(p) @@ -1708,10 +1726,10 @@ proc parseCase(p: var Parser): PNode = proc parseTry(p: var Parser; isExpr: bool): PNode = #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally') - #| (IND{=}? 'except' exprList colcom stmt)* + #| (IND{=}? 'except' optionalExprList colcom stmt)* #| (IND{=}? 'finally' colcom stmt)? #| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally') - #| (optInd 'except' exprList colcom stmt)* + #| (optInd 'except' optionalExprList colcom stmt)* #| (optInd 'finally' colcom stmt)? result = newNodeP(nkTryStmt, p) getTok(p) @@ -1722,7 +1740,7 @@ proc parseTry(p: var Parser; isExpr: bool): PNode = case p.tok.tokType of tkExcept: b = newNodeP(nkExceptBranch, p) - exprList(p, tkColon, b) + optionalExprList(p, tkColon, b) of tkFinally: b = newNodeP(nkFinally, p) getTok(p) diff --git a/doc/grammar.txt b/doc/grammar.txt index bf6d381dea..dad4576414 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -29,6 +29,7 @@ symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' | IDENT | KEYW exprColonEqExpr = expr (':'|'=' expr)? exprList = expr ^+ comma +optionalExprList = expr ^* comma exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? qualifiedIdent = symbol ('.' optInd symbol)? setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' @@ -97,7 +98,7 @@ typeDefAux = simpleExpr ('not' expr)? postExprBlocks = ':' stmt? ( IND{=} doBlock | IND{=} 'of' exprList ':' stmt | IND{=} 'elif' expr ':' stmt - | IND{=} 'except' exprList ':' stmt + | IND{=} 'except' optionalExprList ':' stmt | IND{=} 'finally' ':' stmt | IND{=} 'else' ':' stmt )* exprStmt = simpleExpr @@ -138,10 +139,10 @@ caseStmt = 'case' expr ':'? COMMENT? (IND{>} ofBranches DED | IND{=} ofBranches) tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally') - (IND{=}? 'except' exprList colcom stmt)* + (IND{=}? 'except' optionalExprList colcom stmt)* (IND{=}? 'finally' colcom stmt)? tryExpr = 'try' colcom stmt &(optInd 'except'|'finally') - (optInd 'except' exprList colcom stmt)* + (optInd 'except' optionalExprList colcom stmt)* (optInd 'finally' colcom stmt)? blockStmt = 'block' symbol? colcom stmt blockExpr = 'block' symbol? colcom stmt diff --git a/tests/parser/t20922.nim b/tests/parser/t20922.nim new file mode 100644 index 0000000000..01af9868fd --- /dev/null +++ b/tests/parser/t20922.nim @@ -0,0 +1,46 @@ +discard """ + cmd: "nim check $options --verbosity:0 $file" + action: "reject" + nimout: ''' +t20922.nim(37, 5) Error: expression expected, but found ':' +Error: in expression ' '+'': identifier expected, but found '' +t20922.nim(37, 7) Error: attempting to call undeclared routine: '' +Error: in expression ' '+'': identifier expected, but found '' +t20922.nim(37, 7) Error: attempting to call undeclared routine: '' +t20922.nim(37, 7) Error: expression '' cannot be called +t20922.nim(37, 7) Error: expression '' has no type (or is ambiguous) +t20922.nim(37, 7) Error: VM problem: dest register is not set +t20922.nim(45, 7) Error: expression expected, but found ':' +t20922.nim(46, 5) Error: ':' or '=' expected, but got 'keyword of' +t20922.nim(45, 9) Error: undeclared identifier: 'x' +t20922.nim(45, 9) Error: expression 'x' has no type (or is ambiguous) +Error: in expression ' x': identifier expected, but found '' +t20922.nim(45, 9) Error: attempting to call undeclared routine: '' +Error: in expression ' x': identifier expected, but found '' +t20922.nim(45, 9) Error: attempting to call undeclared routine: '' +t20922.nim(45, 9) Error: expression '' cannot be called +t20922.nim(45, 9) Error: expression '' has no type (or is ambiguous) +t20922.nim(45, 9) Error: VM problem: dest register is not set +t20922.nim(33, 6) Hint: 'mapInstrToToken' is declared but not used [XDeclaredButNotUsed] +t20922.nim(43, 3) Hint: 'Foo' is declared but not used [XDeclaredButNotUsed] +''' +""" +# original test case issue #20922 +type Token = enum + incDataPtr, + incDataPtrByte + +proc mapInstrToToken(instr: char): Token = + case instr: + of '>': + incDataPtr + of: '+': + incDataPtrByte + +# same issue with `of` in object branches (different parser procs calling `exprList`) +type + Bar = enum A, B + Foo = object + case kind: Bar + of: x: int + of B: y: float