From 25f1772debbae85e4c84caaf6aeb8f191dc8dc32 Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Tue, 23 Nov 2021 13:49:36 +0300 Subject: [PATCH 1/5] allow full commands and blocks in type sections --- changelog.md | 4 + compiler/parser.nim | 23 +++- tests/parser/ttypesectioncalls.nim | 210 +++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+), 7 deletions(-) create mode 100644 tests/parser/ttypesectioncalls.nim diff --git a/changelog.md b/changelog.md index ebad54fe45897..0a484b0d41dee 100644 --- a/changelog.md +++ b/changelog.md @@ -59,6 +59,10 @@ ``` - [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. + 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 9ff847ef68fa2..dba85361948b2 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -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 = diff --git a/tests/parser/ttypesectioncalls.nim b/tests/parser/ttypesectioncalls.nim new file mode 100644 index 0000000000000..dc7c797df9978 --- /dev/null +++ b/tests/parser/ttypesectioncalls.nim @@ -0,0 +1,210 @@ +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 +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 +''' +""" +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 From dfcea20bdb8cc2fe61aa176b449a21cbba0a494f Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Wed, 24 Nov 2021 15:10:28 +0300 Subject: [PATCH 2/5] update grammar --- compiler/parser.nim | 5 +++-- doc/grammar.txt | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index dba85361948b2..374b65876a898 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 @@ -1351,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 8f86dd98c28c0..528d277e7becd 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 From 6f7b9330c0bc3111ee67437b9bc85bcaac2820a6 Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Fri, 10 Dec 2021 16:20:12 +0300 Subject: [PATCH 3/5] fix changelog [skip ci] --- changelog.md | 1 - 1 file changed, 1 deletion(-) diff --git a/changelog.md b/changelog.md index 0a484b0d41dee..013951554624b 100644 --- a/changelog.md +++ b/changelog.md @@ -59,7 +59,6 @@ ``` - [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. - 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". From a83108fa1a3b2968d2e7e6535fb3ed4aa17681b8 Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Fri, 31 Dec 2021 21:34:03 +0300 Subject: [PATCH 4/5] more tests --- tests/parser/tinvtypecommand1.nim | 9 +++ tests/parser/tinvtypecommand2.nim | 11 ++++ tests/parser/tinvtypecommand3.nim | 9 +++ tests/parser/ttypesectioncalls.nim | 95 ++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 tests/parser/tinvtypecommand1.nim create mode 100644 tests/parser/tinvtypecommand2.nim create mode 100644 tests/parser/tinvtypecommand3.nim diff --git a/tests/parser/tinvtypecommand1.nim b/tests/parser/tinvtypecommand1.nim new file mode 100644 index 0000000000000..9aa274e2a577c --- /dev/null +++ b/tests/parser/tinvtypecommand1.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/tinvtypecommand2.nim b/tests/parser/tinvtypecommand2.nim new file mode 100644 index 0000000000000..0883df90f9205 --- /dev/null +++ b/tests/parser/tinvtypecommand2.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/tinvtypecommand3.nim b/tests/parser/tinvtypecommand3.nim new file mode 100644 index 0000000000000..7ca59a7999fae --- /dev/null +++ b/tests/parser/tinvtypecommand3.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/ttypesectioncalls.nim b/tests/parser/ttypesectioncalls.nim index dc7c797df9978..93de611e59eb2 100644 --- a/tests/parser/ttypesectioncalls.nim +++ b/tests/parser/ttypesectioncalls.nim @@ -120,6 +120,57 @@ StmtList 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 a: IntLit 1 a: IntLit 2 a: StmtList @@ -160,6 +211,41 @@ 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 ''' """ import macros @@ -208,3 +294,12 @@ sections: 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 From 153b1698222117f9dc4dd43bf432797574e36358 Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Sat, 1 Jan 2022 10:47:50 +0300 Subject: [PATCH 5/5] even more tests --- ...typecommand3.nim => ttypecommandcomma.nim} | 0 ...pecommand1.nim => ttypecommandindent1.nim} | 0 ...pecommand2.nim => ttypecommandindent2.nim} | 0 tests/parser/ttypecommandindent3.nim | 11 +++++++++ tests/parser/ttypesectioncalls.nim | 23 +++++++++++++++++++ 5 files changed, 34 insertions(+) rename tests/parser/{tinvtypecommand3.nim => ttypecommandcomma.nim} (100%) rename tests/parser/{tinvtypecommand1.nim => ttypecommandindent1.nim} (100%) rename tests/parser/{tinvtypecommand2.nim => ttypecommandindent2.nim} (100%) create mode 100644 tests/parser/ttypecommandindent3.nim diff --git a/tests/parser/tinvtypecommand3.nim b/tests/parser/ttypecommandcomma.nim similarity index 100% rename from tests/parser/tinvtypecommand3.nim rename to tests/parser/ttypecommandcomma.nim diff --git a/tests/parser/tinvtypecommand1.nim b/tests/parser/ttypecommandindent1.nim similarity index 100% rename from tests/parser/tinvtypecommand1.nim rename to tests/parser/ttypecommandindent1.nim diff --git a/tests/parser/tinvtypecommand2.nim b/tests/parser/ttypecommandindent2.nim similarity index 100% rename from tests/parser/tinvtypecommand2.nim rename to tests/parser/ttypecommandindent2.nim diff --git a/tests/parser/ttypecommandindent3.nim b/tests/parser/ttypecommandindent3.nim new file mode 100644 index 0000000000000..f9fdcc1e41bf2 --- /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 index 93de611e59eb2..003444fc53830 100644 --- a/tests/parser/ttypesectioncalls.nim +++ b/tests/parser/ttypesectioncalls.nim @@ -171,6 +171,17 @@ 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 @@ -246,6 +257,12 @@ b: StmtList IntLit 47 c: StmtList IntLit 48 +a: StmtList + IntLit 49 +b: StmtList + IntLit 50 +c: StmtList + IntLit 51 ''' """ import macros @@ -303,3 +320,9 @@ sections: 47 do: 48 + T = call: + 49 + do: + 50 + do: + 51