fix issue #20922 by handling missing expr in exprList for tkOf (#20930)

* fix issue #20922 by handling missing expr in `exprList` for `tkOf`

* fix line numbers in test case

* rewrite exprList requiring expr, add optionalExprList for except

As suggested by @metagn.

* update test case to reflect new code

* update grammar.txt

* update line numbers in test case taking into account nimout

Given the number of errors that are produced it seems easier to do it
this way instead of using `tt.Error`.
This commit is contained in:
Vindaar 2022-12-08 10:59:13 +01:00 • committed by GitHub
commit 0a1d4ba842
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 8 deletions

View file

@ -451,6 +451,24 @@ proc exprList(p: var Parser, endTok: TokType, result: PNode) =
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
# progress guaranteed # 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): while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
var a = parseExpr(p) var a = parseExpr(p)
result.add(a) result.add(a)
@ -1436,7 +1454,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
#| postExprBlocks = ':' stmt? ( IND{=} doBlock #| postExprBlocks = ':' stmt? ( IND{=} doBlock
#| | IND{=} 'of' exprList ':' stmt #| | IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt #| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt #| | IND{=} 'except' optionalExprList ':' stmt
#| | IND{=} 'finally' ':' stmt #| | IND{=} 'finally' ':' stmt
#| | IND{=} 'else' ':' stmt )* #| | IND{=} 'else' ':' stmt )*
result = x result = x
@ -1494,7 +1512,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
nextBlock.add parseExpr(p) nextBlock.add parseExpr(p)
of tkExcept: of tkExcept:
nextBlock = newNodeP(nkExceptBranch, p) nextBlock = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, nextBlock) optionalExprList(p, tkColon, nextBlock)
of tkFinally: of tkFinally:
nextBlock = newNodeP(nkFinally, p) nextBlock = newNodeP(nkFinally, p)
getTok(p) getTok(p)
@ -1746,10 +1764,10 @@ proc parseCase(p: var Parser): PNode =
proc parseTry(p: var Parser; isExpr: bool): PNode = proc parseTry(p: var Parser; isExpr: bool): PNode =
#| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally') #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
#| (IND{=}? 'except' exprList colcom stmt)* #| (IND{=}? 'except' optionalExprList colcom stmt)*
#| (IND{=}? 'finally' colcom stmt)? #| (IND{=}? 'finally' colcom stmt)?
#| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally') #| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
#| (optInd 'except' exprList colcom stmt)* #| (optInd 'except' optionalExprList colcom stmt)*
#| (optInd 'finally' colcom stmt)? #| (optInd 'finally' colcom stmt)?
result = newNodeP(nkTryStmt, p) result = newNodeP(nkTryStmt, p)
getTok(p) getTok(p)
@ -1760,7 +1778,7 @@ proc parseTry(p: var Parser; isExpr: bool): PNode =
case p.tok.tokType case p.tok.tokType
of tkExcept: of tkExcept:
b = newNodeP(nkExceptBranch, p) b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b) optionalExprList(p, tkColon, b)
of tkFinally: of tkFinally:
b = newNodeP(nkFinally, p) b = newNodeP(nkFinally, p)
getTok(p) getTok(p)

View file

@ -30,6 +30,7 @@ symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
exprColonEqExpr = expr (':'|'=' expr)? exprColonEqExpr = expr (':'|'=' expr)?
exprEqExpr = expr ('=' expr)? exprEqExpr = expr ('=' expr)?
exprList = expr ^+ comma exprList = expr ^+ comma
optionalExprList = expr ^* comma
exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
qualifiedIdent = symbol ('.' optInd symbol)? qualifiedIdent = symbol ('.' optInd symbol)?
setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
@ -109,7 +110,7 @@ typeDefValue = ((tupleDecl | enumDecl | objectDecl | conceptDecl |
postExprBlocks = ':' stmt? ( IND{=} doBlock postExprBlocks = ':' stmt? ( IND{=} doBlock
| IND{=} 'of' exprList ':' stmt | IND{=} 'of' exprList ':' stmt
| IND{=} 'elif' expr ':' stmt | IND{=} 'elif' expr ':' stmt
| IND{=} 'except' exprList ':' stmt | IND{=} 'except' optionalExprList ':' stmt
| IND{=} 'finally' ':' stmt | IND{=} 'finally' ':' stmt
| IND{=} 'else' ':' stmt )* | IND{=} 'else' ':' stmt )*
exprStmt = simpleExpr postExprBlocks? exprStmt = simpleExpr postExprBlocks?
@ -148,10 +149,10 @@ caseStmt = 'case' expr ':'? COMMENT?
(IND{>} ofBranches DED (IND{>} ofBranches DED
| IND{=} ofBranches) | IND{=} ofBranches)
tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally') tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
(IND{=}? 'except' exprList colcom stmt)* (IND{=}? 'except' optionalExprList colcom stmt)*
(IND{=}? 'finally' colcom stmt)? (IND{=}? 'finally' colcom stmt)?
tryExpr = 'try' colcom stmt &(optInd 'except'|'finally') tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
(optInd 'except' exprList colcom stmt)* (optInd 'except' optionalExprList colcom stmt)*
(optInd 'finally' colcom stmt)? (optInd 'finally' colcom stmt)?
blockStmt = 'block' symbol? colcom stmt blockStmt = 'block' symbol? colcom stmt
blockExpr = 'block' symbol? colcom stmt blockExpr = 'block' symbol? colcom stmt

46
tests/parser/t20922.nim Normal file
View file

@ -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>'
Error: in expression ' '+'': identifier expected, but found ''
t20922.nim(37, 7) Error: attempting to call undeclared routine: '<Error>'
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>'
Error: in expression ' x': identifier expected, but found ''
t20922.nim(45, 9) Error: attempting to call undeclared routine: '<Error>'
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