mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-08 14:03:23 +00:00
Named arguments in commands + many grammar fixes (#20994)
* Breaking parser changes, implement https://github.com/nim-lang/RFCs/issues/442 Types are separated from expressions and better reflected in the grammar. * add test * more accurate grammar * fix keyword typedescs * accept expressions in proc argument lists * CI "fixes" * fixes * allow full ref expressions again, adapt old tests * cleanup, fix some tests * improve grammar, try and revert semtypes change * restrict sigil binding to identOrLiteral * fix, should have caught this immediately * add changelog entry, fix double not nil bug * correct grammar * change section * fix * real fix hopefully * fix test * support LL(1) for tuples * make grammar.txt too
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ type
|
||||
smNormal, smAllowNil, smAfterDot
|
||||
|
||||
PrimaryMode = enum
|
||||
pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
|
||||
pmNormal, pmTypeDesc, pmTypeDef, pmTrySimple
|
||||
|
||||
proc parseAll*(p: var Parser): PNode
|
||||
proc closeParser*(p: var Parser)
|
||||
@@ -286,7 +286,8 @@ 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 parseTypeDefValue(p: var Parser): PNode
|
||||
proc parseParamList(p: var Parser, retColon = true): PNode
|
||||
|
||||
proc isSigilLike(tok: Token): bool {.inline.} =
|
||||
@@ -406,15 +407,8 @@ 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)
|
||||
getTok(p)
|
||||
newlineWasSplitting(p)
|
||||
#optInd(p, result)
|
||||
result.add(a)
|
||||
result.add(parseExpr(p))
|
||||
elif p.tok.tokType == tkEquals:
|
||||
proc equals(p: var Parser, a: PNode): PNode =
|
||||
if p.tok.tokType == tkEquals:
|
||||
result = newNodeP(nkExprEqExpr, p)
|
||||
getTok(p)
|
||||
#optInd(p, result)
|
||||
@@ -423,6 +417,17 @@ proc colonOrEquals(p: var Parser, a: PNode): PNode =
|
||||
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 = equals(p, a)
|
||||
|
||||
proc exprColonEqExpr(p: var Parser): PNode =
|
||||
#| exprColonEqExpr = expr (':'|'=' expr)?
|
||||
var a = parseExpr(p)
|
||||
@@ -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,25 +815,24 @@ 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 =
|
||||
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
|
||||
@@ -833,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
|
||||
@@ -844,13 +856,6 @@ proc primarySuffix(p: var Parser, r: PNode,
|
||||
# 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))
|
||||
break
|
||||
result = namedParams(p, result, nkCall, tkParRi)
|
||||
if result.len > 1 and result[1].kind == nkExprColonExpr:
|
||||
@@ -891,18 +896,9 @@ 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 =
|
||||
@@ -929,7 +925,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)
|
||||
if mode == pmTrySimple:
|
||||
mode = pmNormal
|
||||
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)) and
|
||||
mode == pmNormal:
|
||||
var pragmaExp = newNodeP(nkPragmaExpr, p)
|
||||
@@ -1010,9 +1009,9 @@ type
|
||||
|
||||
proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode =
|
||||
#| 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)?)
|
||||
var a: PNode
|
||||
result = newNodeP(nkIdentDefs, p)
|
||||
# progress guaranteed
|
||||
@@ -1030,7 +1029,7 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode =
|
||||
if p.tok.tokType == tkColon:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(parseTypeDesc(p))
|
||||
result.add(parseTypeDesc(p, fullExpr = true))
|
||||
else:
|
||||
result.add(newNodeP(nkEmpty, p))
|
||||
if p.tok.tokType != tkEquals and withBothOptional notin flags:
|
||||
@@ -1043,9 +1042,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)*)?
|
||||
#| 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:
|
||||
@@ -1155,6 +1155,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
|
||||
@@ -1179,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
|
||||
|
||||
@@ -1199,8 +1200,12 @@ proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
|
||||
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):
|
||||
result.add(primary(p, mode))
|
||||
if isTypedef:
|
||||
result.add(parseTypeDefValue(p))
|
||||
else:
|
||||
result.add(primary(p, mode))
|
||||
if kind == nkDistinctTy and p.tok.tokType == tkSymbol:
|
||||
# XXX document this feature!
|
||||
var nodeKind: TNodeKind
|
||||
@@ -1214,11 +1219,13 @@ proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
|
||||
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
|
||||
|
||||
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)
|
||||
@@ -1283,11 +1290,18 @@ proc parseObject(p: var Parser): PNode
|
||||
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
|
||||
#| / 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
|
||||
# command part is handled in the primarySuffix proc
|
||||
|
||||
# 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.
|
||||
@@ -1297,60 +1311,39 @@ 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, tkParLe, tkBracketLe, tkCurlyLe}
|
||||
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))
|
||||
return
|
||||
|
||||
case p.tok.tokType
|
||||
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
|
||||
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)
|
||||
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")
|
||||
result = parseProcExpr(p, mode != pmTypeDesc, nkIteratorDef)
|
||||
of tkBind:
|
||||
# legacy syntax, no-op in current nim
|
||||
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)
|
||||
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:
|
||||
@@ -1365,16 +1358,70 @@ proc binaryNot(p: var Parser; a: PNode): PNode =
|
||||
else:
|
||||
result = a
|
||||
|
||||
proc parseTypeDesc(p: var Parser): PNode =
|
||||
#| typeDesc = simpleExpr ('not' expr)?
|
||||
proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
|
||||
#| rawTypeDesc = (tupleType | routineType | 'enum' | 'object' |
|
||||
#| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?)
|
||||
#| ('not' expr)?
|
||||
#| typeDescExpr = (routineType / simpleExpr) ('not' expr)?
|
||||
#| typeDesc = rawTypeDesc / typeDescExpr
|
||||
newlineWasSplitting(p)
|
||||
result = simpleExpr(p, pmTypeDesc)
|
||||
if fullExpr:
|
||||
result = simpleExpr(p, pmTypeDesc)
|
||||
else:
|
||||
case p.tok.tokType
|
||||
of tkTuple:
|
||||
result = parseTuple(p, false)
|
||||
of tkProc:
|
||||
getTok(p)
|
||||
result = parseProcExpr(p, false, nkLambda)
|
||||
of tkIterator:
|
||||
getTok(p)
|
||||
result = parseProcExpr(p, false, nkIteratorDef)
|
||||
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)
|
||||
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 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)
|
||||
of tkObject:
|
||||
prettySection:
|
||||
result = parseObject(p)
|
||||
of tkConcept:
|
||||
result = parseTypeClass(p)
|
||||
else:
|
||||
result = simpleExpr(p, pmTypeDef)
|
||||
if p.tok.tokType != tkNot:
|
||||
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 =
|
||||
@@ -1467,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? )
|
||||
#| / ( expr ^+ comma
|
||||
#| postExprBlocks
|
||||
#| ))?
|
||||
var a = simpleExpr(p)
|
||||
#| 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)
|
||||
@@ -1482,20 +1527,17 @@ 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 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
|
||||
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:
|
||||
@@ -2132,7 +2174,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)
|
||||
@@ -2158,7 +2200,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!
|
||||
|
||||
@@ -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)?
|
||||
@@ -60,25 +61,26 @@ 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?
|
||||
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)?)
|
||||
tupleDecl = 'tuple'
|
||||
'[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' |
|
||||
COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
||||
(':' optInd typeDescExpr)? ('=' optInd expr)?)
|
||||
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)?
|
||||
doBlock = 'do' paramListArrow pragma? colcom stmt
|
||||
routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)?
|
||||
forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
|
||||
routineType = ('proc' | 'iterator') paramListColon pragma?
|
||||
forStmt = 'for' ((varTuple / identWithPragma) ^+ comma) 'in' expr colcom stmt
|
||||
forExpr = forStmt
|
||||
expr = (blockExpr
|
||||
| ifExpr
|
||||
@@ -87,25 +89,32 @@ expr = (blockExpr
|
||||
| forExpr
|
||||
| tryExpr)
|
||||
/ simpleExpr
|
||||
primary = operatorB primary primarySuffix* |
|
||||
tupleDecl | routineExpr | enumDecl
|
||||
objectDecl | conceptDecl | ('bind' primary)
|
||||
('var' | 'out' | 'ref' | 'ptr' | 'distinct') primary
|
||||
/ prefixOperator* identOrLiteral primarySuffix*
|
||||
typeDesc = simpleExpr ('not' expr)?
|
||||
typeDefAux = simpleExpr ('not' expr
|
||||
| postExprBlocks)?
|
||||
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)?
|
||||
typeDescExpr = (routineType / simpleExpr) ('not' expr)?
|
||||
typeDesc = rawTypeDesc / typeDescExpr
|
||||
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
|
||||
| IND{=} 'except' exprList ':' stmt
|
||||
| IND{=} 'finally' ':' stmt
|
||||
| IND{=} 'else' ':' stmt )*
|
||||
exprStmt = simpleExpr
|
||||
(( '=' optInd expr colonBody? )
|
||||
/ ( expr ^+ comma
|
||||
postExprBlocks
|
||||
))?
|
||||
exprStmt = simpleExpr postExprBlocks?
|
||||
/ simplePrimary (exprEqExpr ^+ comma) postExprBlocks?
|
||||
/ simpleExpr '=' optInd (expr postExprBlocks?)
|
||||
importStmt = 'import' optInd expr
|
||||
((comma expr)*
|
||||
/ 'except' optInd (expr ^+ comma))
|
||||
@@ -175,7 +184,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?
|
||||
|
||||
@@ -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
|
||||
@@ -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` "
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 <int literal(1)>
|
||||
tsigmatch2.nim(46, 3) Error: type mismatch: got <int literal(1)>
|
||||
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"
|
||||
static: echo "done"
|
||||
|
||||
@@ -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]
|
||||
|
||||
17
tests/parser/tcommandequals.nim
Normal file
17
tests/parser/tcommandequals.nim
Normal file
@@ -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
|
||||
16
tests/parser/tcommandindent.nim
Normal file
16
tests/parser/tcommandindent.nim
Normal file
@@ -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
|
||||
)
|
||||
3
tests/parser/tdoublenotnil.nim
Normal file
3
tests/parser/tdoublenotnil.nim
Normal file
@@ -0,0 +1,3 @@
|
||||
when false:
|
||||
type Foo = Bar not nil not nil #[tt.Error
|
||||
^ invalid indentation]#
|
||||
10
tests/parser/ttypeexprobject.nim
Normal file
10
tests/parser/ttypeexprobject.nim
Normal file
@@ -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
|
||||
25
tests/parser/ttypeexprs.nim
Normal file
25
tests/parser/ttypeexprs.nim
Normal file
@@ -0,0 +1,25 @@
|
||||
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
|
||||
)
|
||||
|
||||
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))
|
||||
|
||||
type SomePointer = proc | ref | ptr | pointer
|
||||
@@ -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
|
||||
'''
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
errormsg: "type mismatch: got <Thin[system.int]>"
|
||||
nimout: '''t7600_1.nim(21, 6) Error: type mismatch: got <Thin[system.int]>
|
||||
nimout: '''t7600_1.nim(21, 1) Error: type mismatch: got <Thin[system.int]>
|
||||
but expected one of:
|
||||
proc test[T](x: Paper[T])
|
||||
first type mismatch at position: 1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
errormsg: "type mismatch: got <Thin>"
|
||||
nimout: '''t7600_2.nim(20, 6) Error: type mismatch: got <Thin>
|
||||
nimout: '''t7600_2.nim(20, 1) Error: type mismatch: got <Thin>
|
||||
but expected one of:
|
||||
proc test(x: Paper)
|
||||
first type mismatch at position: 1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
errormsg: "type mismatch: got <int>"
|
||||
nimout: '''tprevent_forloopvar_mutations.nim(16, 7) Error: type mismatch: got <int>
|
||||
nimout: '''tprevent_forloopvar_mutations.nim(16, 3) Error: type mismatch: got <int>
|
||||
but expected one of:
|
||||
proc inc[T, V: Ordinal](x: var T; y: V = 1)
|
||||
first type mismatch at position: 1
|
||||
|
||||
Reference in New Issue
Block a user