parser support for 'not nil' annotation
This commit is contained in:
parent
2a2f41ee98
commit
538699a281
2 changed files with 63 additions and 52 deletions
|
|
@ -11,7 +11,7 @@
|
||||||
# The parser strictly reflects the grammar ("doc/grammar.txt"); however
|
# The parser strictly reflects the grammar ("doc/grammar.txt"); however
|
||||||
# it uses several helper routines to keep the parser small. A special
|
# it uses several helper routines to keep the parser small. A special
|
||||||
# efficient algorithm is used for the precedence levels. The parser here can
|
# efficient algorithm is used for the precedence levels. The parser here can
|
||||||
# be seen as a refinement of the grammar, as it specifies how the AST is build
|
# be seen as a refinement of the grammar, as it specifies how the AST is built
|
||||||
# from the grammar and how comments belong to the AST.
|
# from the grammar and how comments belong to the AST.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
|
@ -183,15 +183,14 @@ proc getPrecedence(tok: TToken): int =
|
||||||
of '?': result = 2
|
of '?': result = 2
|
||||||
else: considerAsgn(2)
|
else: considerAsgn(2)
|
||||||
of tkDiv, tkMod, tkShl, tkShr: result = 9
|
of tkDiv, tkMod, tkShl, tkShr: result = 9
|
||||||
of tkIn, tkNotIn, tkIs, tkIsNot, tkOf, tkAs: result = 5
|
of tkIn, tkNotIn, tkIs, tkIsNot, tkNot, tkOf, tkAs: result = 5
|
||||||
of tkDotDot: result = 6
|
of tkDotDot: result = 6
|
||||||
of tkAnd: result = 4
|
of tkAnd: result = 4
|
||||||
of tkOr, tkXor: result = 3
|
of tkOr, tkXor: result = 3
|
||||||
of tkNot: result = -2
|
|
||||||
else: result = - 10
|
else: result = - 10
|
||||||
|
|
||||||
proc isOperator(tok: TToken): bool =
|
proc isOperator(tok: TToken): bool =
|
||||||
result = getPrecedence(tok) >= -2
|
result = getPrecedence(tok) >= 0
|
||||||
|
|
||||||
proc parseSymbol(p: var TParser): PNode =
|
proc parseSymbol(p: var TParser): PNode =
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
|
@ -511,7 +510,7 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||||
else: break
|
else: break
|
||||||
|
|
||||||
type
|
type
|
||||||
TPrimaryMode = enum pmNormal, pmIsType, pmSkipSuffix
|
TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
|
||||||
|
|
||||||
proc primary(p: var TParser, mode: TPrimaryMode): PNode
|
proc primary(p: var TParser, mode: TPrimaryMode): PNode
|
||||||
|
|
||||||
|
|
@ -519,14 +518,15 @@ proc lowestExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
|
||||||
result = primary(p, mode)
|
result = primary(p, mode)
|
||||||
# expand while operators have priorities higher than 'limit'
|
# expand while operators have priorities higher than 'limit'
|
||||||
var opPrec = getPrecedence(p.tok)
|
var opPrec = getPrecedence(p.tok)
|
||||||
while opPrec >= limit:
|
let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
|
||||||
|
while opPrec >= limit:
|
||||||
var leftAssoc = ord(IsLeftAssociative(p.tok))
|
var leftAssoc = ord(IsLeftAssociative(p.tok))
|
||||||
var a = newNodeP(nkInfix, p)
|
var a = newNodeP(nkInfix, p)
|
||||||
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
|
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, opNode)
|
optInd(p, opNode)
|
||||||
# read sub-expression with higher priority:
|
# read sub-expression with higher priority:
|
||||||
var b = lowestExprAux(p, opPrec + leftAssoc, mode)
|
var b = lowestExprAux(p, opPrec + leftAssoc, modeB)
|
||||||
addSon(a, opNode)
|
addSon(a, opNode)
|
||||||
addSon(a, result)
|
addSon(a, result)
|
||||||
addSon(a, b)
|
addSon(a, b)
|
||||||
|
|
@ -742,20 +742,12 @@ proc isExprStart(p: TParser): bool =
|
||||||
result = true
|
result = true
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
||||||
when false:
|
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, mode: TPrimaryMode): PNode =
|
||||||
proc parseTypeDescNoSuffix(p: var TParser): PNode =
|
|
||||||
if p.tok.toktype == tkProc: result = parseProcExpr(p, false)
|
|
||||||
elif p.tok.toktype == tkIterator:
|
|
||||||
result = parseProcExpr(p, false)
|
|
||||||
result.kind = nkIteratorTy
|
|
||||||
else: result = primary(p)
|
|
||||||
|
|
||||||
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind): PNode =
|
|
||||||
result = newNodeP(kind, p)
|
result = newNodeP(kind, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
if not isOperator(p.tok) and isExprStart(p):
|
if not isOperator(p.tok) and isExprStart(p):
|
||||||
addSon(result, primary(p, pmIsType))
|
addSon(result, primary(p, mode))
|
||||||
|
|
||||||
proc parseExpr(p: var TParser): PNode =
|
proc parseExpr(p: var TParser): PNode =
|
||||||
#
|
#
|
||||||
|
|
@ -771,6 +763,10 @@ proc parseExpr(p: var TParser): PNode =
|
||||||
# XXX needs proper support:
|
# XXX needs proper support:
|
||||||
#of tkTry: result = parseTry(p)
|
#of tkTry: result = parseTry(p)
|
||||||
|
|
||||||
|
proc parseObject(p: var TParser): PNode
|
||||||
|
proc parseDistinct(p: var TParser): PNode
|
||||||
|
proc parseEnum(p: var TParser): PNode
|
||||||
|
|
||||||
proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
# prefix operator?
|
# prefix operator?
|
||||||
if isOperator(p.tok):
|
if isOperator(p.tok):
|
||||||
|
|
@ -789,14 +785,14 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
return
|
return
|
||||||
|
|
||||||
case p.tok.tokType:
|
case p.tok.tokType:
|
||||||
of tkVar: result = parseTypeDescKAux(p, nkVarTy)
|
of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
|
||||||
of tkRef: result = parseTypeDescKAux(p, nkRefTy)
|
of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
|
||||||
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy)
|
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
|
||||||
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr)
|
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr, mode)
|
||||||
of tkTuple: result = parseTuple(p)
|
of tkTuple: result = parseTuple(p)
|
||||||
of tkProc: result = parseProcExpr(p, mode != pmIsType)
|
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
||||||
of tkIterator:
|
of tkIterator:
|
||||||
if mode == pmIsType:
|
if mode in {pmTypeDesc, pmTypeDef}:
|
||||||
result = parseProcExpr(p, false)
|
result = parseProcExpr(p, false)
|
||||||
result.kind = nkIteratorTy
|
result.kind = nkIteratorTy
|
||||||
else:
|
else:
|
||||||
|
|
@ -805,14 +801,23 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
getTok(p) # we must consume a token here to prevend endless loops!
|
getTok(p) # we must consume a token here to prevend endless loops!
|
||||||
result = ast.emptyNode
|
result = ast.emptyNode
|
||||||
of tkEnum:
|
of tkEnum:
|
||||||
result = newNodeP(nkEnumTy, p)
|
if mode == pmTypeDef:
|
||||||
getTok(p)
|
result = parseEnum(p)
|
||||||
|
else:
|
||||||
|
result = newNodeP(nkEnumTy, p)
|
||||||
|
getTok(p)
|
||||||
of tkObject:
|
of tkObject:
|
||||||
result = newNodeP(nkObjectTy, p)
|
if mode == pmTypeDef:
|
||||||
getTok(p)
|
result = parseObject(p)
|
||||||
|
else:
|
||||||
|
result = newNodeP(nkObjectTy, p)
|
||||||
|
getTok(p)
|
||||||
of tkDistinct:
|
of tkDistinct:
|
||||||
result = newNodeP(nkDistinctTy, p)
|
if mode == pmTypeDef:
|
||||||
getTok(p)
|
result = parseDistinct(p)
|
||||||
|
else:
|
||||||
|
result = newNodeP(nkDistinctTy, p)
|
||||||
|
getTok(p)
|
||||||
of tkAddr:
|
of tkAddr:
|
||||||
result = newNodeP(nkAddr, p)
|
result = newNodeP(nkAddr, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -832,19 +837,10 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
result = primarySuffix(p, result)
|
result = primarySuffix(p, result)
|
||||||
|
|
||||||
proc parseTypeDesc(p: var TParser): PNode =
|
proc parseTypeDesc(p: var TParser): PNode =
|
||||||
result = lowestExpr(p, pmIsType)
|
result = lowestExpr(p, pmTypeDesc)
|
||||||
when false:
|
|
||||||
result = parseTypeDescNoSuffix(p)
|
proc parseTypeDefAux(p: var TParser): PNode =
|
||||||
# optional 'not nil' suffix?
|
result = lowestExpr(p, pmTypeDef)
|
||||||
if p.tok.tokType == tkNot:
|
|
||||||
# we don't call 'getTok' here, so 'parseExpr' includes the 'not' in the
|
|
||||||
# expression; this will yield an nkPrefix AST ;-)
|
|
||||||
let ex = parseExpr(p)
|
|
||||||
let a = newNodeI(nkInfix, result.info, 3)
|
|
||||||
a.sons[0] = ex.sons[0]
|
|
||||||
a.sons[1] = result
|
|
||||||
a.sons[2] = ex.sons[1]
|
|
||||||
result = a
|
|
||||||
|
|
||||||
proc parseExprStmt(p: var TParser): PNode =
|
proc parseExprStmt(p: var TParser): PNode =
|
||||||
var a = lowestExpr(p)
|
var a = lowestExpr(p)
|
||||||
|
|
@ -1445,16 +1441,16 @@ proc parseTypeDef(p: var TParser): PNode =
|
||||||
if p.tok.tokType == tkEquals:
|
if p.tok.tokType == tkEquals:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
var a: PNode
|
#var a: PNode
|
||||||
case p.tok.tokType
|
#case p.tok.tokType
|
||||||
of tkObject: a = parseObject(p)
|
#of tkObject: a = parseObject(p)
|
||||||
of tkEnum: a = parseEnum(p)
|
#of tkEnum: a = parseEnum(p)
|
||||||
of tkDistinct: a = parseDistinct(p)
|
#of tkDistinct: a = parseDistinct(p)
|
||||||
of tkTuple: a = parseTuple(p, true)
|
#of tkTuple: a = parseTuple(p, true)
|
||||||
of tkRef: a = parsePointerInTypeSection(p, nkRefTy)
|
#of tkRef: a = parsePointerInTypeSection(p, nkRefTy)
|
||||||
of tkPtr: a = parsePointerInTypeSection(p, nkPtrTy)
|
#of tkPtr: a = parsePointerInTypeSection(p, nkPtrTy)
|
||||||
else: a = parseTypeDesc(p)
|
#else: a = parseTypeDesc(p)
|
||||||
addSon(result, a)
|
addSon(result, parseTypeDefAux(p))
|
||||||
else:
|
else:
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, ast.emptyNode)
|
||||||
indAndComment(p, result) # special extension!
|
indAndComment(p, result) # special extension!
|
||||||
|
|
|
||||||
15
tests/reject/tnotnil.nim
Normal file
15
tests/reject/tnotnil.nim
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
discard """
|
||||||
|
line: 11
|
||||||
|
errormgs: "type mismatch"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
PObj = ref TObj not nil
|
||||||
|
TObj = object
|
||||||
|
x: int
|
||||||
|
|
||||||
|
var x: PObj = nil
|
||||||
|
|
||||||
|
proc p(x: string not nil): int =
|
||||||
|
result = 45
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue