summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorhlaaftana <10591326+hlaaftana@users.noreply.github.com>2022-01-02 09:29:55 +0300
committerGitHub <noreply@github.com>2022-01-02 07:29:55 +0100
commit61d682e733005534a16af72fc9b0c0e74d2f9ebf (patch)
treed340ed341a7c85e393120c59effea6a485c61b0c
parentef634cc2516ce81a05486f726e423ac458c4467a (diff)
downloadNim-61d682e733005534a16af72fc9b0c0e74d2f9ebf.tar.gz
Allow full commands and blocks in type sections (#19181)
* allow full commands and blocks in type sections
* update grammar
* fix changelog [skip ci]
* more tests
* even more tests
-rw-r--r--changelog.md3
-rw-r--r--compiler/parser.nim28
-rw-r--r--doc/grammar.txt5
-rw-r--r--tests/parser/ttypecommandcomma.nim9
-rw-r--r--tests/parser/ttypecommandindent1.nim9
-rw-r--r--tests/parser/ttypecommandindent2.nim11
-rw-r--r--tests/parser/ttypecommandindent3.nim11
-rw-r--r--tests/parser/ttypesectioncalls.nim328
8 files changed, 393 insertions, 11 deletions
diff --git a/changelog.md b/changelog.md
index 52159b865..89aaff664 100644
--- a/changelog.md
+++ b/changelog.md
@@ -61,6 +61,9 @@
   ```
 - [Case statement macros](manual.html#macros-case-statement-macros) are no longer experimental,
   meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
+- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed
+  for the right-hand side of type definitions in type sections. Previously
+  they would error with "invalid indentation".
 
 ## Compiler changes
 
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 7bc2c78e0..0fb60440c 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -811,7 +811,7 @@ proc primarySuffix(p: var Parser, r: PNode,
   #|       | DOTLIKEOP optInd symbol generalizedLit?
   #|       | '[' optInd exprColonEqExprList optPar ']'
   #|       | '{' optInd exprColonEqExprList optPar '}'
-  #|       | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
+  #|       | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr (comma expr)* # command syntax
   result = r
 
   # progress guaranteed
@@ -821,14 +821,14 @@ proc primarySuffix(p: var Parser, r: PNode,
     of tkParLe:
       # progress guaranteed
       if p.tok.strongSpaceA > 0:
-        # inside type sections, expressions such as `ref (int, bar)`
-        # are parsed as a nkCommand with a single tuple argument (nkPar)
+        result = commandExpr(p, result, mode)
+        # type sections allow full command syntax
         if mode == pmTypeDef:
-          result = newNodeP(nkCommand, p)
-          result.add r
-          result.add primary(p, pmNormal)
-        else:
-          result = commandExpr(p, result, mode)
+          var isFirstParam = false
+          while p.tok.tokType == tkComma:
+            getTok(p)
+            optInd(p, result)
+            result.add(commandParam(p, isFirstParam, mode))
         break
       result = namedParams(p, result, nkCall, tkParRi)
       if result.len > 1 and result[1].kind == nkExprColonExpr:
@@ -869,9 +869,18 @@ proc primarySuffix(p: var Parser, r: PNode,
           # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
           # solution, but pragmas.nim can't handle that
           result = commandExpr(p, result, mode)
+          if mode == pmTypeDef:
+            var isFirstParam = false
+            while p.tok.tokType == tkComma:
+              getTok(p)
+              optInd(p, result)
+              result.add(commandParam(p, isFirstParam, mode))
         break
     else:
       break
+  # type sections allow post-expr blocks
+  if mode == pmTypeDef:
+    result = postExprBlocks(p, result)
 
 proc parseOperators(p: var Parser, headNode: PNode,
                     limit: int, mode: PrimaryMode): PNode =
@@ -1342,7 +1351,8 @@ proc parseTypeDesc(p: var Parser): PNode =
   result = binaryNot(p, result)
 
 proc parseTypeDefAux(p: var Parser): PNode =
-  #| typeDefAux = simpleExpr ('not' expr)?
+  #| typeDefAux = simpleExpr ('not' expr
+  #|                         | postExprBlocks)?
   result = simpleExpr(p, pmTypeDef)
   result = binaryNot(p, result)
 
diff --git a/doc/grammar.txt b/doc/grammar.txt
index bf6d381de..1e41b9eeb 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -60,7 +60,7 @@ primarySuffix = '(' (exprColonEqExpr comma?)* ')'
       | DOTLIKEOP optInd symbol generalizedLit?
       | '[' optInd exprColonEqExprList optPar ']'
       | '{' optInd exprColonEqExprList optPar '}'
-      | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
+      | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr (comma expr)* # command syntax
 pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}')
 identVis = symbol OPR?  # postfix position
 identVisDot = symbol '.' optInd symbol OPR?
@@ -93,7 +93,8 @@ primary = operatorB primary primarySuffix* |
           ('var' | 'out' | 'ref' | 'ptr' | 'distinct') primary
         /  prefixOperator* identOrLiteral primarySuffix*
 typeDesc = simpleExpr ('not' expr)?
-typeDefAux = simpleExpr ('not' expr)?
+typeDefAux = simpleExpr ('not' expr
+                        | postExprBlocks)?
 postExprBlocks = ':' stmt? ( IND{=} doBlock
                            | IND{=} 'of' exprList ':' stmt
                            | IND{=} 'elif' expr ':' stmt
diff --git a/tests/parser/ttypecommandcomma.nim b/tests/parser/ttypecommandcomma.nim
new file mode 100644
index 000000000..7ca59a799
--- /dev/null
+++ b/tests/parser/ttypecommandcomma.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "invalid indentation"
+  line: 8
+  column: 19
+"""
+
+type
+  Foo = call(1, 2), 3:
+    4
\ No newline at end of file
diff --git a/tests/parser/ttypecommandindent1.nim b/tests/parser/ttypecommandindent1.nim
new file mode 100644
index 000000000..9aa274e2a
--- /dev/null
+++ b/tests/parser/ttypecommandindent1.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "invalid indentation"
+  line: 9
+  column: 3
+"""
+
+type
+  Foo = call x, y, z:
+  abc
diff --git a/tests/parser/ttypecommandindent2.nim b/tests/parser/ttypecommandindent2.nim
new file mode 100644
index 000000000..0883df90f
--- /dev/null
+++ b/tests/parser/ttypecommandindent2.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "invalid indentation"
+  line: 10
+  column: 5
+"""
+
+type
+  Foo = call x, y, z:
+      abc
+    do:
+        def
diff --git a/tests/parser/ttypecommandindent3.nim b/tests/parser/ttypecommandindent3.nim
new file mode 100644
index 000000000..f9fdcc1e4
--- /dev/null
+++ b/tests/parser/ttypecommandindent3.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "expression expected, but found 'keyword do'"
+  line: 10
+  column: 1
+"""
+
+type
+  Foo = call x, y, z:
+    abc
+do:
+    def
diff --git a/tests/parser/ttypesectioncalls.nim b/tests/parser/ttypesectioncalls.nim
new file mode 100644
index 000000000..003444fc5
--- /dev/null
+++ b/tests/parser/ttypesectioncalls.nim
@@ -0,0 +1,328 @@
+discard """
+nimout: '''
+StmtList
+  TypeSection
+    TypeDef
+      Ident "A"
+      Empty
+      Call
+        Ident "call"
+        IntLit 1
+  TypeSection
+    TypeDef
+      Ident "B"
+      Empty
+      Command
+        Ident "call"
+        IntLit 2
+    TypeDef
+      Ident "C"
+      Empty
+      Call
+        Ident "call"
+        StmtList
+          IntLit 3
+    TypeDef
+      Ident "D"
+      Empty
+      Call
+        Ident "call"
+        StmtList
+          IntLit 4
+  TypeSection
+    TypeDef
+      Ident "E"
+      Empty
+      Call
+        Ident "call"
+        IntLit 5
+        IntLit 6
+    TypeDef
+      Ident "F"
+      Empty
+      Command
+        Ident "call"
+        IntLit 7
+        IntLit 8
+    TypeDef
+      Ident "G"
+      Empty
+      Call
+        Ident "call"
+        IntLit 9
+        StmtList
+          IntLit 10
+    TypeDef
+      Ident "H"
+      Empty
+      Call
+        Ident "call"
+        IntLit 11
+        StmtList
+          IntLit 12
+    TypeDef
+      Ident "I"
+      Empty
+      Command
+        Ident "call"
+        IntLit 13
+        StmtList
+          IntLit 14
+    TypeDef
+      Ident "J"
+      Empty
+      Command
+        Ident "call"
+        IntLit 15
+        StmtList
+          IntLit 16
+  TypeSection
+    TypeDef
+      Ident "K"
+      Empty
+      Call
+        Ident "call"
+        IntLit 17
+        IntLit 18
+        IntLit 19
+    TypeDef
+      Ident "L"
+      Empty
+      Command
+        Ident "call"
+        IntLit 20
+        IntLit 21
+        IntLit 22
+    TypeDef
+      Ident "M"
+      Empty
+      Call
+        Ident "call"
+        IntLit 23
+        IntLit 24
+        StmtList
+          IntLit 25
+    TypeDef
+      Ident "N"
+      Empty
+      Command
+        Ident "call"
+        IntLit 26
+        IntLit 27
+        StmtList
+          IntLit 28
+    TypeDef
+      Ident "O"
+      Empty
+      Command
+        Ident "call"
+        IntLit 29
+        IntLit 30
+        StmtList
+          IntLit 31
+  TypeSection
+    TypeDef
+      Ident "P"
+      Empty
+      Command
+        Ident "call"
+        TupleConstr
+          IntLit 32
+          IntLit 33
+        Infix
+          Ident "+"
+          Infix
+            Ident "*"
+            IntLit 34
+            IntLit 35
+          IntLit 36
+        StmtList
+          IntLit 37
+    TypeDef
+      Ident "R"
+      Empty
+      Command
+        Ident "call"
+        Infix
+          Ident "@"
+          TupleConstr
+            IntLit 38
+            IntLit 39
+          Infix
+            Ident "shl"
+            IntLit 40
+            IntLit 41
+        Infix
+          Ident "-"
+          Infix
+            Ident "*"
+            IntLit 42
+            IntLit 43
+          IntLit 44
+        StmtList
+          IntLit 45
+    TypeDef
+      Ident "S"
+      Empty
+      Command
+        Ident "call"
+        IntLit 46
+        StmtList
+          IntLit 47
+        StmtList
+          IntLit 48
+    TypeDef
+      Ident "T"
+      Empty
+      Call
+        Ident "call"
+        StmtList
+          IntLit 49
+        StmtList
+          IntLit 50
+        StmtList
+          IntLit 51
+a: IntLit 1
+a: IntLit 2
+a: StmtList
+  IntLit 3
+a: StmtList
+  IntLit 4
+a: IntLit 5
+b: IntLit 6
+a: IntLit 7
+b: IntLit 8
+a: IntLit 9
+b: StmtList
+  IntLit 10
+a: IntLit 11
+b: StmtList
+  IntLit 12
+a: IntLit 13
+b: StmtList
+  IntLit 14
+a: IntLit 15
+b: StmtList
+  IntLit 16
+a: IntLit 17
+b: IntLit 18
+c: IntLit 19
+a: IntLit 20
+b: IntLit 21
+c: IntLit 22
+a: IntLit 23
+b: IntLit 24
+c: StmtList
+  IntLit 25
+a: IntLit 26
+b: IntLit 27
+c: StmtList
+  IntLit 28
+a: IntLit 29
+b: IntLit 30
+c: StmtList
+  IntLit 31
+a: TupleConstr
+  IntLit 32
+  IntLit 33
+b: Infix
+  Ident "+"
+  Infix
+    Ident "*"
+    IntLit 34
+    IntLit 35
+  IntLit 36
+c: StmtList
+  IntLit 37
+a: Infix
+  Ident "@"
+  TupleConstr
+    IntLit 38
+    IntLit 39
+  Infix
+    Ident "shl"
+    IntLit 40
+    IntLit 41
+b: Infix
+  Ident "-"
+  Infix
+    Ident "*"
+    IntLit 42
+    IntLit 43
+  IntLit 44
+c: StmtList
+  IntLit 45
+a: IntLit 46
+b: StmtList
+  IntLit 47
+c: StmtList
+  IntLit 48
+a: StmtList
+  IntLit 49
+b: StmtList
+  IntLit 50
+c: StmtList
+  IntLit 51
+'''
+"""
+import macros
+
+macro call(a): untyped =
+  echo "a: ", a.treeRepr
+  result = ident"int"
+macro call(a, b): untyped =
+  echo "a: ", a.treeRepr
+  echo "b: ", b.treeRepr
+  result = ident"int"
+macro call(a, b, c): untyped =
+  echo "a: ", a.treeRepr
+  echo "b: ", b.treeRepr
+  echo "c: ", c.treeRepr
+  result = ident"int"
+
+macro sections(x): untyped =
+  echo x.treeRepr
+  result = newStmtList(x)
+  for ts in x:
+    for td in ts:
+      let t = td[0]
+      result.add quote do:
+        doAssert `t` is int
+
+sections:
+  type A = call(1)
+  type
+    B = call 2
+    C = call: 3
+    D = call(): 4
+  type
+    E = call(5, 6)
+    F = call 7, 8
+    G = call(9): 10
+    H = call(11):
+      12
+    I = call 13: 14
+    J = call 15:
+      16
+  type
+    K = call(17, 18, 19)
+    L = call 20, 21, 22
+    M = call(23, 24): 25
+    N = call 26, 27: 28
+    O = call 29, 30:
+      31
+  type
+    P = call (32, 33), 34 * 35 + 36:
+      37
+    R = call (38, 39) @ 40 shl 41, 42 * 43 - 44:
+      45
+    S = call 46:
+      47
+    do:
+      48
+    T = call:
+      49
+    do:
+      50
+    do:
+      51