diff options
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 2 | ||||
-rwxr-xr-x | compiler/parser.nim | 75 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 47 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 37 | ||||
-rwxr-xr-x | compiler/types.nim | 26 |
5 files changed, 120 insertions, 67 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index edf93f4c9..027f4d003 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -715,6 +715,8 @@ const tyFloat..tyFloat128, tyUInt..tyUInt64} ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet, tyTuple, tySequence} + NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence, + tyProc, tyString, tyError} ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, skMacro, skTemplate, skConverter, skEnumField, skLet, skStub} PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst} diff --git a/compiler/parser.nim b/compiler/parser.nim index 59f7934e0..c0a7bc7fe 100755 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -183,14 +183,15 @@ proc getPrecedence(tok: TToken): int = of '?': result = 2 else: considerAsgn(2) of tkDiv, tkMod, tkShl, tkShr: result = 9 - of tkIn, tkNotIn, tkIs, tkIsNot, tkNot, tkOf, tkAs: result = 5 + of tkIn, tkNotIn, tkIs, tkIsNot, tkOf, tkAs: result = 5 of tkDotDot: result = 6 of tkAnd: result = 4 of tkOr, tkXor: result = 3 + of tkNot: result = -2 else: result = - 10 proc isOperator(tok: TToken): bool = - result = getPrecedence(tok) >= 0 + result = getPrecedence(tok) >= -2 proc parseSymbol(p: var TParser): PNode = case p.tok.tokType @@ -509,10 +510,13 @@ proc primarySuffix(p: var TParser, r: PNode): PNode = result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi) else: break -proc primary(p: var TParser, skipSuffix = false): PNode +type + TPrimaryMode = enum pmNormal, pmIsType, pmSkipSuffix + +proc primary(p: var TParser, mode: TPrimaryMode): PNode -proc lowestExprAux(p: var TParser, limit: int): PNode = - result = primary(p) +proc lowestExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode = + result = primary(p, mode) # expand while operators have priorities higher than 'limit' var opPrec = getPrecedence(p.tok) while opPrec >= limit: @@ -522,15 +526,15 @@ proc lowestExprAux(p: var TParser, limit: int): PNode = getTok(p) optInd(p, opNode) # read sub-expression with higher priority: - var b = lowestExprAux(p, opPrec + leftAssoc) + var b = lowestExprAux(p, opPrec + leftAssoc, mode) addSon(a, opNode) addSon(a, result) addSon(a, b) result = a opPrec = getPrecedence(p.tok) -proc lowestExpr(p: var TParser): PNode = - result = lowestExprAux(p, -1) +proc lowestExpr(p: var TParser, mode = pmNormal): PNode = + result = lowestExprAux(p, -1, mode) proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = result = newNodeP(kind, p) @@ -738,12 +742,20 @@ proc isExprStart(p: TParser): bool = result = true else: result = false +when false: + 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) getTok(p) optInd(p, result) if not isOperator(p.tok) and isExprStart(p): - addSon(result, parseTypeDesc(p)) + addSon(result, primary(p, pmIsType)) proc parseExpr(p: var TParser): PNode = # @@ -759,7 +771,7 @@ proc parseExpr(p: var TParser): PNode = # XXX needs proper support: #of tkTry: result = parseTry(p) -proc primary(p: var TParser, skipSuffix = false): PNode = +proc primary(p: var TParser, mode: TPrimaryMode): PNode = # prefix operator? if isOperator(p.tok): let isSigil = IsSigilLike(p.tok) @@ -770,10 +782,10 @@ proc primary(p: var TParser, skipSuffix = false): PNode = optInd(p, a) if isSigil: #XXX prefix operators - addSon(result, primary(p, true)) + addSon(result, primary(p, pmSkipSuffix)) result = primarySuffix(p, result) else: - addSon(result, primary(p)) + addSon(result, primary(p, pmNormal)) return case p.tok.tokType: @@ -782,7 +794,16 @@ proc primary(p: var TParser, skipSuffix = false): PNode = of tkPtr: result = parseTypeDescKAux(p, nkPtrTy) of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr) of tkTuple: result = parseTuple(p) - of tkProc: result = parseProcExpr(p, true) + of tkProc: result = parseProcExpr(p, mode != pmIsType) + of tkIterator: + if mode == pmIsType: + result = parseProcExpr(p, false) + result.kind = nkIteratorTy + else: + # no anon iterators for now: + parMessage(p, errExprExpected, p.tok) + getTok(p) # we must consume a token here to prevend endless loops! + result = ast.emptyNode of tkEnum: result = newNodeP(nkEnumTy, p) getTok(p) @@ -795,27 +816,35 @@ proc primary(p: var TParser, skipSuffix = false): PNode = of tkAddr: result = newNodeP(nkAddr, p) getTok(p) - addSon(result, primary(p)) + addSon(result, primary(p, pmNormal)) of tkStatic: result = newNodeP(nkStaticExpr, p) getTok(p) - addSon(result, primary(p)) + addSon(result, primary(p, pmNormal)) of tkBind: result = newNodeP(nkBind, p) getTok(p) optInd(p, result) - addSon(result, primary(p)) + addSon(result, primary(p, pmNormal)) else: result = identOrLiteral(p) - if not skipSuffix: + if mode != pmSkipSuffix: result = primarySuffix(p, result) - + proc parseTypeDesc(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 = parseExpr(p) + result = lowestExpr(p, pmIsType) + when false: + result = parseTypeDescNoSuffix(p) + # optional 'not nil' suffix? + 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 = var a = lowestExpr(p) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index ab80298de..530e803a3 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -799,16 +799,18 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkPar: if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) else: + # XXX support anon tuple here LocalError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) of nkCallKinds: if n[0].kind == nkIdent: let op = n.sons[0].ident if op.id in {ord(wAnd), ord(wOr)} or op.s == "|": + checkSonsLen(n, 3) var t1 = semTypeNode(c, n.sons[1], nil) t2 = semTypeNode(c, n.sons[2], nil) - if t1 == nil: + if t1 == nil: LocalError(n.sons[1].info, errTypeExpected) result = newOrPrevType(tyError, prev, c) elif t2 == nil: @@ -819,6 +821,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result.addSonSkipIntLit(t1) result.addSonSkipIntLit(t2) result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny) + elif op.id == ord(wNot): + checkSonsLen(n, 3) + result = semTypeNode(c, n.sons[1], prev) + if result.kind in NilableTypes and n.sons[2].kind == nkNilLit: + result.flags.incl(tfNotNil) + else: + LocalError(n.info, errGenerated, "invalid type") else: result = semTypeExpr(c, n) else: @@ -883,25 +892,33 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkVarTy: result = semVarType(c, n, prev) of nkDistinctTy: result = semDistinct(c, n, prev) of nkProcTy, nkIteratorTy: - if n.sonsLen == 0: return newConstraint(c, tyProc) - checkSonsLen(n, 2) - openScope(c.tab) - result = semProcTypeNode(c, n.sons[0], nil, prev, skProc) - # dummy symbol for `pragma`: - var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c) - s.typ = result - if n.sons[1].kind == nkEmpty or n.sons[1].len == 0: - if result.callConv == ccDefault: - result.callConv = ccClosure - #Message(n.info, warnImplicitClosure, renderTree(n)) + if n.sonsLen == 0: + result = newConstraint(c, tyProc) else: - pragma(c, s, n.sons[1], procTypePragmas) - when useEffectSystem: SetEffectsForProcType(result, n.sons[1]) - closeScope(c.tab) + checkSonsLen(n, 2) + openScope(c.tab) + result = semProcTypeNode(c, n.sons[0], nil, prev, skProc) + # dummy symbol for `pragma`: + var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c) + s.typ = result + if n.sons[1].kind == nkEmpty or n.sons[1].len == 0: + if result.callConv == ccDefault: + result.callConv = ccClosure + #Message(n.info, warnImplicitClosure, renderTree(n)) + else: + pragma(c, s, n.sons[1], procTypePragmas) + when useEffectSystem: SetEffectsForProcType(result, n.sons[1]) + closeScope(c.tab) + if n.kind == nkIteratorTy: + result.flags.incl(tfIterator) of nkEnumTy: result = semEnum(c, n, prev) of nkType: result = n.typ of nkStmtListType: result = semStmtListType(c, n, prev) of nkBlockType: result = semBlockType(c, n, prev) + of nkSharedTy: + checkSonsLen(n, 1) + result = semTypeNode(c, n.sons[0], prev) + result.flags.incl(tfShared) else: LocalError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 0b9244c2a..03fb9a075 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -257,12 +257,14 @@ proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation = var y = a.n.sons[i].sym if x.name.id != y.name.id: return isNone +proc allowsNil(f: PType): TTypeRelation {.inline.} = + result = if tfNotNil notin f.flags: isSubtype else: isNone + proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = proc inconsistentVarTypes(f, a: PType): bool {.inline.} = result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar) case a.kind - of tyNil: result = isSubtype of tyProc: if sonsLen(f) != sonsLen(a): return # Note: We have to do unification for the parameters before the @@ -299,6 +301,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = return isNone when useEffectSystem: if not compatibleEffects(f, a): return isNone + of tyNil: result = f.allowsNil else: nil proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation = @@ -388,16 +391,15 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = elif typeRel(c, base(f), a.sons[0]) >= isGeneric: result = isConvertible else: nil - of tySequence: + of tySequence: case a.Kind - of tyNil: - result = isSubtype - of tySequence: - if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): + of tySequence: + if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): result = isSubtype - else: + else: result = typeRel(c, f.sons[0], a.sons[0]) if result < isGeneric: result = isNone + of tyNil: result = f.allowsNil else: nil of tyOrdinal: if isOrdinalType(a): @@ -432,21 +434,21 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = of tyPtr: result = typeRel(c, base(f), base(a)) if result <= isConvertible: result = isNone - of tyNil: result = isSubtype + of tyNil: result = f.allowsNil else: nil of tyRef: case a.kind - of tyRef: + of tyRef: result = typeRel(c, base(f), base(a)) if result <= isConvertible: result = isNone - of tyNil: result = isSubtype + of tyNil: result = f.allowsNil else: nil - of tyProc: + of tyProc: result = procTypeRel(c, f, a) of tyPointer: case a.kind of tyPointer: result = isEqual - of tyNil: result = isSubtype + of tyNil: result = f.allowsNil of tyProc: if a.callConv != ccClosure: result = isConvertible of tyPtr, tyCString: result = isConvertible @@ -454,15 +456,15 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = of tyString: case a.kind of tyString: result = isEqual - of tyNil: result = isSubtype + of tyNil: result = f.allowsNil else: nil - of tyCString: + of tyCString: # conversion from string to cstring is automatic: case a.Kind of tyCString: result = isEqual - of tyNil: result = isSubtype + of tyNil: result = f.allowsNil of tyString: result = isConvertible - of tyPtr: + of tyPtr: if a.sons[0].kind == tyChar: result = isConvertible of tyArray: if (firstOrd(a.sons[0]) == 0) and @@ -706,8 +708,7 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType, z.calleeSym = m.calleeSym var best = -1 for i in countup(0, sonsLen(arg) - 1): - # iterators are not first class yet, so ignore them - if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}: + if arg.sons[i].sym.kind in {skProc, skIterator, skMethod, skConverter}: copyCandidate(z, m) var r = typeRel(z, f, arg.sons[i].typ) if r != isNone: diff --git a/compiler/types.nim b/compiler/types.nim index dbd03620c..825b1027a 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -791,6 +791,9 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = else: if containsOrIncl(c, a, b): return true + proc sameFlags(a, b: PType): bool {.inline.} = + result = eqTypeFlags*a.flags == eqTypeFlags*b.flags + if x == y: return true var a = skipTypes(x, {tyGenericInst}) var b = skipTypes(y, {tyGenericInst}) @@ -809,36 +812,37 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = case a.Kind of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, tyInt..tyBigNum, tyStmt: - result = true + result = sameFlags(a, b) of tyExpr: - result = ExprStructuralEquivalent(a.n, b.n) + result = ExprStructuralEquivalent(a.n, b.n) and sameFlags(a, b) of tyObject: IfFastObjectTypeCheckFailed(a, b): CycleCheck() - result = sameObjectStructures(a, b, c) + result = sameObjectStructures(a, b, c) and sameFlags(a, b) of tyDistinct: CycleCheck() - if c.cmp == dcEq: result = sameDistinctTypes(a, b) - else: result = sameTypeAux(a.sons[0], b.sons[0], c) + if c.cmp == dcEq: result = sameDistinctTypes(a, b) and sameFlags(a, b) + else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b) of tyEnum, tyForward, tyProxy: # XXX generic enums do not make much sense, but require structural checking - result = a.id == b.id + result = a.id == b.id and sameFlags(a, b) of tyTuple: CycleCheck() - result = sameTuple(a, b, c) - of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c) + result = sameTuple(a, b, c) and sameFlags(a, b) + of tyGenericInst: + result = sameTypeAux(lastSon(a), lastSon(b), c) of tyTypeDesc: if TypeDescExactMatch in c.flags: CycleCheck() - result = sameChildrenAux(x, y, c) + result = sameChildrenAux(x, y, c) and sameFlags(a, b) else: - result = true + result = sameFlags(a, b) of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter, tyOrdinal, tyTypeClass: CycleCheck() - result = sameChildrenAux(a, b, c) + result = sameChildrenAux(a, b, c) and sameFlags(a, b) if result and (a.kind == tyProc): result = a.callConv == b.callConv of tyRange: |