mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-03 18:34:43 +00:00
implements `distinct with/without X, Y`
This still doesn't work quite right, because some common operations like array indexing lay completely outside the scope/symbol lookup system - they are not even magics.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user