From 826d273ed2f14b678a7761deadf7bd1a3a89bebb Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Thu, 13 Jan 2022 14:27:11 +0300 Subject: [PATCH 01/20] Breaking parser changes, implement https://github.com/nim-lang/RFCs/issues/442 Types are separated from expressions and better reflected in the grammar. --- compiler/parser.nim | 194 +++++++++++++++++++------------ doc/grammar.txt | 28 +++-- doc/manual.md | 11 ++ lib/pure/options.nim | 4 +- tests/parser/ttypeexprobject.nim | 10 ++ tests/parser/ttypeexprref.nim | 10 ++ 6 files changed, 169 insertions(+), 88 deletions(-) create mode 100644 tests/parser/ttypeexprobject.nim create mode 100644 tests/parser/ttypeexprref.nim diff --git a/compiler/parser.nim b/compiler/parser.nim index dbfbec733e68..a247b15dce08 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -79,7 +79,7 @@ type smNormal, smAllowNil, smAfterDot PrimaryMode = enum - pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix + pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix, pmSkipCommand proc parseAll*(p: var Parser): PNode proc closeParser*(p: var Parser) @@ -287,6 +287,7 @@ proc newIdentNodeP(ident: PIdent, p: Parser): PNode = proc parseExpr(p: var Parser): PNode proc parseStmt(p: var Parser): PNode proc parseTypeDesc(p: var Parser): PNode +proc parseTypeDefAux(p: var Parser): PNode proc parseParamList(p: var Parser, retColon = true): PNode proc isSigilLike(tok: Token): bool {.inline.} = @@ -406,22 +407,26 @@ proc parseSymbol(p: var Parser, mode = smNormal): PNode = #if not isKeyword(p.tok.tokType): getTok(p) result = p.emptyNode -proc colonOrEquals(p: var Parser, a: PNode): PNode = - if p.tok.tokType == tkColon: - result = newNodeP(nkExprColonExpr, p) +proc equals(p: var Parser, a: PNode): PNode = + if p.tok.tokType == tkEquals: + result = newNodeP(nkExprEqExpr, p) getTok(p) - newlineWasSplitting(p) #optInd(p, result) result.add(a) result.add(parseExpr(p)) - elif p.tok.tokType == tkEquals: - result = newNodeP(nkExprEqExpr, p) + else: + result = a + +proc colonOrEquals(p: var Parser, a: PNode): PNode = + if p.tok.tokType == tkColon: + result = newNodeP(nkExprColonExpr, p) getTok(p) + newlineWasSplitting(p) #optInd(p, result) result.add(a) result.add(parseExpr(p)) else: - result = a + result = equals(p, a) proc exprColonEqExpr(p: var Parser): PNode = #| exprColonEqExpr = expr (':'|'=' expr)? @@ -431,6 +436,14 @@ proc exprColonEqExpr(p: var Parser): PNode = else: result = colonOrEquals(p, a) +proc exprEqExpr(p: var Parser): PNode = + #| exprEqExpr = expr ('=' expr)? + var a = parseExpr(p) + if p.tok.tokType == tkDo: + result = postExprBlocks(p, a) + else: + result = equals(p, a) + proc exprList(p: var Parser, endTok: TokType, result: PNode) = #| exprList = expr ^+ comma when defined(nimpretty): @@ -802,16 +815,12 @@ proc namedParams(p: var Parser, callee: PNode, proc commandParam(p: var Parser, isFirstParam: var bool; mode: PrimaryMode): PNode = if mode == pmTypeDesc: result = simpleExpr(p, mode) + elif not isFirstParam: + result = exprEqExpr(p) else: result = parseExpr(p) - if p.tok.tokType == tkDo: - result = postExprBlocks(p, result) - elif p.tok.tokType == tkEquals and not isFirstParam: - let lhs = result - result = newNodeP(nkExprEqExpr, p) - getTok(p) - result.add(lhs) - result.add(parseExpr(p)) + if p.tok.tokType == tkDo: + result = postExprBlocks(p, result) isFirstParam = false proc commandExpr(p: var Parser; r: PNode; mode: PrimaryMode): PNode = @@ -843,14 +852,8 @@ proc primarySuffix(p: var Parser, r: PNode, of tkParLe: # progress guaranteed if p.tok.strongSpaceA: - result = commandExpr(p, result, mode) - # type sections allow full command syntax - if mode == pmTypeDef: - var isFirstParam = false - while p.tok.tokType == tkComma: - getTok(p) - optInd(p, result) - result.add(commandParam(p, isFirstParam, mode)) + if mode != pmSkipCommand: + result = commandExpr(p, result, mode) break result = namedParams(p, result, nkCall, tkParRi) if result.len > 1 and result[1].kind == nkExprColonExpr: @@ -862,13 +865,15 @@ proc primarySuffix(p: var Parser, r: PNode, of tkBracketLe: # progress guaranteed if p.tok.strongSpaceA: - result = commandExpr(p, result, mode) + if mode != pmSkipCommand: + result = commandExpr(p, result, mode) break result = namedParams(p, result, nkBracketExpr, tkBracketRi) of tkCurlyLe: # progress guaranteed if p.tok.strongSpaceA: - result = commandExpr(p, result, mode) + if mode != pmSkipCommand: + result = commandExpr(p, result, mode) break result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) of tkSymbol, tkAccent, tkIntLit..tkCustomLit, tkNil, tkCast, @@ -887,22 +892,14 @@ proc primarySuffix(p: var Parser, r: PNode, else: if isDotLike2: parMessage(p, warnDotLikeOps, "dot-like operators will be parsed differently with `-d:nimPreviewDotLikeOps`") - if p.inPragma == 0 and (isUnary(p.tok) or p.tok.tokType notin {tkOpr, tkDotDot}): + if mode != pmSkipCommand and + p.inPragma == 0 and (isUnary(p.tok) or p.tok.tokType notin {tkOpr, tkDotDot}): # 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 = @@ -1043,9 +1040,10 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode = result.add(newNodeP(nkEmpty, p)) proc parseTuple(p: var Parser, indentAllowed = false): PNode = - #| tupleDecl = 'tuple' - #| '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' | - #| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)? + #| tupleType = 'tuple' + #| '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' + #| tupleDecl = tupleType | + #| ('tuple' COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?) result = newNodeP(nkTupleTy, p) getTok(p) if p.tok.tokType == tkBracketLe: @@ -1155,6 +1153,7 @@ proc parseDoBlock(p: var Parser; info: TLineInfo): PNode = proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode = #| routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)? + #| routineType = ('proc' | 'iterator') paramListColon pragma? # either a proc type or a anonymous proc let info = parLineInfo(p) let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0 @@ -1193,14 +1192,20 @@ proc parseSymbolList(p: var Parser, result: PNode) = getTok(p) optInd(p, s) -proc parseTypeDescKAux(p: var Parser, kind: TNodeKind, +proc parseTypeDescKAux(p: var Parser, + kind: TNodeKind, mode: PrimaryMode): PNode = result = newNodeP(kind, p) getTok(p) if p.tok.indent != -1 and p.tok.indent <= p.currInd: return optInd(p, result) if not isOperator(p.tok) and isExprStart(p): - result.add(primary(p, mode)) + if mode == pmTypeDef: + result.add(parseTypeDefAux(p)) + elif mode == pmTypeDesc: + result.add(parseTypeDesc(p)) + else: + result.add(primary(p, mode)) if kind == nkDistinctTy and p.tok.tokType == tkSymbol: # XXX document this feature! var nodeKind: TNodeKind @@ -1284,9 +1289,9 @@ proc parseTypeClass(p: var Parser): PNode proc primary(p: var Parser, mode: PrimaryMode): PNode = #| primary = operatorB primary primarySuffix* | - #| tupleDecl | routineExpr | enumDecl - #| objectDecl | conceptDecl | ('bind' primary) - #| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') primary + #| routineExpr | + #| 'bind' primary | + #| rawTypeDesc #| / prefixOperator* identOrLiteral primarySuffix* if isOperator(p.tok): # Note 'sigil like' operators are currently not reflected in the grammar @@ -1307,7 +1312,6 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode = return case p.tok.tokType - of tkTuple: result = parseTuple(p, mode == pmTypeDef) of tkProc: getTok(p) result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda) @@ -1317,35 +1321,14 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode = of tkIterator: getTok(p) result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkIteratorDef) - of tkEnum: - if mode == pmTypeDef: - prettySection: - result = parseEnum(p) - else: - result = newNodeP(nkEnumTy, p) - getTok(p) - of tkObject: - if mode == pmTypeDef: - prettySection: - result = parseObject(p) - else: - result = newNodeP(nkObjectTy, p) - getTok(p) - of tkConcept: - if mode == pmTypeDef: - result = parseTypeClass(p) - else: - parMessage(p, "the 'concept' keyword is only valid in 'type' sections") of tkBind: result = newNodeP(nkBind, p) getTok(p) optInd(p, result) result.add(primary(p, pmNormal)) - of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode) - of tkOut: result = parseTypeDescKAux(p, nkOutTy, mode) - of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode) - of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode) - of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode) + of tkTuple, tkEnum, tkObject, tkConcept, + tkVar, tkOut, tkRef, tkPtr, tkDistinct: + result = parseTypeDesc(p) else: let baseInd = p.lex.currLineIndent result = identOrLiteral(p, mode) @@ -1366,15 +1349,74 @@ proc binaryNot(p: var Parser; a: PNode): PNode = result = a proc parseTypeDesc(p: var Parser): PNode = - #| typeDesc = simpleExpr ('not' expr)? + #| rawTypeDesc = (tupleType | routineType | 'enum' | 'object' | + #| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?) + #| ('not' expr)? + #| typeDesc = rawTypeDesc | simpleExpr ('not' expr)? newlineWasSplitting(p) - result = simpleExpr(p, pmTypeDesc) + case p.tok.tokType + of tkTuple: + result = parseTuple(p, false) + of tkProc: + result = parseProcExpr(p, false, nkLambda) + of tkIterator: + result = parseProcExpr(p, false, nkLambda) + if result.kind == nkLambda: result.transitionSonsKind(nkIteratorDef) + else: result.transitionSonsKind(nkIteratorTy) + of tkEnum: + result = newNodeP(nkEnumTy, p) + getTok(p) + of tkObject: + result = newNodeP(nkObjectTy, p) + getTok(p) + of tkConcept: + parMessage(p, "the 'concept' keyword is only valid in 'type' sections") + of tkVar: result = parseTypeDescKAux(p, nkVarTy, pmTypeDesc) + of tkOut: result = parseTypeDescKAux(p, nkOutTy, pmTypeDesc) + of tkRef: result = parseTypeDescKAux(p, nkRefTy, pmTypeDesc) + of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, pmTypeDesc) + of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDesc) + else: + result = simpleExpr(p, pmTypeDesc) result = binaryNot(p, result) proc parseTypeDefAux(p: var Parser): PNode = - #| typeDefAux = simpleExpr ('not' expr - #| | postExprBlocks)? - result = simpleExpr(p, pmTypeDef) + #| typeDefAux = ((tupleDecl | routineType | + #| ('ref' | 'ptr') typeDefAux? | + #| enumDecl | objectDecl | conceptDecl) + #| / exprStmt) ('not' expr)? + case p.tok.tokType + of tkTuple: + result = parseTuple(p, true) + of tkProc: result = parseProcExpr(p, false, nkLambda) + of tkIterator: + result = parseProcExpr(p, false, nkLambda) + if result.kind == nkLambda: result.transitionSonsKind(nkIteratorDef) + else: result.transitionSonsKind(nkIteratorTy) + of tkRef: + result = parseTypeDescKAux(p, nkRefTy, pmTypeDef) + of tkPtr: + result = parseTypeDescKAux(p, nkPtrTy, pmTypeDef) + of tkEnum: + prettySection: + result = parseEnum(p) + of tkObject: + prettySection: + result = parseObject(p) + of tkConcept: + result = parseTypeClass(p) + else: + result = simpleExpr(p, pmTypeDef) + if p.tok.tokType == tkNot: + result = binaryNot(p, result) + else: + if result.kind == nkCommand: + var isFirstParam = false + while p.tok.tokType == tkComma: + getTok(p) + optInd(p, result) + result.add(commandParam(p, isFirstParam, pmTypeDef)) + result = postExprBlocks(p, result) result = binaryNot(p, result) proc makeCall(n: PNode): PNode = @@ -1469,10 +1511,10 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode = proc parseExprStmt(p: var Parser): PNode = #| exprStmt = simpleExpr #| (( '=' optInd expr colonBody? ) - #| / ( expr ^+ comma + #| / ( exprEqExpr ^+ comma #| postExprBlocks #| ))? - var a = simpleExpr(p) + var a = simpleExpr(p, pmSkipCommand) if p.tok.tokType == tkEquals: result = newNodeP(nkAsgn, p) getTok(p) diff --git a/doc/grammar.txt b/doc/grammar.txt index 63ce4503c5c8..42e5f231e49e 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -28,6 +28,7 @@ operatorB = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 | symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' | IDENT | KEYW exprColonEqExpr = expr (':'|'=' expr)? +exprEqExpr = expr ('=' expr)? exprList = expr ^+ comma exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? qualifiedIdent = symbol ('.' optInd symbol)? @@ -70,14 +71,16 @@ declColonEquals = identWithPragma (comma identWithPragma)* comma? (':' optInd typeDesc)? ('=' optInd expr)? identColonEquals = IDENT (comma IDENT)* comma? (':' optInd typeDesc)? ('=' optInd expr)?) -tupleDecl = 'tuple' - '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' | - COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)? +tupleType = 'tuple' + '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' +tupleDecl = tupleType | + ('tuple' COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?) paramList = '(' declColonEquals ^* (comma/semicolon) ')' paramListArrow = paramList? ('->' optInd typeDesc)? paramListColon = paramList? (':' optInd typeDesc)? doBlock = 'do' paramListArrow pragma? colcom stmt routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)? +routineType = ('proc' | 'iterator') paramListColon pragma? forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt forExpr = forStmt expr = (blockExpr @@ -88,13 +91,18 @@ expr = (blockExpr | tryExpr) / simpleExpr primary = operatorB primary primarySuffix* | - tupleDecl | routineExpr | enumDecl - objectDecl | conceptDecl | ('bind' primary) - ('var' | 'out' | 'ref' | 'ptr' | 'distinct') primary + routineExpr | + 'bind' primary | + rawTypeDesc / prefixOperator* identOrLiteral primarySuffix* -typeDesc = simpleExpr ('not' expr)? -typeDefAux = simpleExpr ('not' expr - | postExprBlocks)? +rawTypeDesc = (tupleType | routineType | 'enum' | 'object' | + ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?) + ('not' expr)? +typeDesc = rawTypeDesc | simpleExpr ('not' expr)? +typeDefAux = ((tupleDecl | routineType | + ('ref' | 'ptr') typeDefAux? | + enumDecl | objectDecl | conceptDecl) + / exprStmt) ('not' expr)? postExprBlocks = ':' stmt? ( IND{=} doBlock | IND{=} 'of' exprList ':' stmt | IND{=} 'elif' expr ':' stmt @@ -103,7 +111,7 @@ postExprBlocks = ':' stmt? ( IND{=} doBlock | IND{=} 'else' ':' stmt )* exprStmt = simpleExpr (( '=' optInd expr colonBody? ) - / ( expr ^+ comma + / ( exprEqExpr ^+ comma postExprBlocks ))? importStmt = 'import' optInd expr diff --git a/doc/manual.md b/doc/manual.md index 378aaed905b7..ab54f504e2dc 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -2084,6 +2084,17 @@ This feature is useful if an object should only gain reference semantics: data: int ``` +As a consequence of this syntax, normal expressions starting with `ref` +or `ptr` must be wrapped in parentheses or some other expression form +to be used directly in type sections. + +.. code-block:: nim + type + # invalid + IntRef = ref int | ptr int + # correct + IntRef = (ref int | ptr int) + To allocate a new traced object, the built-in procedure `new` has to be used. To deal with untraced memory, the procedures `alloc`, `dealloc` and diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 9dc4e096b33b..f7cd1e7fbf34 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -81,10 +81,10 @@ when defined(nimPreviewSlimSystem): when (NimMajor, NimMinor) >= (1, 1): type - SomePointer = ref | ptr | pointer | proc + SomePointer = (ref | ptr | pointer | proc) else: type - SomePointer = ref | ptr | pointer + SomePointer = (ref | ptr | pointer) type Option*[T] = object diff --git a/tests/parser/ttypeexprobject.nim b/tests/parser/ttypeexprobject.nim new file mode 100644 index 000000000000..6895f1731a53 --- /dev/null +++ b/tests/parser/ttypeexprobject.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "invalid indentation" + line: 10 + column: 14 +""" + +type + A = (object | tuple | int) + B = int | object | tuple + C = object | tuple | int # issue #8846 diff --git a/tests/parser/ttypeexprref.nim b/tests/parser/ttypeexprref.nim new file mode 100644 index 000000000000..67716eeedda5 --- /dev/null +++ b/tests/parser/ttypeexprref.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "invalid indentation" + line: 10 + column: 11 +""" + +type + A = (ref | ptr | pointer) + B = pointer | ptr | ref + C = ref | ptr | pointer From 643d5394e89942dadb55bade3ed772c205b5b439 Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Thu, 13 Jan 2022 14:43:55 +0300 Subject: [PATCH 02/20] add test --- tests/parser/tcommandequals.nim | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/parser/tcommandequals.nim diff --git a/tests/parser/tcommandequals.nim b/tests/parser/tcommandequals.nim new file mode 100644 index 000000000000..f41b318acf44 --- /dev/null +++ b/tests/parser/tcommandequals.nim @@ -0,0 +1,17 @@ +discard """ + output: ''' +5 +''' +""" + +proc foo(a, b: int) = + echo a + b + +foo a = 2, b = 3 + +import macros + +macro bar(args: varargs[untyped]): untyped = + doAssert args[0].kind == nnkExprEqExpr + +bar "a" = 1 From 9b45773bd2869602f396cb9102840ddf6096b28b Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Thu, 13 Jan 2022 14:52:35 +0300 Subject: [PATCH 03/20] more accurate grammar --- compiler/parser.nim | 13 +++---------- doc/grammar.txt | 3 ++- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index a247b15dce08..09f02fc8b013 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1384,7 +1384,8 @@ proc parseTypeDefAux(p: var Parser): PNode = #| typeDefAux = ((tupleDecl | routineType | #| ('ref' | 'ptr') typeDefAux? | #| enumDecl | objectDecl | conceptDecl) - #| / exprStmt) ('not' expr)? + #| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?)) + #| ('not' expr)? case p.tok.tokType of tkTuple: result = parseTuple(p, true) @@ -1524,16 +1525,8 @@ proc parseExprStmt(p: var Parser): PNode = result.add(a) result.add(b) else: - # simpleExpr parsed 'p a' from 'p a, b'? var isFirstParam = false - if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand: - result = a - while true: - getTok(p) - optInd(p, result) - result.add(commandParam(p, isFirstParam, pmNormal)) - if p.tok.tokType != tkComma: break - elif p.tok.indent < 0 and isExprStart(p): + if p.tok.indent < 0 and isExprStart(p): result = newTreeI(nkCommand, a.info, a) while true: result.add(commandParam(p, isFirstParam, pmNormal)) diff --git a/doc/grammar.txt b/doc/grammar.txt index 42e5f231e49e..03b0a5b32655 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -102,7 +102,8 @@ typeDesc = rawTypeDesc | simpleExpr ('not' expr)? typeDefAux = ((tupleDecl | routineType | ('ref' | 'ptr') typeDefAux? | enumDecl | objectDecl | conceptDecl) - / exprStmt) ('not' expr)? + / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?)) + ('not' expr)? postExprBlocks = ':' stmt? ( IND{=} doBlock | IND{=} 'of' exprList ':' stmt | IND{=} 'elif' expr ':' stmt From bc2763abb830a26694d27181bf333a344c4e7f44 Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Thu, 13 Jan 2022 15:12:56 +0300 Subject: [PATCH 04/20] fix keyword typedescs --- compiler/parser.nim | 2 -- tests/parser/ttypeexprs.nim | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 tests/parser/ttypeexprs.nim diff --git a/compiler/parser.nim b/compiler/parser.nim index 09f02fc8b013..55069c6f7b23 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1202,8 +1202,6 @@ proc parseTypeDescKAux(p: var Parser, if not isOperator(p.tok) and isExprStart(p): if mode == pmTypeDef: result.add(parseTypeDefAux(p)) - elif mode == pmTypeDesc: - result.add(parseTypeDesc(p)) else: result.add(primary(p, mode)) if kind == nkDistinctTy and p.tok.tokType == tkSymbol: diff --git a/tests/parser/ttypeexprs.nim b/tests/parser/ttypeexprs.nim new file mode 100644 index 000000000000..380dc909498d --- /dev/null +++ b/tests/parser/ttypeexprs.nim @@ -0,0 +1,3 @@ +proc foo[T: ptr int | ptr string](x: T) = discard +var x = "abc" +foo(addr x) From b9c74300e2a838e6d77d500da5ddbeec04cd8ffa Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Thu, 13 Jan 2022 19:16:50 +0300 Subject: [PATCH 05/20] accept expressions in proc argument lists --- compiler/parser.nim | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 55069c6f7b23..4eb850a1927e 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -787,7 +787,7 @@ proc identOrLiteral(p: var Parser, mode: PrimaryMode): PNode = getTok(p) of tkParLe: # () constructor - if mode in {pmTypeDesc, pmTypeDef}: + if false and mode in {pmTypeDesc, pmTypeDef}: result = exprColonEqExprList(p, nkPar, tkParRi) else: result = parsePar(p) @@ -1007,9 +1007,9 @@ type proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode = #| declColonEquals = identWithPragma (comma identWithPragma)* comma? - #| (':' optInd typeDesc)? ('=' optInd expr)? + #| (':' optInd simpleExpr)? ('=' optInd expr)? #| identColonEquals = IDENT (comma IDENT)* comma? - #| (':' optInd typeDesc)? ('=' optInd expr)?) + #| (':' optInd simpleExpr)? ('=' optInd expr)?) var a: PNode result = newNodeP(nkIdentDefs, p) # progress guaranteed @@ -1027,7 +1027,8 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode = if p.tok.tokType == tkColon: getTok(p) optInd(p, result) - result.add(parseTypeDesc(p)) + # mode mostly because of subsequent = + result.add(simpleExpr(p, pmTypeDesc)) else: result.add(newNodeP(nkEmpty, p)) if p.tok.tokType != tkEquals and withBothOptional notin flags: @@ -1350,7 +1351,7 @@ proc parseTypeDesc(p: var Parser): PNode = #| rawTypeDesc = (tupleType | routineType | 'enum' | 'object' | #| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?) #| ('not' expr)? - #| typeDesc = rawTypeDesc | simpleExpr ('not' expr)? + #| typeDesc = rawTypeDesc / simpleExpr newlineWasSplitting(p) case p.tok.tokType of tkTuple: @@ -1376,14 +1377,14 @@ proc parseTypeDesc(p: var Parser): PNode = of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDesc) else: result = simpleExpr(p, pmTypeDesc) + return result result = binaryNot(p, result) proc parseTypeDefAux(p: var Parser): PNode = #| typeDefAux = ((tupleDecl | routineType | #| ('ref' | 'ptr') typeDefAux? | - #| enumDecl | objectDecl | conceptDecl) - #| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?)) - #| ('not' expr)? + #| enumDecl | objectDecl | conceptDecl) ('not' expr)?) + #| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?) case p.tok.tokType of tkTuple: result = parseTuple(p, true) @@ -1416,6 +1417,7 @@ proc parseTypeDefAux(p: var Parser): PNode = optInd(p, result) result.add(commandParam(p, isFirstParam, pmTypeDef)) result = postExprBlocks(p, result) + return result result = binaryNot(p, result) proc makeCall(n: PNode): PNode = From 7a99704a818b1948be458ed7f8f70dd96268cac8 Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Thu, 13 Jan 2022 19:35:18 +0300 Subject: [PATCH 06/20] CI "fixes" --- compiler/parser.nim | 2 +- compiler/semtypes.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 4eb850a1927e..f8667af4b4e8 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -928,7 +928,7 @@ proc parseOperators(p: var Parser, headNode: PNode, proc simpleExprAux(p: var Parser, limit: int, mode: PrimaryMode): PNode = result = primary(p, mode) if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)) and - mode == pmNormal: + mode in {pmNormal, pmSkipCommand}: var pragmaExp = newNodeP(nkPragmaExpr, p) pragmaExp.add result pragmaExp.add p.parsePragma diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 945d22ab7e3e..2d2de9aeb081 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -2053,7 +2053,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = semProcTypeWithScope(c, n, prev, skProc) of nkEnumTy: result = semEnum(c, n, prev) of nkType: result = n.typ - of nkStmtListType: result = semStmtListType(c, n, prev) + of nkStmtListType, nkStmtList: result = semStmtListType(c, n, prev) of nkBlockType: result = semBlockType(c, n, prev) else: result = semTypeExpr(c, n, prev) From 32cf5e1d300519c731599432a56b9697cf2171fa Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Thu, 13 Jan 2022 21:44:12 +0300 Subject: [PATCH 07/20] fixes --- compiler/parser.nim | 32 +++++++++++++++++-------------- tests/parser/tcommand_as_expr.nim | 9 +++++++++ tests/parser/tcommandindent.nim | 16 ++++++++++++++++ tests/parser/ttypeexprs.nim | 7 +++++++ 4 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 tests/parser/tcommandindent.nim diff --git a/compiler/parser.nim b/compiler/parser.nim index f8667af4b4e8..ccc44ae3df31 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -79,7 +79,7 @@ type smNormal, smAllowNil, smAfterDot PrimaryMode = enum - pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix, pmSkipCommand + pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix, pmCommandStart proc parseAll*(p: var Parser): PNode proc closeParser*(p: var Parser) @@ -787,7 +787,7 @@ proc identOrLiteral(p: var Parser, mode: PrimaryMode): PNode = getTok(p) of tkParLe: # () constructor - if false and mode in {pmTypeDesc, pmTypeDef}: + if mode in {pmTypeDesc, pmTypeDef}: result = exprColonEqExprList(p, nkPar, tkParRi) else: result = parsePar(p) @@ -852,7 +852,7 @@ proc primarySuffix(p: var Parser, r: PNode, of tkParLe: # progress guaranteed if p.tok.strongSpaceA: - if mode != pmSkipCommand: + if mode != pmCommandStart: result = commandExpr(p, result, mode) break result = namedParams(p, result, nkCall, tkParRi) @@ -865,14 +865,14 @@ proc primarySuffix(p: var Parser, r: PNode, of tkBracketLe: # progress guaranteed if p.tok.strongSpaceA: - if mode != pmSkipCommand: + if mode != pmCommandStart: result = commandExpr(p, result, mode) break result = namedParams(p, result, nkBracketExpr, tkBracketRi) of tkCurlyLe: # progress guaranteed if p.tok.strongSpaceA: - if mode != pmSkipCommand: + if mode != pmCommandStart: result = commandExpr(p, result, mode) break result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) @@ -892,7 +892,7 @@ proc primarySuffix(p: var Parser, r: PNode, else: if isDotLike2: parMessage(p, warnDotLikeOps, "dot-like operators will be parsed differently with `-d:nimPreviewDotLikeOps`") - if mode != pmSkipCommand and + if mode != pmCommandStart and p.inPragma == 0 and (isUnary(p.tok) or p.tok.tokType notin {tkOpr, tkDotDot}): # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet # solution, but pragmas.nim can't handle that @@ -927,8 +927,9 @@ proc parseOperators(p: var Parser, headNode: PNode, proc simpleExprAux(p: var Parser, limit: int, mode: PrimaryMode): PNode = result = primary(p, mode) + let mode = if mode == pmCommandStart: pmNormal else: mode if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)) and - mode in {pmNormal, pmSkipCommand}: + mode == pmNormal: var pragmaExp = newNodeP(nkPragmaExpr, p) pragmaExp.add result pragmaExp.add p.parsePragma @@ -1351,7 +1352,7 @@ proc parseTypeDesc(p: var Parser): PNode = #| rawTypeDesc = (tupleType | routineType | 'enum' | 'object' | #| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?) #| ('not' expr)? - #| typeDesc = rawTypeDesc / simpleExpr + #| typeDesc = rawTypeDesc / simpleExpr ('not' expr)? newlineWasSplitting(p) case p.tok.tokType of tkTuple: @@ -1377,14 +1378,13 @@ proc parseTypeDesc(p: var Parser): PNode = of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDesc) else: result = simpleExpr(p, pmTypeDesc) - return result result = binaryNot(p, result) proc parseTypeDefAux(p: var Parser): PNode = #| typeDefAux = ((tupleDecl | routineType | - #| ('ref' | 'ptr') typeDefAux? | + #| ('ref' | 'ptr' | 'distinct') typeDefAux? | #| enumDecl | objectDecl | conceptDecl) ('not' expr)?) - #| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?) + #| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)? ('not' expr)?) case p.tok.tokType of tkTuple: result = parseTuple(p, true) @@ -1397,6 +1397,8 @@ proc parseTypeDefAux(p: var Parser): PNode = result = parseTypeDescKAux(p, nkRefTy, pmTypeDef) of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, pmTypeDef) + of tkDistinct: + result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDef) of tkEnum: prettySection: result = parseEnum(p) @@ -1417,7 +1419,6 @@ proc parseTypeDefAux(p: var Parser): PNode = optInd(p, result) result.add(commandParam(p, isFirstParam, pmTypeDef)) result = postExprBlocks(p, result) - return result result = binaryNot(p, result) proc makeCall(n: PNode): PNode = @@ -1515,7 +1516,7 @@ proc parseExprStmt(p: var Parser): PNode = #| / ( exprEqExpr ^+ comma #| postExprBlocks #| ))? - var a = simpleExpr(p, pmSkipCommand) + var a = simpleExpr(p, pmCommandStart) if p.tok.tokType == tkEquals: result = newNodeP(nkAsgn, p) getTok(p) @@ -1528,9 +1529,12 @@ proc parseExprStmt(p: var Parser): PNode = var isFirstParam = false if p.tok.indent < 0 and isExprStart(p): result = newTreeI(nkCommand, a.info, a) + let baseIndent = p.currInd while true: result.add(commandParam(p, isFirstParam, pmNormal)) - if p.tok.tokType != tkComma: break + if p.tok.tokType != tkComma or + (p.tok.indent >= 0 and p.tok.indent < baseIndent): + break getTok(p) optInd(p, result) else: diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim index b25ec4bd8059..f37c34f63049 100644 --- a/tests/parser/tcommand_as_expr.nim +++ b/tests/parser/tcommand_as_expr.nim @@ -36,3 +36,12 @@ echo f -4 echo int -1 # doesn't compile echo int `-` 1 # compiles + +var num = 1 +num += int 2 +doAssert num == 3 + +import options +var opt = some some none int +opt = some some none int +opt = some none Option[int] diff --git a/tests/parser/tcommandindent.nim b/tests/parser/tcommandindent.nim new file mode 100644 index 000000000000..449c218dbd92 --- /dev/null +++ b/tests/parser/tcommandindent.nim @@ -0,0 +1,16 @@ +when false: # parse the following + let foo = Obj( + field1: proc (src: pointer, srcLen: Natural) + {.nimcall, gcsafe, raises: [IOError, Defect].} = + var file = FileOutputStream(s).file + + implementWrites s.buffers, src, srcLen, "FILE", + writeStartAddr, writeLen, + file.writeBuffer(writeStartAddr, writeLen) + , + field2: proc {.nimcall, gcsafe, raises: [IOError, Defect].} = + flushFile FileOutputStream(s).file + , + field3: proc () {.nimcall, gcsafe, raises: [IOError, Defect].} = + close FileOutputStream(s).file + ) diff --git a/tests/parser/ttypeexprs.nim b/tests/parser/ttypeexprs.nim index 380dc909498d..4d6e94ef4cc0 100644 --- a/tests/parser/ttypeexprs.nim +++ b/tests/parser/ttypeexprs.nim @@ -1,3 +1,10 @@ proc foo[T: ptr int | ptr string](x: T) = discard var x = "abc" foo(addr x) + +let n = 3'u32 +type Double = ( + when n.sizeof == 4: uint64 + elif n.sizeof == 2: uint32 + else: uint16 +) From 00a0ee1bc352c42a578e5b82a74d7cd9c04671bf Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Fri, 14 Jan 2022 15:45:33 +0300 Subject: [PATCH 08/20] allow full ref expressions again, adapt old tests --- compiler/parser.nim | 80 ++++++++++--------- doc/grammar.txt | 14 ++-- doc/manual.md | 20 ++--- tests/assert/tassert2.nim | 2 +- tests/effects/tdiagnostic_messages.nim | 2 +- tests/effects/teffects1.nim | 2 +- tests/errmsgs/tsigmatch2.nim | 4 +- tests/parser/ttypeexprref.nim | 10 --- tests/parser/ttypeexprs.nim | 13 +++ tests/typerel/t7600_1.nim | 2 +- tests/typerel/t7600_2.nim | 2 +- .../varres/tprevent_forloopvar_mutations.nim | 2 +- 12 files changed, 81 insertions(+), 72 deletions(-) delete mode 100644 tests/parser/ttypeexprref.nim diff --git a/compiler/parser.nim b/compiler/parser.nim index ccc44ae3df31..ea3c1304e64c 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -79,7 +79,8 @@ type smNormal, smAllowNil, smAfterDot PrimaryMode = enum - pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix, pmCommandStart + pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix, pmCommandStart, + pmTypeDescStart proc parseAll*(p: var Parser): PNode proc closeParser*(p: var Parser) @@ -286,7 +287,7 @@ proc newIdentNodeP(ident: PIdent, p: Parser): PNode = proc parseExpr(p: var Parser): PNode proc parseStmt(p: var Parser): PNode -proc parseTypeDesc(p: var Parser): PNode +proc parseTypeDesc(p: var Parser, fullExpr = false): PNode proc parseTypeDefAux(p: var Parser): PNode proc parseParamList(p: var Parser, retColon = true): PNode @@ -1008,9 +1009,9 @@ type proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode = #| declColonEquals = identWithPragma (comma identWithPragma)* comma? - #| (':' optInd simpleExpr)? ('=' optInd expr)? + #| (':' optInd typeDescExpr)? ('=' optInd expr)? #| identColonEquals = IDENT (comma IDENT)* comma? - #| (':' optInd simpleExpr)? ('=' optInd expr)?) + #| (':' optInd typeDescExpr)? ('=' optInd expr)?) var a: PNode result = newNodeP(nkIdentDefs, p) # progress guaranteed @@ -1028,8 +1029,7 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode = if p.tok.tokType == tkColon: getTok(p) optInd(p, result) - # mode mostly because of subsequent = - result.add(simpleExpr(p, pmTypeDesc)) + result.add(parseTypeDesc(p, fullExpr = true)) else: result.add(newNodeP(nkEmpty, p)) if p.tok.tokType != tkEquals and withBothOptional notin flags: @@ -1201,8 +1201,9 @@ proc parseTypeDescKAux(p: var Parser, getTok(p) if p.tok.indent != -1 and p.tok.indent <= p.currInd: return optInd(p, result) + let isTypedef = mode == pmTypeDef and p.tok.tokType in {tkObject, tkTuple} if not isOperator(p.tok) and isExprStart(p): - if mode == pmTypeDef: + if isTypedef: result.add(parseTypeDefAux(p)) else: result.add(primary(p, mode)) @@ -1219,6 +1220,8 @@ proc parseTypeDescKAux(p: var Parser, let list = newNodeP(nodeKind, p) result.add list parseSymbolList(p, list) + if mode == pmTypeDef and not isTypedef: + result = parseOperators(p, result, -1, mode) proc parseVarTuple(p: var Parser): PNode @@ -1348,36 +1351,40 @@ proc binaryNot(p: var Parser; a: PNode): PNode = else: result = a -proc parseTypeDesc(p: var Parser): PNode = +proc parseTypeDesc(p: var Parser, fullExpr = false): PNode = #| rawTypeDesc = (tupleType | routineType | 'enum' | 'object' | #| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?) #| ('not' expr)? - #| typeDesc = rawTypeDesc / simpleExpr ('not' expr)? + #| typeDescExpr = simpleExpr ('not' expr)? + #| typeDesc = rawTypeDesc / typeDescExpr newlineWasSplitting(p) - case p.tok.tokType - of tkTuple: - result = parseTuple(p, false) - of tkProc: - result = parseProcExpr(p, false, nkLambda) - of tkIterator: - result = parseProcExpr(p, false, nkLambda) - if result.kind == nkLambda: result.transitionSonsKind(nkIteratorDef) - else: result.transitionSonsKind(nkIteratorTy) - of tkEnum: - result = newNodeP(nkEnumTy, p) - getTok(p) - of tkObject: - result = newNodeP(nkObjectTy, p) - getTok(p) - of tkConcept: - parMessage(p, "the 'concept' keyword is only valid in 'type' sections") - of tkVar: result = parseTypeDescKAux(p, nkVarTy, pmTypeDesc) - of tkOut: result = parseTypeDescKAux(p, nkOutTy, pmTypeDesc) - of tkRef: result = parseTypeDescKAux(p, nkRefTy, pmTypeDesc) - of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, pmTypeDesc) - of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDesc) - else: + if fullExpr: result = simpleExpr(p, pmTypeDesc) + else: + case p.tok.tokType + of tkTuple: + result = parseTuple(p, false) + of tkProc: + result = parseProcExpr(p, false, nkLambda) + of tkIterator: + result = parseProcExpr(p, false, nkLambda) + if result.kind == nkLambda: result.transitionSonsKind(nkIteratorDef) + else: result.transitionSonsKind(nkIteratorTy) + of tkEnum: + result = newNodeP(nkEnumTy, p) + getTok(p) + of tkObject: + result = newNodeP(nkObjectTy, p) + getTok(p) + of tkConcept: + parMessage(p, "the 'concept' keyword is only valid in 'type' sections") + of tkVar: result = parseTypeDescKAux(p, nkVarTy, pmTypeDesc) + of tkOut: result = parseTypeDescKAux(p, nkOutTy, pmTypeDesc) + of tkRef: result = parseTypeDescKAux(p, nkRefTy, pmTypeDesc) + of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, pmTypeDesc) + of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDesc) + else: + result = simpleExpr(p, pmTypeDesc) result = binaryNot(p, result) proc parseTypeDefAux(p: var Parser): PNode = @@ -1393,12 +1400,9 @@ proc parseTypeDefAux(p: var Parser): PNode = result = parseProcExpr(p, false, nkLambda) if result.kind == nkLambda: result.transitionSonsKind(nkIteratorDef) else: result.transitionSonsKind(nkIteratorTy) - of tkRef: - result = parseTypeDescKAux(p, nkRefTy, pmTypeDef) - of tkPtr: - result = parseTypeDescKAux(p, nkPtrTy, pmTypeDef) - of tkDistinct: - result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDef) + of tkRef: result = parseTypeDescKAux(p, nkRefTy, pmTypeDef) + of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, pmTypeDef) + of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDef) of tkEnum: prettySection: result = parseEnum(p) diff --git a/doc/grammar.txt b/doc/grammar.txt index 03b0a5b32655..a2c6a090edd6 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -68,9 +68,9 @@ identVisDot = symbol '.' optInd symbol OPR? identWithPragma = identVis pragma? identWithPragmaDot = identVisDot pragma? declColonEquals = identWithPragma (comma identWithPragma)* comma? - (':' optInd typeDesc)? ('=' optInd expr)? + (':' optInd typeDescExpr)? ('=' optInd expr)? identColonEquals = IDENT (comma IDENT)* comma? - (':' optInd typeDesc)? ('=' optInd expr)?) + (':' optInd typeDescExpr)? ('=' optInd expr)?) tupleType = 'tuple' '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' tupleDecl = tupleType | @@ -98,12 +98,12 @@ primary = operatorB primary primarySuffix* | rawTypeDesc = (tupleType | routineType | 'enum' | 'object' | ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?) ('not' expr)? -typeDesc = rawTypeDesc | simpleExpr ('not' expr)? +typeDescExpr = simpleExpr ('not' expr)? +typeDesc = rawTypeDesc / typeDescExpr typeDefAux = ((tupleDecl | routineType | - ('ref' | 'ptr') typeDefAux? | - enumDecl | objectDecl | conceptDecl) - / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?)) - ('not' expr)? + ('ref' | 'ptr' | 'distinct') typeDefAux? | + enumDecl | objectDecl | conceptDecl) ('not' expr)?) + / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)? ('not' expr)?) postExprBlocks = ':' stmt? ( IND{=} doBlock | IND{=} 'of' exprList ':' stmt | IND{=} 'elif' expr ':' stmt diff --git a/doc/manual.md b/doc/manual.md index ab54f504e2dc..4d1dccf3934a 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -2084,16 +2084,18 @@ This feature is useful if an object should only gain reference semantics: data: int ``` -As a consequence of this syntax, normal expressions starting with `ref` -or `ptr` must be wrapped in parentheses or some other expression form -to be used directly in type sections. +.. + (This part was true earlier in the PR but is not true anymore) + As a consequence of this syntax, normal expressions starting with `ref` + or `ptr` must be wrapped in parentheses or some other expression form + to be used directly in type sections. -.. code-block:: nim - type - # invalid - IntRef = ref int | ptr int - # correct - IntRef = (ref int | ptr int) + .. code-block:: nim + type + # invalid + IntRef = ref int | ptr int + # correct + IntRef = (ref int | ptr int) To allocate a new traced object, the built-in procedure `new` has to be used. diff --git a/tests/assert/tassert2.nim b/tests/assert/tassert2.nim index 5d849aaad71c..05e19cfcf957 100644 --- a/tests/assert/tassert2.nim +++ b/tests/assert/tassert2.nim @@ -24,7 +24,7 @@ except AssertionDefect as e: try: assert false # assert test with no msg except AssertionDefect as e: - assert e.msg.endsWith "tassert2.nim(25, 10) `false` " + assert e.msg.endsWith "tassert2.nim(25, 3) `false` " try: let a = 1 diff --git a/tests/effects/tdiagnostic_messages.nim b/tests/effects/tdiagnostic_messages.nim index 2ce4895a38da..b1acf8c5cf68 100644 --- a/tests/effects/tdiagnostic_messages.nim +++ b/tests/effects/tdiagnostic_messages.nim @@ -12,7 +12,7 @@ tdiagnostic_messages.nim(36, 6) Error: 'a' can have side effects >>> tdiagnostic_messages.nim(32, 33) Hint: 'callWithSideEffects' calls `.sideEffect` 'indirectCallViaPointer' >>>> tdiagnostic_messages.nim(27, 6) Hint: 'indirectCallViaPointer' called by 'callWithSideEffects' >>>>> tdiagnostic_messages.nim(28, 32) Hint: 'indirectCallViaPointer' calls routine via pointer indirection ->>> tdiagnostic_messages.nim(33, 10) Hint: 'callWithSideEffects' calls `.sideEffect` 'myEcho' +>>> tdiagnostic_messages.nim(33, 3) Hint: 'callWithSideEffects' calls `.sideEffect` 'myEcho' >>>> tdiagnostic_messages.nim(24, 6) Hint: 'myEcho' called by 'callWithSideEffects' >>> tdiagnostic_messages.nim(34, 3) Hint: 'callWithSideEffects' accesses global state 'globalVar' >>>> tdiagnostic_messages.nim(23, 5) Hint: 'globalVar' accessed by 'callWithSideEffects' diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim index 68bafa94df6d..caa8907c3062 100644 --- a/tests/effects/teffects1.nim +++ b/tests/effects/teffects1.nim @@ -17,7 +17,7 @@ proc forw: int {. .} proc lier(): int {.raises: [IO2Error].} = #[tt.Hint ^ 'lier' cannot raise 'IO2Error' [XCannotRaiseY] ]# writeLine stdout, "arg" #[tt.Error - ^ writeLine stdout, ["arg"] can raise an unlisted exception: ref IOError ]# + ^ writeLine stdout, ["arg"] can raise an unlisted exception: ref IOError ]# proc forw: int = raise newException(IOError, "arg") diff --git a/tests/errmsgs/tsigmatch2.nim b/tests/errmsgs/tsigmatch2.nim index 4996634c93e8..31c966337507 100644 --- a/tests/errmsgs/tsigmatch2.nim +++ b/tests/errmsgs/tsigmatch2.nim @@ -14,7 +14,7 @@ proc foo(i: Foo): string expression: foo(1.2) tsigmatch2.nim(40, 14) Error: expression '' has no type (or is ambiguous) -tsigmatch2.nim(46, 7) Error: type mismatch: got +tsigmatch2.nim(46, 3) Error: type mismatch: got but expected one of: proc foo(args: varargs[string, myproc]) first type mismatch at position: 1 @@ -44,4 +44,4 @@ block: let temp = 12.isNil proc foo(args: varargs[string, myproc]) = discard foo 1 -static: echo "done" \ No newline at end of file +static: echo "done" diff --git a/tests/parser/ttypeexprref.nim b/tests/parser/ttypeexprref.nim deleted file mode 100644 index 67716eeedda5..000000000000 --- a/tests/parser/ttypeexprref.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - errormsg: "invalid indentation" - line: 10 - column: 11 -""" - -type - A = (ref | ptr | pointer) - B = pointer | ptr | ref - C = ref | ptr | pointer diff --git a/tests/parser/ttypeexprs.nim b/tests/parser/ttypeexprs.nim index 4d6e94ef4cc0..a2614faf2b8d 100644 --- a/tests/parser/ttypeexprs.nim +++ b/tests/parser/ttypeexprs.nim @@ -8,3 +8,16 @@ type Double = ( elif n.sizeof == 2: uint32 else: uint16 ) + +type + A = (ref | ptr | pointer) + B = pointer | ptr | ref + C = ref | ptr | pointer + +template `+`(a, b): untyped = (b, a) +template `*`(a, b): untyped = (a, b) + +doAssert (ref int + ref float * ref string + ref bool) is + (ref bool, ((ref float, ref string), ref int)) +type X = ref int + ref float * ref string + ref bool +doAssert X is (ref bool, ((ref float, ref string), ref int)) diff --git a/tests/typerel/t7600_1.nim b/tests/typerel/t7600_1.nim index e9d01bd0d8bb..83f93ae7f049 100644 --- a/tests/typerel/t7600_1.nim +++ b/tests/typerel/t7600_1.nim @@ -1,6 +1,6 @@ discard """ errormsg: "type mismatch: got " -nimout: '''t7600_1.nim(21, 6) Error: type mismatch: got +nimout: '''t7600_1.nim(21, 1) Error: type mismatch: got but expected one of: proc test[T](x: Paper[T]) first type mismatch at position: 1 diff --git a/tests/typerel/t7600_2.nim b/tests/typerel/t7600_2.nim index 371707f4c509..9488a44bc460 100644 --- a/tests/typerel/t7600_2.nim +++ b/tests/typerel/t7600_2.nim @@ -1,6 +1,6 @@ discard """ errormsg: "type mismatch: got " -nimout: '''t7600_2.nim(20, 6) Error: type mismatch: got +nimout: '''t7600_2.nim(20, 1) Error: type mismatch: got but expected one of: proc test(x: Paper) first type mismatch at position: 1 diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim index fef75b339ff9..c9aeb94d8f81 100644 --- a/tests/varres/tprevent_forloopvar_mutations.nim +++ b/tests/varres/tprevent_forloopvar_mutations.nim @@ -1,6 +1,6 @@ discard """ errormsg: "type mismatch: got " - nimout: '''tprevent_forloopvar_mutations.nim(16, 7) Error: type mismatch: got + nimout: '''tprevent_forloopvar_mutations.nim(16, 3) Error: type mismatch: got but expected one of: proc inc[T, V: Ordinal](x: var T; y: V = 1) first type mismatch at position: 1 From b8b36994a0d0fe8242746cce6c917b74ea0da894 Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Fri, 14 Jan 2022 17:37:30 +0300 Subject: [PATCH 09/20] cleanup, fix some tests --- compiler/parser.nim | 45 +++++++++++++++--------------------- compiler/semtypes.nim | 2 +- doc/grammar.txt | 17 +++++++------- doc/manual.md | 13 ----------- lib/pure/options.nim | 4 ++-- tests/assert/tassert2.nim | 4 ++-- tests/parser/ttypeexprs.nim | 2 ++ tests/system/tvarargslen.nim | 6 ++--- 8 files changed, 37 insertions(+), 56 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index ea3c1304e64c..4189cc404adb 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -79,8 +79,7 @@ type smNormal, smAllowNil, smAfterDot PrimaryMode = enum - pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix, pmCommandStart, - pmTypeDescStart + pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix, pmCommandStart proc parseAll*(p: var Parser): PNode proc closeParser*(p: var Parser) @@ -288,7 +287,7 @@ proc newIdentNodeP(ident: PIdent, p: Parser): PNode = proc parseExpr(p: var Parser): PNode proc parseStmt(p: var Parser): PNode proc parseTypeDesc(p: var Parser, fullExpr = false): PNode -proc parseTypeDefAux(p: var Parser): PNode +proc parseTypeDefValue(p: var Parser): PNode proc parseParamList(p: var Parser, retColon = true): PNode proc isSigilLike(tok: Token): bool {.inline.} = @@ -927,8 +926,10 @@ proc parseOperators(p: var Parser, headNode: PNode, opPrec = getPrecedence(p.tok) proc simpleExprAux(p: var Parser, limit: int, mode: PrimaryMode): PNode = + var mode = mode result = primary(p, mode) - let mode = if mode == pmCommandStart: pmNormal else: mode + if mode == pmCommandStart: + mode = pmNormal if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)) and mode == pmNormal: var pragmaExp = newNodeP(nkPragmaExpr, p) @@ -1042,10 +1043,9 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode = result.add(newNodeP(nkEmpty, p)) proc parseTuple(p: var Parser, indentAllowed = false): PNode = - #| tupleType = 'tuple' - #| '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' + #| tupleType = 'tuple' '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' #| tupleDecl = tupleType | - #| ('tuple' COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?) + #| 'tuple' COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)? result = newNodeP(nkTupleTy, p) getTok(p) if p.tok.tokType == tkBracketLe: @@ -1180,7 +1180,7 @@ proc isExprStart(p: Parser): bool = of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkFor, tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics, tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCustomLit, tkVar, tkRef, tkPtr, - tkTuple, tkObject, tkWhen, tkCase, tkOut, tkTry, tkBlock: + tkEnum, tkTuple, tkObject, tkWhen, tkCase, tkOut, tkTry, tkBlock: result = true else: result = false @@ -1194,8 +1194,7 @@ proc parseSymbolList(p: var Parser, result: PNode) = getTok(p) optInd(p, s) -proc parseTypeDescKAux(p: var Parser, - kind: TNodeKind, +proc parseTypeDescKAux(p: var Parser, kind: TNodeKind, mode: PrimaryMode): PNode = result = newNodeP(kind, p) getTok(p) @@ -1204,7 +1203,7 @@ proc parseTypeDescKAux(p: var Parser, let isTypedef = mode == pmTypeDef and p.tok.tokType in {tkObject, tkTuple} if not isOperator(p.tok) and isExprStart(p): if isTypedef: - result.add(parseTypeDefAux(p)) + result.add(parseTypeDefValue(p)) else: result.add(primary(p, mode)) if kind == nkDistinctTy and p.tok.tokType == tkSymbol: @@ -1226,7 +1225,7 @@ proc parseTypeDescKAux(p: var Parser, proc parseVarTuple(p: var Parser): PNode proc parseFor(p: var Parser): PNode = - #| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt + #| forStmt = 'for' ((varTuple / identWithPragma) ^+ comma) 'in' expr colcom stmt #| forExpr = forStmt getTokNoInd(p) result = newNodeP(nkForStmt, p) @@ -1387,19 +1386,13 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode = result = simpleExpr(p, pmTypeDesc) result = binaryNot(p, result) -proc parseTypeDefAux(p: var Parser): PNode = - #| typeDefAux = ((tupleDecl | routineType | - #| ('ref' | 'ptr' | 'distinct') typeDefAux? | - #| enumDecl | objectDecl | conceptDecl) ('not' expr)?) - #| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)? ('not' expr)?) +proc parseTypeDefValue(p: var Parser): PNode = + #| typeDefValue = ((tupleDecl | enumDecl | objectDecl | conceptDecl | + #| ('ref' | 'ptr' | 'distinct') (tupleDecl | objectDecl)) + #| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?)) + #| ('not' expr)? case p.tok.tokType - of tkTuple: - result = parseTuple(p, true) - of tkProc: result = parseProcExpr(p, false, nkLambda) - of tkIterator: - result = parseProcExpr(p, false, nkLambda) - if result.kind == nkLambda: result.transitionSonsKind(nkIteratorDef) - else: result.transitionSonsKind(nkIteratorTy) + of tkTuple: result = parseTuple(p, true) of tkRef: result = parseTypeDescKAux(p, nkRefTy, pmTypeDef) of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, pmTypeDef) of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDef) @@ -2175,7 +2168,7 @@ proc parseTypeClass(p: var Parser): PNode = proc parseTypeDef(p: var Parser): PNode = #| - #| typeDef = identVisDot genericParamList? pragma '=' optInd typeDefAux + #| typeDef = identVisDot genericParamList? pragma '=' optInd typeDefValue #| indAndComment? result = newNodeP(nkTypeDef, p) var identifier = identVis(p, allowDot=true) @@ -2201,7 +2194,7 @@ proc parseTypeDef(p: var Parser): PNode = result.info = parLineInfo(p) getTok(p) optInd(p, result) - result.add(parseTypeDefAux(p)) + result.add(parseTypeDefValue(p)) else: result.add(p.emptyNode) indAndComment(p, result) # special extension! diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 2d2de9aeb081..9577c8e7a294 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -2054,7 +2054,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkEnumTy: result = semEnum(c, n, prev) of nkType: result = n.typ of nkStmtListType, nkStmtList: result = semStmtListType(c, n, prev) - of nkBlockType: result = semBlockType(c, n, prev) + of nkBlockType, nkBlockStmt, nkBlockExpr: result = semBlockType(c, n, prev) else: result = semTypeExpr(c, n, prev) when false: diff --git a/doc/grammar.txt b/doc/grammar.txt index a2c6a090edd6..ab76448b6041 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -71,17 +71,16 @@ declColonEquals = identWithPragma (comma identWithPragma)* comma? (':' optInd typeDescExpr)? ('=' optInd expr)? identColonEquals = IDENT (comma IDENT)* comma? (':' optInd typeDescExpr)? ('=' optInd expr)?) -tupleType = 'tuple' - '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' +tupleType = 'tuple' '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' tupleDecl = tupleType | - ('tuple' COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?) + 'tuple' COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)? paramList = '(' declColonEquals ^* (comma/semicolon) ')' paramListArrow = paramList? ('->' optInd typeDesc)? paramListColon = paramList? (':' optInd typeDesc)? doBlock = 'do' paramListArrow pragma? colcom stmt routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)? routineType = ('proc' | 'iterator') paramListColon pragma? -forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt +forStmt = 'for' ((varTuple / identWithPragma) ^+ comma) 'in' expr colcom stmt forExpr = forStmt expr = (blockExpr | ifExpr @@ -100,10 +99,10 @@ rawTypeDesc = (tupleType | routineType | 'enum' | 'object' | ('not' expr)? typeDescExpr = simpleExpr ('not' expr)? typeDesc = rawTypeDesc / typeDescExpr -typeDefAux = ((tupleDecl | routineType | - ('ref' | 'ptr' | 'distinct') typeDefAux? | - enumDecl | objectDecl | conceptDecl) ('not' expr)?) - / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)? ('not' expr)?) +typeDefValue = ((tupleDecl | enumDecl | objectDecl | conceptDecl | + ('ref' | 'ptr' | 'distinct') (tupleDecl | objectDecl)) + / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?)) + ('not' expr)? postExprBlocks = ':' stmt? ( IND{=} doBlock | IND{=} 'of' exprList ':' stmt | IND{=} 'elif' expr ':' stmt @@ -184,7 +183,7 @@ objectDecl = 'object' ('of' typeDesc)? COMMENT? objectPart conceptParam = ('var' | 'out')? symbol conceptDecl = 'concept' conceptParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? &IND{>} stmt -typeDef = identVisDot genericParamList? pragma '=' optInd typeDefAux +typeDef = identVisDot genericParamList? pragma '=' optInd typeDefValue indAndComment? varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr colonBody = colcom stmt postExprBlocks? diff --git a/doc/manual.md b/doc/manual.md index 4d1dccf3934a..378aaed905b7 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -2084,19 +2084,6 @@ This feature is useful if an object should only gain reference semantics: data: int ``` -.. - (This part was true earlier in the PR but is not true anymore) - As a consequence of this syntax, normal expressions starting with `ref` - or `ptr` must be wrapped in parentheses or some other expression form - to be used directly in type sections. - - .. code-block:: nim - type - # invalid - IntRef = ref int | ptr int - # correct - IntRef = (ref int | ptr int) - To allocate a new traced object, the built-in procedure `new` has to be used. To deal with untraced memory, the procedures `alloc`, `dealloc` and diff --git a/lib/pure/options.nim b/lib/pure/options.nim index f7cd1e7fbf34..9dc4e096b33b 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -81,10 +81,10 @@ when defined(nimPreviewSlimSystem): when (NimMajor, NimMinor) >= (1, 1): type - SomePointer = (ref | ptr | pointer | proc) + SomePointer = ref | ptr | pointer | proc else: type - SomePointer = (ref | ptr | pointer) + SomePointer = ref | ptr | pointer type Option*[T] = object diff --git a/tests/assert/tassert2.nim b/tests/assert/tassert2.nim index 05e19cfcf957..e32ab72e1e74 100644 --- a/tests/assert/tassert2.nim +++ b/tests/assert/tassert2.nim @@ -100,7 +100,7 @@ block: ## checks for issue https://github.com/nim-lang/Nim/issues/9301 doAssert 1 + 1 == 3 except AssertionDefect as e: # used to const fold as false - assert e.msg.endsWith "tassert2.nim(100, 14) `1 + 1 == 3` " + assert e.msg.endsWith "tassert2.nim(100, 5) `1 + 1 == 3` " block: ## checks AST isn't transformed as it used to let a = 1 @@ -108,4 +108,4 @@ block: ## checks AST isn't transformed as it used to doAssert a > 1 except AssertionDefect as e: # used to rewrite as `1 < a` - assert e.msg.endsWith "tassert2.nim(108, 14) `a > 1` " + assert e.msg.endsWith "tassert2.nim(108, 5) `a > 1` " diff --git a/tests/parser/ttypeexprs.nim b/tests/parser/ttypeexprs.nim index a2614faf2b8d..e40efc7d9f59 100644 --- a/tests/parser/ttypeexprs.nim +++ b/tests/parser/ttypeexprs.nim @@ -21,3 +21,5 @@ doAssert (ref int + ref float * ref string + ref bool) is (ref bool, ((ref float, ref string), ref int)) type X = ref int + ref float * ref string + ref bool doAssert X is (ref bool, ((ref float, ref string), ref int)) + +type SomePointer = proc | ref | ptr | pointer diff --git a/tests/system/tvarargslen.nim b/tests/system/tvarargslen.nim index a129aa5c2f23..24b54a1e0e44 100644 --- a/tests/system/tvarargslen.nim +++ b/tests/system/tvarargslen.nim @@ -1,8 +1,8 @@ discard """ output: ''' -tvarargslen.nim:35:9 (1, 2) -tvarargslen.nim:36:9 12 -tvarargslen.nim:37:9 1 +tvarargslen.nim:35:2 (1, 2) +tvarargslen.nim:36:2 12 +tvarargslen.nim:37:2 1 tvarargslen.nim:38:8 done ''' From 4ce30e7fb92acac267c0c19eee898f03d56a5745 Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Tue, 18 Jan 2022 13:00:27 +0300 Subject: [PATCH 10/20] improve grammar, try and revert semtypes change --- compiler/parser.nim | 8 ++++---- compiler/semtypes.nim | 4 ++-- doc/grammar.txt | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 4189cc404adb..34b9ea4a6b2a 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1316,13 +1316,13 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode = case p.tok.tokType of tkProc: getTok(p) - result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda) + result = parseProcExpr(p, mode != pmTypeDesc, nkLambda) of tkFunc: getTok(p) - result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkFuncDef) + result = parseProcExpr(p, mode != pmTypeDesc, nkFuncDef) of tkIterator: getTok(p) - result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkIteratorDef) + result = parseProcExpr(p, mode != pmTypeDesc, nkIteratorDef) of tkBind: result = newNodeP(nkBind, p) getTok(p) @@ -1354,7 +1354,7 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode = #| rawTypeDesc = (tupleType | routineType | 'enum' | 'object' | #| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?) #| ('not' expr)? - #| typeDescExpr = simpleExpr ('not' expr)? + #| typeDescExpr = (routineType / simpleExpr) ('not' expr)? #| typeDesc = rawTypeDesc / typeDescExpr newlineWasSplitting(p) if fullExpr: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 9577c8e7a294..945d22ab7e3e 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -2053,8 +2053,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = semProcTypeWithScope(c, n, prev, skProc) of nkEnumTy: result = semEnum(c, n, prev) of nkType: result = n.typ - of nkStmtListType, nkStmtList: result = semStmtListType(c, n, prev) - of nkBlockType, nkBlockStmt, nkBlockExpr: result = semBlockType(c, n, prev) + of nkStmtListType: result = semStmtListType(c, n, prev) + of nkBlockType: result = semBlockType(c, n, prev) else: result = semTypeExpr(c, n, prev) when false: diff --git a/doc/grammar.txt b/doc/grammar.txt index ab76448b6041..36c3149f95f1 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -97,7 +97,7 @@ primary = operatorB primary primarySuffix* | rawTypeDesc = (tupleType | routineType | 'enum' | 'object' | ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?) ('not' expr)? -typeDescExpr = simpleExpr ('not' expr)? +typeDescExpr = (routineType / simpleExpr) ('not' expr)? typeDesc = rawTypeDesc / typeDescExpr typeDefValue = ((tupleDecl | enumDecl | objectDecl | conceptDecl | ('ref' | 'ptr' | 'distinct') (tupleDecl | objectDecl)) From fa79ec53340abdcf62b3ffe1a47d86d1e391f22b Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Thu, 20 Jan 2022 15:57:31 +0300 Subject: [PATCH 11/20] restrict sigil binding to identOrLiteral --- compiler/parser.nim | 72 ++++++++++++++++++++++++--------------------- doc/grammar.txt | 22 +++++++------- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 34b9ea4a6b2a..31dee26be992 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -79,7 +79,7 @@ type smNormal, smAllowNil, smAfterDot PrimaryMode = enum - pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix, pmCommandStart + pmNormal, pmTypeDesc, pmTypeDef, pmTrySimple proc parseAll*(p: var Parser): PNode proc closeParser*(p: var Parser) @@ -824,12 +824,15 @@ proc commandParam(p: var Parser, isFirstParam: var bool; mode: PrimaryMode): PNo isFirstParam = false proc commandExpr(p: var Parser; r: PNode; mode: PrimaryMode): PNode = - result = newNodeP(nkCommand, p) - result.add(r) - var isFirstParam = true - # progress NOT guaranteed - p.hasProgress = false - result.add commandParam(p, isFirstParam, mode) + if mode == pmTrySimple: + result = r + else: + result = newNodeP(nkCommand, p) + result.add(r) + var isFirstParam = true + # progress NOT guaranteed + p.hasProgress = false + result.add commandParam(p, isFirstParam, mode) proc isDotLike(tok: Token): bool = result = tok.tokType == tkOpr and tok.ident.s.len > 1 and @@ -842,7 +845,7 @@ proc primarySuffix(p: var Parser, r: PNode, #| | DOTLIKEOP optInd symbol generalizedLit? #| | '[' optInd exprColonEqExprList optPar ']' #| | '{' optInd exprColonEqExprList optPar '}' - #| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr (comma expr)* # command syntax + # XXX strong spaces need to be reflected above result = r # progress guaranteed @@ -852,8 +855,7 @@ proc primarySuffix(p: var Parser, r: PNode, of tkParLe: # progress guaranteed if p.tok.strongSpaceA: - if mode != pmCommandStart: - result = commandExpr(p, result, mode) + result = commandExpr(p, result, mode) break result = namedParams(p, result, nkCall, tkParRi) if result.len > 1 and result[1].kind == nkExprColonExpr: @@ -865,15 +867,13 @@ proc primarySuffix(p: var Parser, r: PNode, of tkBracketLe: # progress guaranteed if p.tok.strongSpaceA: - if mode != pmCommandStart: - result = commandExpr(p, result, mode) + result = commandExpr(p, result, mode) break result = namedParams(p, result, nkBracketExpr, tkBracketRi) of tkCurlyLe: # progress guaranteed if p.tok.strongSpaceA: - if mode != pmCommandStart: - result = commandExpr(p, result, mode) + result = commandExpr(p, result, mode) break result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) of tkSymbol, tkAccent, tkIntLit..tkCustomLit, tkNil, tkCast, @@ -892,8 +892,7 @@ proc primarySuffix(p: var Parser, r: PNode, else: if isDotLike2: parMessage(p, warnDotLikeOps, "dot-like operators will be parsed differently with `-d:nimPreviewDotLikeOps`") - if mode != pmCommandStart and - p.inPragma == 0 and (isUnary(p.tok) or p.tok.tokType notin {tkOpr, tkDotDot}): + if p.inPragma == 0 and (isUnary(p.tok) or p.tok.tokType notin {tkOpr, tkDotDot}): # 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) @@ -928,7 +927,7 @@ proc parseOperators(p: var Parser, headNode: PNode, proc simpleExprAux(p: var Parser, limit: int, mode: PrimaryMode): PNode = var mode = mode result = primary(p, mode) - if mode == pmCommandStart: + if mode == pmTrySimple: mode = pmNormal if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)) and mode == pmNormal: @@ -1290,11 +1289,17 @@ proc parseObject(p: var Parser): PNode proc parseTypeClass(p: var Parser): PNode proc primary(p: var Parser, mode: PrimaryMode): PNode = - #| primary = operatorB primary primarySuffix* | - #| routineExpr | - #| 'bind' primary | - #| rawTypeDesc - #| / prefixOperator* identOrLiteral primarySuffix* + #| simplePrimary = SIGILLIKEOP? identOrLiteral primarySuffix* + #| commandStart = &('`'|IDENT|literal|'cast'|'addr'|'type'|'var'|'out'| + #| 'static'|'enum'|'tuple'|'object'|'proc') + #| primary = simplePrimary (commandStart expr)* + #| / operatorB primary + #| / routineExpr + #| / rawTypeDesc + #| / prefixOperator primary + # XXX strong spaces need to be reflected in commandStart + + # prefix operators: if isOperator(p.tok): # Note 'sigil like' operators are currently not reflected in the grammar # and should be removed for Nim 2.0, I don't think anybody uses them. @@ -1304,10 +1309,11 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode = result.add(a) getTok(p) optInd(p, a) - if isSigil: - #XXX prefix operators + const identOrLiteralKinds = tkBuiltInMagics + + {tkSymbol, tkAccent, tkNil, tkIntLit..tkCustomLit, tkCast, tkOut} + if isSigil and p.tok.tokType in identOrLiteralKinds: let baseInd = p.lex.currLineIndent - result.add(primary(p, pmSkipSuffix)) + result.add(identOrLiteral(p, mode)) result = primarySuffix(p, result, baseInd, mode) else: result.add(primary(p, pmNormal)) @@ -1324,6 +1330,7 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode = getTok(p) result = parseProcExpr(p, mode != pmTypeDesc, nkIteratorDef) of tkBind: + # legacy syntax, no-op in current nim result = newNodeP(nkBind, p) getTok(p) optInd(p, result) @@ -1334,8 +1341,7 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode = else: let baseInd = p.lex.currLineIndent result = identOrLiteral(p, mode) - if mode != pmSkipSuffix: - result = primarySuffix(p, result, baseInd, mode) + result = primarySuffix(p, result, baseInd, mode) proc binaryNot(p: var Parser; a: PNode): PNode = if p.tok.tokType == tkNot: @@ -1508,12 +1514,10 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode = parMessage(p, "expected ':'") proc parseExprStmt(p: var Parser): PNode = - #| exprStmt = simpleExpr - #| (( '=' optInd expr colonBody? ) - #| / ( exprEqExpr ^+ comma - #| postExprBlocks - #| ))? - var a = simpleExpr(p, pmCommandStart) + #| exprStmt = simpleExpr postExprBlocks? + #| / simplePrimary (exprEqExpr ^+ comma) postExprBlocks? + #| / simpleExpr '=' optInd (expr postExprBlocks?) + var a = simpleExpr(p, pmTrySimple) if p.tok.tokType == tkEquals: result = newNodeP(nkAsgn, p) getTok(p) @@ -1524,6 +1528,8 @@ proc parseExprStmt(p: var Parser): PNode = result.add(b) else: var isFirstParam = false + # if an expression is starting here, a simplePrimary was parsed and + # this is the start of a command if p.tok.indent < 0 and isExprStart(p): result = newTreeI(nkCommand, a.info, a) let baseIndent = p.currInd diff --git a/doc/grammar.txt b/doc/grammar.txt index 36c3149f95f1..7bf11dd2fda1 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -61,7 +61,6 @@ primarySuffix = '(' (exprColonEqExpr comma?)* ')' | DOTLIKEOP optInd symbol generalizedLit? | '[' optInd exprColonEqExprList optPar ']' | '{' optInd exprColonEqExprList optPar '}' - | &( '`'|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? @@ -89,11 +88,14 @@ expr = (blockExpr | forExpr | tryExpr) / simpleExpr -primary = operatorB primary primarySuffix* | - routineExpr | - 'bind' primary | - rawTypeDesc - / prefixOperator* identOrLiteral primarySuffix* +simplePrimary = SIGILLIKEOP? identOrLiteral primarySuffix* +commandStart = &('`'|IDENT|literal|'cast'|'addr'|'type'|'var'|'out'| + 'static'|'enum'|'tuple'|'object'|'proc') +primary = simplePrimary (commandStart expr)* + / operatorB primary + / routineExpr + / rawTypeDesc + / prefixOperator primary rawTypeDesc = (tupleType | routineType | 'enum' | 'object' | ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?) ('not' expr)? @@ -109,11 +111,9 @@ postExprBlocks = ':' stmt? ( IND{=} doBlock | IND{=} 'except' exprList ':' stmt | IND{=} 'finally' ':' stmt | IND{=} 'else' ':' stmt )* -exprStmt = simpleExpr - (( '=' optInd expr colonBody? ) - / ( exprEqExpr ^+ comma - postExprBlocks - ))? +exprStmt = simpleExpr postExprBlocks? + / simplePrimary (exprEqExpr ^+ comma) postExprBlocks? + / simpleExpr '=' optInd (expr postExprBlocks?) importStmt = 'import' optInd expr ((comma expr)* / 'except' optInd (expr ^+ comma)) From 4d52b366bac82883922d43424b0853f2c55550ac Mon Sep 17 00:00:00 2001 From: hlaaftana Date: Thu, 20 Jan 2022 17:47:41 +0300 Subject: [PATCH 12/20] fix, should have caught this immediately --- compiler/parser.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 31dee26be992..eb89d04ef50e 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1309,8 +1309,8 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode = result.add(a) getTok(p) optInd(p, a) - const identOrLiteralKinds = tkBuiltInMagics + - {tkSymbol, tkAccent, tkNil, tkIntLit..tkCustomLit, tkCast, tkOut} + const identOrLiteralKinds = tkBuiltInMagics + {tkSymbol, tkAccent, tkNil, + tkIntLit..tkCustomLit, tkCast, tkOut, tkParLe, tkBracketLe, tkCurlyLe} if isSigil and p.tok.tokType in identOrLiteralKinds: let baseInd = p.lex.currLineIndent result.add(identOrLiteral(p, mode)) From 74c256241d6318037302beb05e798b3a93563233 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+metagn@users.noreply.github.com> Date: Wed, 20 Jul 2022 12:41:43 +0300 Subject: [PATCH 13/20] add changelog entry, fix double not nil bug --- changelog.md | 4 ++++ compiler/parser.nim | 4 +--- tests/parser/tdoublenotnil.nim | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 tests/parser/tdoublenotnil.nim diff --git a/changelog.md b/changelog.md index 9ebc3bdaaec6..072ff151cee8 100644 --- a/changelog.md +++ b/changelog.md @@ -246,6 +246,10 @@ - Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters). - Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`. +- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent + with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`. + This decision was made with the assumption that the old syntax was used rarely; + if your code used the old syntax, please be aware of this change. ## Compiler changes diff --git a/compiler/parser.nim b/compiler/parser.nim index eb89d04ef50e..139ff44e31f7 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1412,9 +1412,7 @@ proc parseTypeDefValue(p: var Parser): PNode = result = parseTypeClass(p) else: result = simpleExpr(p, pmTypeDef) - if p.tok.tokType == tkNot: - result = binaryNot(p, result) - else: + if p.tok.tokType != tkNot: if result.kind == nkCommand: var isFirstParam = false while p.tok.tokType == tkComma: diff --git a/tests/parser/tdoublenotnil.nim b/tests/parser/tdoublenotnil.nim new file mode 100644 index 000000000000..c61008c548c8 --- /dev/null +++ b/tests/parser/tdoublenotnil.nim @@ -0,0 +1,3 @@ +when false: + type Foo = Bar not nil not nil #[tt.Error + ^ invalid indentation]# From 511b5d96e658196551d58f436b627dbbaa66a5c6 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+metagn@users.noreply.github.com> Date: Wed, 7 Sep 2022 20:41:01 +0300 Subject: [PATCH 14/20] correct grammar --- compiler/parser.nim | 3 ++- doc/grammar.txt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 139ff44e31f7..384dc1fb1a6d 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1292,12 +1292,13 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode = #| simplePrimary = SIGILLIKEOP? identOrLiteral primarySuffix* #| commandStart = &('`'|IDENT|literal|'cast'|'addr'|'type'|'var'|'out'| #| 'static'|'enum'|'tuple'|'object'|'proc') - #| primary = simplePrimary (commandStart expr)* + #| primary = simplePrimary (commandStart expr) #| / operatorB primary #| / routineExpr #| / rawTypeDesc #| / prefixOperator primary # XXX strong spaces need to be reflected in commandStart + # command part is handled in the primarySuffix proc # prefix operators: if isOperator(p.tok): diff --git a/doc/grammar.txt b/doc/grammar.txt index 7bf11dd2fda1..a9e80faabbf5 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -91,7 +91,7 @@ expr = (blockExpr simplePrimary = SIGILLIKEOP? identOrLiteral primarySuffix* commandStart = &('`'|IDENT|literal|'cast'|'addr'|'type'|'var'|'out'| 'static'|'enum'|'tuple'|'object'|'proc') -primary = simplePrimary (commandStart expr)* +primary = simplePrimary (commandStart expr) / operatorB primary / routineExpr / rawTypeDesc From a3759567416fdb32ee8c600ec864c45c4ba2913f Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Fri, 2 Dec 2022 11:29:36 +0300 Subject: [PATCH 15/20] change section --- changelog.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 072ff151cee8..680fd8a35793 100644 --- a/changelog.md +++ b/changelog.md @@ -80,6 +80,11 @@ - Removed two type pragma syntaxes deprecated since 0.20, namely `type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`. +- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent + with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`. + This decision was made with the assumption that the old syntax was used rarely; + if your code used the old syntax, please be aware of this change. + - [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators are no longer experimental. @@ -246,10 +251,6 @@ - Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters). - Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`. -- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent - with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`. - This decision was made with the assumption that the old syntax was used rarely; - if your code used the old syntax, please be aware of this change. ## Compiler changes From b1b90465f70a510e38596ddad10c9dca0323e020 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Fri, 2 Dec 2022 12:21:48 +0300 Subject: [PATCH 16/20] fix --- compiler/parser.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 384dc1fb1a6d..332335dc3389 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1323,13 +1323,13 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode = case p.tok.tokType of tkProc: getTok(p) - result = parseProcExpr(p, mode != pmTypeDesc, nkLambda) + result = parseProcExpr(p, true, nkLambda) of tkFunc: getTok(p) - result = parseProcExpr(p, mode != pmTypeDesc, nkFuncDef) + result = parseProcExpr(p, true, nkFuncDef) of tkIterator: getTok(p) - result = parseProcExpr(p, mode != pmTypeDesc, nkIteratorDef) + result = parseProcExpr(p, true, nkIteratorDef) of tkBind: # legacy syntax, no-op in current nim result = newNodeP(nkBind, p) @@ -1371,11 +1371,11 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode = of tkTuple: result = parseTuple(p, false) of tkProc: + getTok(p) result = parseProcExpr(p, false, nkLambda) of tkIterator: - result = parseProcExpr(p, false, nkLambda) - if result.kind == nkLambda: result.transitionSonsKind(nkIteratorDef) - else: result.transitionSonsKind(nkIteratorTy) + getTok(p) + result = parseProcExpr(p, false, nkIteratorDef) of tkEnum: result = newNodeP(nkEnumTy, p) getTok(p) From 042e1c673dbf05ed924251e66e1aa549cff132ac Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Fri, 2 Dec 2022 12:32:09 +0300 Subject: [PATCH 17/20] real fix hopefully --- compiler/parser.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 332335dc3389..2cf905bbcf72 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1323,13 +1323,13 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode = case p.tok.tokType of tkProc: getTok(p) - result = parseProcExpr(p, true, nkLambda) + result = parseProcExpr(p, mode != pmTypeDesc, nkLambda) of tkFunc: getTok(p) - result = parseProcExpr(p, true, nkFuncDef) + result = parseProcExpr(p, mode != pmTypeDesc, nkFuncDef) of tkIterator: getTok(p) - result = parseProcExpr(p, true, nkIteratorDef) + result = parseProcExpr(p, mode != pmTypeDesc, nkIteratorDef) of tkBind: # legacy syntax, no-op in current nim result = newNodeP(nkBind, p) From b7607536d11db9abd3940dc22fdb2b45559df945 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Fri, 2 Dec 2022 13:29:46 +0300 Subject: [PATCH 18/20] fix test --- tests/errmsgs/t9768.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/errmsgs/t9768.nim b/tests/errmsgs/t9768.nim index 94def90f0726..058d297b3584 100644 --- a/tests/errmsgs/t9768.nim +++ b/tests/errmsgs/t9768.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "unhandled exception: t9768.nim(24, 12) `a < 4` [AssertionDefect]" + errormsg: "unhandled exception: t9768.nim(24, 3) `a < 4` [AssertionDefect]" file: "std/assertions.nim" nimout: ''' stack trace: (most recent call last) From c93c1569ea1a5073276ae0fd14237047ac2d9ea0 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Tue, 6 Dec 2022 12:06:30 +0300 Subject: [PATCH 19/20] support LL(1) for tuples --- compiler/parser.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 2cf905bbcf72..0199c10afc20 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1042,9 +1042,10 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode = result.add(newNodeP(nkEmpty, p)) proc parseTuple(p: var Parser, indentAllowed = false): PNode = - #| tupleType = 'tuple' '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' - #| tupleDecl = tupleType | - #| 'tuple' COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)? + #| tupleTypeBracket = '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' + #| tupleType = 'tuple' tupleTypeBracket + #| tupleDecl = 'tuple' (tupleTypeBracket / + #| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?) result = newNodeP(nkTupleTy, p) getTok(p) if p.tok.tokType == tkBracketLe: From 7f1c4e3a354c5a34ca8bbccd779bfb36bff32f63 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Tue, 6 Dec 2022 12:08:47 +0300 Subject: [PATCH 20/20] make grammar.txt too --- doc/grammar.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/grammar.txt b/doc/grammar.txt index a9e80faabbf5..a0ff7d9f0ad6 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -70,9 +70,10 @@ declColonEquals = identWithPragma (comma identWithPragma)* comma? (':' optInd typeDescExpr)? ('=' optInd expr)? identColonEquals = IDENT (comma IDENT)* comma? (':' optInd typeDescExpr)? ('=' optInd expr)?) -tupleType = 'tuple' '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' -tupleDecl = tupleType | - 'tuple' COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)? +tupleTypeBracket = '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' +tupleType = 'tuple' tupleTypeBracket +tupleDecl = 'tuple' (tupleTypeBracket / + COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?) paramList = '(' declColonEquals ^* (comma/semicolon) ')' paramListArrow = paramList? ('->' optInd typeDesc)? paramListColon = paramList? (':' optInd typeDesc)?