summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/parser.nim28
-rw-r--r--doc/grammar.txt7
-rw-r--r--tests/parser/t20922.nim46
3 files changed, 73 insertions, 8 deletions
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 0199c10af..6b3cebb7f 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -451,6 +451,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)
@@ -1436,7 +1454,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
@@ -1494,7 +1512,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)
@@ -1746,10 +1764,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)
@@ -1760,7 +1778,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 a0ff7d9f0..88094981c 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -30,6 +30,7 @@ symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
 exprColonEqExpr = expr (':'|'=' expr)?
 exprEqExpr = expr ('=' expr)?
 exprList = expr ^+ comma
+optionalExprList = expr ^* comma
 exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
 qualifiedIdent = symbol ('.' optInd symbol)?
 setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
@@ -109,7 +110,7 @@ typeDefValue = ((tupleDecl | enumDecl | objectDecl | conceptDecl |
 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 postExprBlocks?
@@ -148,10 +149,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 000000000..01af9868f
--- /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>'
+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