diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 6 | ||||
-rw-r--r-- | compiler/parser.nim | 44 | ||||
-rw-r--r-- | compiler/renderer.nim | 15 | ||||
-rw-r--r-- | compiler/semtypes.nim | 11 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 23 |
5 files changed, 72 insertions, 27 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index ae1b34fd9..30778c02d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -188,6 +188,10 @@ type nkStmtListType, # a statement list ending in a type; for macros nkBlockType, # a statement block ending in a type; for macros # types as syntactic trees: + + nkWith, # distinct with `foo` + nkWithout, # distinct without `foo` + nkTypeOfExpr, # type(1+2) nkObjectTy, # object body nkTupleTy, # tuple body @@ -418,7 +422,7 @@ type nfExplicitCall # x.y() was used instead of x.y nfExprCall # this is an attempt to call a regular expression nfIsRef # this node is a 'ref' node; used for the VM - + TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 23) tfVarargs, # procedure has C styled varargs diff --git a/compiler/parser.nim b/compiler/parser.nim index 060629518..d59e013d7 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -67,7 +67,7 @@ proc optPar*(p: var TParser) proc optInd*(p: var TParser, n: PNode) proc indAndComment*(p: var TParser, n: PNode) proc setBaseFlags*(n: PNode, base: TNumericalBase) -proc parseSymbol*(p: var TParser): PNode +proc parseSymbol*(p: var TParser, allowNil = false): PNode proc parseTry(p: var TParser): PNode proc parseCase(p: var TParser): PNode # implementation @@ -273,7 +273,7 @@ proc colcom(p: var TParser, n: PNode) = eat(p, tkColon) skipComment(p, n) -proc parseSymbol(p: var TParser): PNode = +proc parseSymbol(p: var TParser, allowNil = false): PNode = #| symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`' #| | IDENT case p.tok.tokType @@ -312,9 +312,13 @@ proc parseSymbol(p: var TParser): PNode = break eat(p, tkAccent) else: - parMessage(p, errIdentifierExpected, p.tok) - getTok(p) # BUGFIX: We must consume a token here to prevent endless loops! - result = ast.emptyNode + if allowNil and p.tok.tokType == tkNil: + result = newNodeP(nkNilLit, p) + getTok(p) + else: + parMessage(p, errIdentifierExpected, p.tok) + getTok(p) # BUGFIX: We must consume a token here to prevent endless loops! + result = ast.emptyNode proc indexExpr(p: var TParser): PNode = #| indexExpr = expr @@ -964,14 +968,30 @@ proc isExprStart(p: TParser): bool = tkTuple, tkObject, tkType, tkWhen, tkCase, tkShared: result = true else: result = false - -proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, - mode: TPrimaryMode): PNode = + +proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) = + while true: + var s = parseSymbol(p, allowNil) + if s.kind == nkEmpty: break + addSon(result, s) + if p.tok.tokType != tkComma: break + getTok(p) + optInd(p, s) + +proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, + mode: TPrimaryMode): PNode = result = newNodeP(kind, p) getTok(p) optInd(p, result) if not isOperator(p.tok) and isExprStart(p): addSon(result, primary(p, mode)) + if kind == nkDistinctTy and p.tok.tokType in {tkWith, tkWithout}: + let nodeKind = if p.tok.tokType == tkWith: nkWith + else: nkWithout + getTok(p) + let list = newNodeP(nodeKind, p) + result.addSon list + parseSymbolList(p, list, allowNil = true) proc parseExpr(p: var TParser): PNode = #| expr = (ifExpr @@ -988,7 +1008,6 @@ proc parseExpr(p: var TParser): PNode = proc parseEnum(p: var TParser): PNode proc parseObject(p: var TParser): PNode -proc parseDistinct(p: var TParser): PNode proc parseTypeClass(p: var TParser): PNode proc primary(p: var TParser, mode: TPrimaryMode): PNode = @@ -1743,13 +1762,6 @@ proc parseTypeClass(p: var TParser): PNode = else: addSon(result, parseStmt(p)) -proc parseDistinct(p: var TParser): PNode = - #| distinct = 'distinct' optInd typeDesc - result = newNodeP(nkDistinctTy, p) - getTok(p) - optInd(p, result) - addSon(result, parseTypeDesc(p)) - proc parseTypeDef(p: var TParser): PNode = #| typeDef = identWithPragma genericParamList? '=' optInd typeDefAux #| indAndComment? diff --git a/compiler/renderer.nim b/compiler/renderer.nim index d68cb91c0..2d2310914 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -424,8 +424,11 @@ proc lsub(n: PNode): int = of nkRefTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ref") of nkPtrTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ptr") of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var") - of nkDistinctTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + - len("Distinct") + of nkDistinctTy: + result = len("distinct") + (if n.len > 0: lsub(n.sons[0])+1 else: 0) + if n.len > 1: + result += (if n[1].kind == nkWith: len("_with_") else: len("_without_")) + result += lcomma(n[1]) of nkStaticTy: result = (if n.len > 0: lsub(n.sons[0]) else: 0) + len("static[]") of nkTypeDef: result = lsons(n) + 3 @@ -1020,9 +1023,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = else: put(g, tkVar, "var") of nkDistinctTy: - if sonsLen(n) > 0: + if n.len > 0: putWithSpace(g, tkDistinct, "distinct") gsub(g, n.sons[0]) + if n.len > 1: + if n[1].kind == nkWith: + putWithSpace(g, tkWith, " with") + else: + putWithSpace(g, tkWithout, " without") + gcomma(g, n[1]) else: put(g, tkDistinct, "distinct") of nkTypeDef: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 269676624..c53dc0f7d 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -139,13 +139,12 @@ proc semVarType(c: PContext, n: PNode, prev: PType): PType = addSonSkipIntLit(result, base) else: result = newConstraint(c, tyVar) - + proc semDistinct(c: PContext, n: PNode, prev: PType): PType = - if sonsLen(n) == 1: - result = newOrPrevType(tyDistinct, prev, c) - addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil)) - else: - result = newConstraint(c, tyDistinct) + if n.len == 0: return newConstraint(c, tyDistinct) + result = newOrPrevType(tyDistinct, prev, c) + addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil)) + if n.len > 1: result.n = n[1] proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = assert isRange(n) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index c09964638..ae31f1630 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -491,6 +491,23 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, return isGeneric +proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool = + if rules.kind == nkWith: + for r in rules: + if r.considerAcc == callIdent: return true + return false + else: + for r in rules: + if r.considerAcc == callIdent: return false + return true + +proc maybeSkipDistinct(t: PType, callee: PSym): PType = + if t != nil and t.kind == tyDistinct and t.n != nil and + shouldSkipDistinct(t.n, callee.name): + result = t.base + else: + result = t + proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # typeRel can be used to establish various relationships between types: # @@ -518,7 +535,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = assert(aOrig != nil) # var and static arguments match regular modifier-free types - let a = aOrig.skipTypes({tyStatic, tyVar}) + let a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym) + # XXX: Theoretically, maybeSkipDistinct could be called before we even + # start the param matching process. This could be done in `prepareOperand` + # for example, but unfortunately `prepareOperand` is not called in certain + # situation when nkDotExpr are rotated to nkDotCalls if a.kind == tyGenericInst and skipTypes(f, {tyVar}).kind notin { |