parser support for 'not nil' annotation

This commit is contained in:
Araq 2012-11-25 23:40:42 +01:00
commit 538699a281
2 changed files with 63 additions and 52 deletions

View file

@ -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
View 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