refactoring: suggest can import sigmatch for type matching
This commit is contained in:
parent
4e7a22cac3
commit
fdde4d3a92
12 changed files with 445 additions and 266 deletions
|
|
@ -51,16 +51,18 @@ type
|
||||||
TTabIter*{.final.} = object # consider all fields here private
|
TTabIter*{.final.} = object # consider all fields here private
|
||||||
h*: THash # current hash
|
h*: THash # current hash
|
||||||
|
|
||||||
|
|
||||||
proc InitTabIter*(ti: var TTabIter, tab: TStrTable): PSym
|
proc InitTabIter*(ti: var TTabIter, tab: TStrTable): PSym
|
||||||
proc NextIter*(ti: var TTabIter, tab: TStrTable): PSym
|
proc NextIter*(ti: var TTabIter, tab: TStrTable): PSym
|
||||||
# usage:
|
# usage:
|
||||||
# var i: TTabIter; s: PSym;
|
# var
|
||||||
# s := InitTabIter(i, table);
|
# i: TTabIter
|
||||||
# while s <> nil do begin
|
# s: PSym
|
||||||
|
# s = InitTabIter(i, table)
|
||||||
|
# while s != nil:
|
||||||
# ...
|
# ...
|
||||||
# s := NextIter(i, table);
|
# s = NextIter(i, table)
|
||||||
# end;
|
#
|
||||||
|
|
||||||
type
|
type
|
||||||
TIdentIter*{.final.} = object # iterator over all syms with the same identifier
|
TIdentIter*{.final.} = object # iterator over all syms with the same identifier
|
||||||
h*: THash # current hash
|
h*: THash # current hash
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import
|
||||||
strutils, nhashes, lists, options, scanner, ast, astalgo, trees, treetab,
|
strutils, nhashes, lists, options, scanner, ast, astalgo, trees, treetab,
|
||||||
wordrecg, ropes, msgs, os, condsyms, idents, rnimsyn, types, platform, math,
|
wordrecg, ropes, msgs, os, condsyms, idents, rnimsyn, types, platform, math,
|
||||||
magicsys, pnimsyn, nversion, nimsets, semdata, evals, semfold, importer,
|
magicsys, pnimsyn, nversion, nimsets, semdata, evals, semfold, importer,
|
||||||
procfind, lookups, rodread, pragmas, passes, suggest
|
procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest
|
||||||
|
|
||||||
proc semPass*(): TPass
|
proc semPass*(): TPass
|
||||||
# implementation
|
# implementation
|
||||||
|
|
@ -34,10 +34,6 @@ proc isTopLevel(c: PContext): bool =
|
||||||
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||||
result = newSym(kind, considerAcc(n), getCurrOwner())
|
result = newSym(kind, considerAcc(n), getCurrOwner())
|
||||||
result.info = n.info
|
result.info = n.info
|
||||||
|
|
||||||
proc markUsed(n: PNode, s: PSym) =
|
|
||||||
incl(s.flags, sfUsed)
|
|
||||||
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
|
|
||||||
|
|
||||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym
|
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym
|
||||||
# identifier with visability
|
# identifier with visability
|
||||||
|
|
@ -115,7 +111,7 @@ proc semMacroExpr(c: PContext, n: PNode, sym: PSym,
|
||||||
if semCheck: result = semAfterMacroCall(c, result, sym)
|
if semCheck: result = semAfterMacroCall(c, result, sym)
|
||||||
dec(evalTemplateCounter)
|
dec(evalTemplateCounter)
|
||||||
|
|
||||||
include seminst, sigmatch
|
include seminst, semcall
|
||||||
|
|
||||||
proc CheckBool(t: PNode) =
|
proc CheckBool(t: PNode) =
|
||||||
if (t.Typ == nil) or
|
if (t.Typ == nil) or
|
||||||
|
|
|
||||||
98
rod/semcall.nim
Normal file
98
rod/semcall.nim
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nimrod Compiler
|
||||||
|
# (c) Copyright 2011 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## This module implements semantic checking for calls.
|
||||||
|
|
||||||
|
proc sameMethodDispatcher(a, b: PSym): bool =
|
||||||
|
result = false
|
||||||
|
if a.kind == skMethod and b.kind == skMethod:
|
||||||
|
var aa = lastSon(a.ast)
|
||||||
|
var bb = lastSon(b.ast)
|
||||||
|
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym:
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
|
||||||
|
initialBinding: PNode): PNode =
|
||||||
|
var
|
||||||
|
o: TOverloadIter
|
||||||
|
x, y, z: TCandidate
|
||||||
|
#Message(n.info, warnUser, renderTree(n))
|
||||||
|
var sym = initOverloadIter(o, c, f)
|
||||||
|
result = nil
|
||||||
|
if sym == nil: return
|
||||||
|
initCandidate(x, sym, initialBinding)
|
||||||
|
initCandidate(y, sym, initialBinding)
|
||||||
|
|
||||||
|
while sym != nil:
|
||||||
|
if sym.kind in filter:
|
||||||
|
initCandidate(z, sym, initialBinding)
|
||||||
|
z.calleeSym = sym
|
||||||
|
matches(c, n, z)
|
||||||
|
if z.state == csMatch:
|
||||||
|
case x.state
|
||||||
|
of csEmpty, csNoMatch: x = z
|
||||||
|
of csMatch:
|
||||||
|
var cmp = cmpCandidates(x, z)
|
||||||
|
if cmp < 0: x = z # z is better than x
|
||||||
|
elif cmp == 0: y = z # z is as good as x
|
||||||
|
else: nil
|
||||||
|
sym = nextOverloadIter(o, c, f)
|
||||||
|
if x.state == csEmpty:
|
||||||
|
# no overloaded proc found
|
||||||
|
# do not generate an error yet; the semantic checking will check for
|
||||||
|
# an overloaded () operator
|
||||||
|
elif y.state == csMatch and cmpCandidates(x, y) == 0 and
|
||||||
|
not sameMethodDispatcher(x.calleeSym, y.calleeSym):
|
||||||
|
if x.state != csMatch:
|
||||||
|
InternalError(n.info, "x.state is not csMatch")
|
||||||
|
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
|
||||||
|
getProcHeader(x.calleeSym), getProcHeader(y.calleeSym),
|
||||||
|
x.calleeSym.Name.s])
|
||||||
|
else:
|
||||||
|
# only one valid interpretation found:
|
||||||
|
markUsed(n, x.calleeSym)
|
||||||
|
if x.calleeSym.ast == nil:
|
||||||
|
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
|
||||||
|
if x.calleeSym.ast.sons[genericParamsPos].kind != nkEmpty:
|
||||||
|
# a generic proc!
|
||||||
|
x.calleeSym = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
||||||
|
x.callee = x.calleeSym.typ
|
||||||
|
result = x.call
|
||||||
|
result.sons[0] = newSymNode(x.calleeSym)
|
||||||
|
result.typ = x.callee.sons[0]
|
||||||
|
|
||||||
|
proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
|
||||||
|
# process the bindings once:
|
||||||
|
var initialBinding: PNode
|
||||||
|
var f = n.sons[0]
|
||||||
|
if f.kind == nkBracketExpr:
|
||||||
|
# fill in the bindings:
|
||||||
|
initialBinding = f
|
||||||
|
f = f.sons[0]
|
||||||
|
else:
|
||||||
|
initialBinding = nil
|
||||||
|
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
|
||||||
|
|
||||||
|
proc explictGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
|
assert n.kind == nkBracketExpr
|
||||||
|
for i in 1..sonsLen(n)-1:
|
||||||
|
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
|
||||||
|
# we cannot check for the proper number of type parameters because in
|
||||||
|
# `f[a,b](x, y)` `f` is not resolved yet properly.
|
||||||
|
# XXX: BUG this should be checked somehow!
|
||||||
|
assert n.sons[0].kind == nkSym
|
||||||
|
|
||||||
|
var x: TCandidate
|
||||||
|
initCandidate(x, s, n)
|
||||||
|
var newInst = generateInstance(c, s, x.bindings, n.info)
|
||||||
|
|
||||||
|
markUsed(n, s)
|
||||||
|
result = newSymNode(newInst)
|
||||||
|
result.info = n.info
|
||||||
|
|
||||||
|
|
@ -166,6 +166,10 @@ proc makeRangeType(c: PContext, first, last: biggestInt,
|
||||||
result.n = n
|
result.n = n
|
||||||
addSon(result, getSysType(tyInt)) # basetype of range
|
addSon(result, getSysType(tyInt)) # basetype of range
|
||||||
|
|
||||||
|
proc markUsed*(n: PNode, s: PSym) =
|
||||||
|
incl(s.flags, sfUsed)
|
||||||
|
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
|
||||||
|
|
||||||
proc illFormedAst*(n: PNode) =
|
proc illFormedAst*(n: PNode) =
|
||||||
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ const
|
||||||
ConstAbstractTypes = {tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
ConstAbstractTypes = {tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||||
tyArrayConstr, tyTuple, tySet}
|
tyArrayConstr, tyTuple, tySet}
|
||||||
|
|
||||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
||||||
semCheck: bool = true): PNode =
|
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
result = evalTemplate(c, n, s)
|
result = evalTemplate(c, n, s)
|
||||||
|
|
@ -122,9 +121,9 @@ proc checkConvertible(info: TLineInfo, castDest, src: PType) =
|
||||||
|
|
||||||
proc isCastable(dst, src: PType): bool =
|
proc isCastable(dst, src: PType): bool =
|
||||||
#const
|
#const
|
||||||
# castableTypeKinds = {@set}[tyInt, tyPtr, tyRef, tyCstring, tyString,
|
# castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
|
||||||
# tySequence, tyPointer, tyNil, tyOpenArray,
|
# tySequence, tyPointer, tyNil, tyOpenArray,
|
||||||
# tyProc, tySet, tyEnum, tyBool, tyChar];
|
# tyProc, tySet, tyEnum, tyBool, tyChar}
|
||||||
var ds, ss: biggestInt
|
var ds, ss: biggestInt
|
||||||
# this is very unrestrictive; cast is allowed if castDest.size >= src.size
|
# this is very unrestrictive; cast is allowed if castDest.size >= src.size
|
||||||
ds = computeSize(dst)
|
ds = computeSize(dst)
|
||||||
|
|
@ -232,7 +231,8 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
||||||
proc changeType(n: PNode, newType: PType) =
|
proc changeType(n: PNode, newType: PType) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCurly, nkBracket:
|
of nkCurly, nkBracket:
|
||||||
for i in countup(0, sonsLen(n) - 1): changeType(n.sons[i], elemType(newType))
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
|
changeType(n.sons[i], elemType(newType))
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if newType.kind != tyTuple:
|
if newType.kind != tyTuple:
|
||||||
InternalError(n.info, "changeType: no tuple type for constructor")
|
InternalError(n.info, "changeType: no tuple type for constructor")
|
||||||
|
|
@ -350,8 +350,6 @@ proc isAssignable(n: PNode): TAssignableResult =
|
||||||
result = isAssignable(n.sons[0])
|
result = isAssignable(n.sons[0])
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
# Object and tuple conversions are still addressable, so we skip them
|
# Object and tuple conversions are still addressable, so we skip them
|
||||||
#if skipPtrsGeneric(n.sons[1].typ).kind in [tyOpenArray,
|
|
||||||
# tyTuple, tyObject] then
|
|
||||||
if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}:
|
if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}:
|
||||||
result = isAssignable(n.sons[1])
|
result = isAssignable(n.sons[1])
|
||||||
of nkHiddenDeref, nkDerefExpr:
|
of nkHiddenDeref, nkDerefExpr:
|
||||||
|
|
@ -643,6 +641,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0], {efAllowType} + flags)
|
n.sons[0] = semExprWithType(c, n.sons[0], {efAllowType} + flags)
|
||||||
|
if gCmd == cmdSuggest:
|
||||||
|
suggestFieldAccess(c, n.sons[0])
|
||||||
var i = considerAcc(n.sons[1])
|
var i = considerAcc(n.sons[1])
|
||||||
var ty = n.sons[0].Typ
|
var ty = n.sons[0].Typ
|
||||||
var f: PSym = nil
|
var f: PSym = nil
|
||||||
|
|
|
||||||
138
rod/seminst.nim
138
rod/seminst.nim
|
|
@ -7,35 +7,11 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This module does the instantiation of generic procs and types.
|
# This module does the instantiation of generic procs.
|
||||||
|
|
||||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
info: TLineInfo): PSym
|
info: TLineInfo): PSym
|
||||||
# generates an instantiated proc
|
# generates an instantiated proc
|
||||||
proc searchInstTypes(tab: TIdTable, key: PType): PType =
|
|
||||||
# returns nil if we need to declare this type
|
|
||||||
result = PType(IdTableGet(tab, key))
|
|
||||||
if (result == nil) and (tab.counter > 0):
|
|
||||||
# we have to do a slow linear search because types may need
|
|
||||||
# to be compared by their structure:
|
|
||||||
for h in countup(0, high(tab.data)):
|
|
||||||
var t = PType(tab.data[h].key)
|
|
||||||
if t != nil:
|
|
||||||
if key.containerId == t.containerID:
|
|
||||||
var match = true
|
|
||||||
for j in countup(0, sonsLen(t) - 1):
|
|
||||||
# XXX sameType is not really correct for nested generics?
|
|
||||||
if not sameType(t.sons[j], key.sons[j]):
|
|
||||||
match = false
|
|
||||||
break
|
|
||||||
if match:
|
|
||||||
return PType(tab.data[h].val)
|
|
||||||
|
|
||||||
proc containsGenericTypeIter(t: PType, closure: PObject): bool =
|
|
||||||
result = t.kind in GenericTypes
|
|
||||||
|
|
||||||
proc containsGenericType(t: PType): bool =
|
|
||||||
result = iterOverType(t, containsGenericTypeIter, nil)
|
|
||||||
|
|
||||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) =
|
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) =
|
||||||
if (n.kind != nkGenericParams):
|
if (n.kind != nkGenericParams):
|
||||||
|
|
@ -129,106 +105,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
c.p = oldP # restore
|
c.p = oldP # restore
|
||||||
c.module = oldMod
|
c.module = oldMod
|
||||||
dec(c.InstCounter)
|
dec(c.InstCounter)
|
||||||
|
|
||||||
proc checkConstructedType(info: TLineInfo, t: PType) =
|
|
||||||
if (tfAcyclic in t.flags) and (skipTypes(t, abstractInst).kind != tyObject):
|
|
||||||
LocalError(info, errInvalidPragmaX, "acyclic")
|
|
||||||
elif computeSize(t) < 0:
|
|
||||||
LocalError(info, errIllegalRecursionInTypeX, typeToString(t))
|
|
||||||
elif (t.kind == tyVar) and (t.sons[0].kind == tyVar):
|
|
||||||
LocalError(info, errVarVarTypeNotAllowed)
|
|
||||||
|
|
||||||
type
|
|
||||||
TReplTypeVars{.final.} = object
|
|
||||||
c*: PContext
|
|
||||||
typeMap*: TIdTable # map PType to PType
|
|
||||||
symMap*: TIdTable # map PSym to PSym
|
|
||||||
info*: TLineInfo
|
|
||||||
|
|
||||||
|
|
||||||
proc ReplaceTypeVarsT(cl: var TReplTypeVars, t: PType): PType
|
|
||||||
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
|
||||||
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
|
|
||||||
if n != nil:
|
|
||||||
result = copyNode(n)
|
|
||||||
result.typ = ReplaceTypeVarsT(cl, n.typ)
|
|
||||||
case n.kind
|
|
||||||
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
|
|
||||||
nil
|
|
||||||
of nkSym:
|
|
||||||
result.sym = ReplaceTypeVarsS(cl, n.sym)
|
|
||||||
else:
|
|
||||||
var length = sonsLen(n)
|
|
||||||
if length > 0:
|
|
||||||
newSons(result, length)
|
|
||||||
for i in countup(0, length - 1):
|
|
||||||
result.sons[i] = ReplaceTypeVarsN(cl, n.sons[i])
|
|
||||||
|
|
||||||
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
|
||||||
if s == nil: return nil
|
|
||||||
result = PSym(idTableGet(cl.symMap, s))
|
|
||||||
if result == nil:
|
|
||||||
result = copySym(s, false)
|
|
||||||
incl(result.flags, sfFromGeneric)
|
|
||||||
idTablePut(cl.symMap, s, result)
|
|
||||||
result.typ = ReplaceTypeVarsT(cl, s.typ)
|
|
||||||
result.owner = s.owner
|
|
||||||
result.ast = ReplaceTypeVarsN(cl, s.ast)
|
|
||||||
|
|
||||||
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
|
|
||||||
result = PType(idTableGet(cl.typeMap, t))
|
|
||||||
if result == nil:
|
|
||||||
GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t))
|
|
||||||
elif result.kind == tyGenericParam:
|
|
||||||
InternalError(cl.info, "substitution with generic parameter")
|
|
||||||
|
|
||||||
proc ReplaceTypeVarsT(cl: var TReplTypeVars, t: PType): PType =
|
|
||||||
var body, newbody, x, header: PType
|
|
||||||
result = t
|
|
||||||
if t == nil: return
|
|
||||||
case t.kind
|
|
||||||
of tyGenericParam:
|
|
||||||
result = lookupTypeVar(cl, t)
|
|
||||||
of tyGenericInvokation:
|
|
||||||
body = t.sons[0]
|
|
||||||
if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
|
|
||||||
header = nil
|
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
|
||||||
if t.sons[i].kind == tyGenericParam:
|
|
||||||
x = lookupTypeVar(cl, t.sons[i])
|
|
||||||
if header == nil: header = copyType(t, t.owner, false)
|
|
||||||
header.sons[i] = x
|
|
||||||
else:
|
|
||||||
x = t.sons[i]
|
|
||||||
idTablePut(cl.typeMap, body.sons[i - 1], x)
|
|
||||||
if header == nil: header = t
|
|
||||||
result = searchInstTypes(gInstTypes, header)
|
|
||||||
if result != nil: return
|
|
||||||
result = newType(tyGenericInst, t.sons[0].owner)
|
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
|
||||||
# if one of the params is not concrete, we cannot do anything
|
|
||||||
# but we already raised an error!
|
|
||||||
addSon(result, header.sons[i])
|
|
||||||
idTablePut(gInstTypes, header, result)
|
|
||||||
newbody = ReplaceTypeVarsT(cl, lastSon(body))
|
|
||||||
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
|
|
||||||
addSon(result, newbody)
|
|
||||||
#writeln(output, ropeToStr(Typetoyaml(newbody)));
|
|
||||||
checkConstructedType(cl.info, newbody)
|
|
||||||
of tyGenericBody:
|
|
||||||
InternalError(cl.info, "ReplaceTypeVarsT: tyGenericBody")
|
|
||||||
result = ReplaceTypeVarsT(cl, lastSon(t))
|
|
||||||
else:
|
|
||||||
if containsGenericType(t):
|
|
||||||
result = copyType(t, t.owner, false)
|
|
||||||
for i in countup(0, sonsLen(result) - 1):
|
|
||||||
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
|
|
||||||
result.n = ReplaceTypeVarsN(cl, result.n)
|
|
||||||
if result.Kind in GenericTypes:
|
|
||||||
LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
|
|
||||||
#writeln(output, ropeToStr(Typetoyaml(result)))
|
|
||||||
#checkConstructedType(cl.info, result)
|
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||||
var cl: TReplTypeVars
|
var cl: TReplTypeVars
|
||||||
InitIdTable(cl.symMap)
|
InitIdTable(cl.symMap)
|
||||||
|
|
@ -237,14 +114,3 @@ proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||||
cl.c = c
|
cl.c = c
|
||||||
result = ReplaceTypeVarsT(cl, header)
|
result = ReplaceTypeVarsT(cl, header)
|
||||||
|
|
||||||
proc generateTypeInstance(p: PContext, pt: TIdTable, arg: PNode,
|
|
||||||
t: PType): PType =
|
|
||||||
var cl: TReplTypeVars
|
|
||||||
InitIdTable(cl.symMap)
|
|
||||||
copyIdTable(cl.typeMap, pt)
|
|
||||||
cl.info = arg.info
|
|
||||||
cl.c = p
|
|
||||||
pushInfoContext(arg.info)
|
|
||||||
result = ReplaceTypeVarsT(cl, t)
|
|
||||||
popInfoContext()
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
elif (sfMinus in allowed) and (v.id == ord(wMinus)):
|
elif (sfMinus in allowed) and (v.id == ord(wMinus)):
|
||||||
incl(result.flags, sfMinus)
|
incl(result.flags, sfMinus)
|
||||||
else:
|
else:
|
||||||
GlobalError(n.sons[0].info, errInvalidVisibilityX, v.s)
|
LocalError(n.sons[0].info, errInvalidVisibilityX, v.s)
|
||||||
else:
|
else:
|
||||||
illFormedAst(n)
|
illFormedAst(n)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
147
rod/semtypinst.nim
Normal file
147
rod/semtypinst.nim
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nimrod Compiler
|
||||||
|
# (c) Copyright 2011 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This module does the instantiation of generic procs and types.
|
||||||
|
|
||||||
|
import ast, astalgo, msgs, types, semdata
|
||||||
|
|
||||||
|
proc checkConstructedType*(info: TLineInfo, t: PType) =
|
||||||
|
if (tfAcyclic in t.flags) and (skipTypes(t, abstractInst).kind != tyObject):
|
||||||
|
LocalError(info, errInvalidPragmaX, "acyclic")
|
||||||
|
elif computeSize(t) < 0:
|
||||||
|
LocalError(info, errIllegalRecursionInTypeX, typeToString(t))
|
||||||
|
elif (t.kind == tyVar) and (t.sons[0].kind == tyVar):
|
||||||
|
LocalError(info, errVarVarTypeNotAllowed)
|
||||||
|
|
||||||
|
proc containsGenericTypeIter(t: PType, closure: PObject): bool =
|
||||||
|
result = t.kind in GenericTypes
|
||||||
|
|
||||||
|
proc containsGenericType*(t: PType): bool =
|
||||||
|
result = iterOverType(t, containsGenericTypeIter, nil)
|
||||||
|
|
||||||
|
proc searchInstTypes(tab: TIdTable, key: PType): PType =
|
||||||
|
# returns nil if we need to declare this type
|
||||||
|
result = PType(IdTableGet(tab, key))
|
||||||
|
if (result == nil) and (tab.counter > 0):
|
||||||
|
# we have to do a slow linear search because types may need
|
||||||
|
# to be compared by their structure:
|
||||||
|
for h in countup(0, high(tab.data)):
|
||||||
|
var t = PType(tab.data[h].key)
|
||||||
|
if t != nil:
|
||||||
|
if key.containerId == t.containerID:
|
||||||
|
var match = true
|
||||||
|
for j in countup(0, sonsLen(t) - 1):
|
||||||
|
# XXX sameType is not really correct for nested generics?
|
||||||
|
if not sameType(t.sons[j], key.sons[j]):
|
||||||
|
match = false
|
||||||
|
break
|
||||||
|
if match:
|
||||||
|
return PType(tab.data[h].val)
|
||||||
|
|
||||||
|
type
|
||||||
|
TReplTypeVars* {.final.} = object
|
||||||
|
c*: PContext
|
||||||
|
typeMap*: TIdTable # map PType to PType
|
||||||
|
symMap*: TIdTable # map PSym to PSym
|
||||||
|
info*: TLineInfo
|
||||||
|
|
||||||
|
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
|
||||||
|
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
||||||
|
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
|
if n != nil:
|
||||||
|
result = copyNode(n)
|
||||||
|
result.typ = ReplaceTypeVarsT(cl, n.typ)
|
||||||
|
case n.kind
|
||||||
|
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||||
|
nil
|
||||||
|
of nkSym:
|
||||||
|
result.sym = ReplaceTypeVarsS(cl, n.sym)
|
||||||
|
else:
|
||||||
|
var length = sonsLen(n)
|
||||||
|
if length > 0:
|
||||||
|
newSons(result, length)
|
||||||
|
for i in countup(0, length - 1):
|
||||||
|
result.sons[i] = ReplaceTypeVarsN(cl, n.sons[i])
|
||||||
|
|
||||||
|
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
||||||
|
if s == nil: return nil
|
||||||
|
result = PSym(idTableGet(cl.symMap, s))
|
||||||
|
if result == nil:
|
||||||
|
result = copySym(s, false)
|
||||||
|
incl(result.flags, sfFromGeneric)
|
||||||
|
idTablePut(cl.symMap, s, result)
|
||||||
|
result.typ = ReplaceTypeVarsT(cl, s.typ)
|
||||||
|
result.owner = s.owner
|
||||||
|
result.ast = ReplaceTypeVarsN(cl, s.ast)
|
||||||
|
|
||||||
|
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
|
||||||
|
result = PType(idTableGet(cl.typeMap, t))
|
||||||
|
if result == nil:
|
||||||
|
GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t))
|
||||||
|
elif result.kind == tyGenericParam:
|
||||||
|
InternalError(cl.info, "substitution with generic parameter")
|
||||||
|
|
||||||
|
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
|
var body, newbody, x, header: PType
|
||||||
|
result = t
|
||||||
|
if t == nil: return
|
||||||
|
case t.kind
|
||||||
|
of tyGenericParam:
|
||||||
|
result = lookupTypeVar(cl, t)
|
||||||
|
of tyGenericInvokation:
|
||||||
|
body = t.sons[0]
|
||||||
|
if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
|
||||||
|
header = nil
|
||||||
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
|
if t.sons[i].kind == tyGenericParam:
|
||||||
|
x = lookupTypeVar(cl, t.sons[i])
|
||||||
|
if header == nil: header = copyType(t, t.owner, false)
|
||||||
|
header.sons[i] = x
|
||||||
|
else:
|
||||||
|
x = t.sons[i]
|
||||||
|
idTablePut(cl.typeMap, body.sons[i - 1], x)
|
||||||
|
if header == nil: header = t
|
||||||
|
result = searchInstTypes(gInstTypes, header)
|
||||||
|
if result != nil: return
|
||||||
|
result = newType(tyGenericInst, t.sons[0].owner)
|
||||||
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
|
# if one of the params is not concrete, we cannot do anything
|
||||||
|
# but we already raised an error!
|
||||||
|
addSon(result, header.sons[i])
|
||||||
|
idTablePut(gInstTypes, header, result)
|
||||||
|
newbody = ReplaceTypeVarsT(cl, lastSon(body))
|
||||||
|
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
|
||||||
|
addSon(result, newbody)
|
||||||
|
#writeln(output, ropeToStr(Typetoyaml(newbody)));
|
||||||
|
checkConstructedType(cl.info, newbody)
|
||||||
|
of tyGenericBody:
|
||||||
|
InternalError(cl.info, "ReplaceTypeVarsT: tyGenericBody")
|
||||||
|
result = ReplaceTypeVarsT(cl, lastSon(t))
|
||||||
|
else:
|
||||||
|
if containsGenericType(t):
|
||||||
|
result = copyType(t, t.owner, false)
|
||||||
|
for i in countup(0, sonsLen(result) - 1):
|
||||||
|
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
|
||||||
|
result.n = ReplaceTypeVarsN(cl, result.n)
|
||||||
|
if result.Kind in GenericTypes:
|
||||||
|
LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
|
||||||
|
#writeln(output, ropeToStr(Typetoyaml(result)))
|
||||||
|
#checkConstructedType(cl.info, result)
|
||||||
|
|
||||||
|
proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
|
||||||
|
t: PType): PType =
|
||||||
|
var cl: TReplTypeVars
|
||||||
|
InitIdTable(cl.symMap)
|
||||||
|
copyIdTable(cl.typeMap, pt)
|
||||||
|
cl.info = arg.info
|
||||||
|
cl.c = p
|
||||||
|
pushInfoContext(arg.info)
|
||||||
|
result = ReplaceTypeVarsT(cl, t)
|
||||||
|
popInfoContext()
|
||||||
|
|
||||||
121
rod/sigmatch.nim
121
rod/sigmatch.nim
|
|
@ -10,24 +10,28 @@
|
||||||
# This module implements the signature matching for resolving
|
# This module implements the signature matching for resolving
|
||||||
# the call to overloaded procs, generic procs and operators.
|
# the call to overloaded procs, generic procs and operators.
|
||||||
|
|
||||||
|
import
|
||||||
|
ast, astalgo, semdata, types, msgs, rnimsyn, lookups, semtypinst,
|
||||||
|
magicsys
|
||||||
|
|
||||||
type
|
type
|
||||||
TCandidateState = enum
|
TCandidateState* = enum
|
||||||
csEmpty, csMatch, csNoMatch
|
csEmpty, csMatch, csNoMatch
|
||||||
TCandidate{.final.} = object
|
TCandidate* {.final.} = object
|
||||||
exactMatches: int
|
exactMatches: int
|
||||||
subtypeMatches: int
|
subtypeMatches: int
|
||||||
intConvMatches: int # conversions to int are not as expensive
|
intConvMatches: int # conversions to int are not as expensive
|
||||||
convMatches: int
|
convMatches: int
|
||||||
genericMatches: int
|
genericMatches: int
|
||||||
state: TCandidateState
|
state*: TCandidateState
|
||||||
callee: PType # may not be nil!
|
callee*: PType # may not be nil!
|
||||||
calleeSym: PSym # may be nil
|
calleeSym*: PSym # may be nil
|
||||||
call: PNode # modified call
|
call*: PNode # modified call
|
||||||
bindings: TIdTable # maps sym-ids to types
|
bindings*: TIdTable # maps sym-ids to types
|
||||||
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
||||||
# for example
|
# for example
|
||||||
|
|
||||||
TTypeRelation = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
isNone, isConvertible, isIntConv, isSubtype, isGeneric, isEqual
|
isNone, isConvertible, isIntConv, isSubtype, isGeneric, isEqual
|
||||||
|
|
||||||
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||||
|
|
@ -41,12 +45,12 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||||
c.call = nil
|
c.call = nil
|
||||||
c.baseTypeMatch = false
|
c.baseTypeMatch = false
|
||||||
|
|
||||||
proc initCandidate(c: var TCandidate, callee: PType) =
|
proc initCandidate*(c: var TCandidate, callee: PType) =
|
||||||
initCandidateAux(c, callee)
|
initCandidateAux(c, callee)
|
||||||
c.calleeSym = nil
|
c.calleeSym = nil
|
||||||
initIdTable(c.bindings)
|
initIdTable(c.bindings)
|
||||||
|
|
||||||
proc initCandidate(c: var TCandidate, callee: PSym, binding: PNode) =
|
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode) =
|
||||||
initCandidateAux(c, callee.typ)
|
initCandidateAux(c, callee.typ)
|
||||||
c.calleeSym = callee
|
c.calleeSym = callee
|
||||||
initIdTable(c.bindings)
|
initIdTable(c.bindings)
|
||||||
|
|
@ -70,7 +74,7 @@ proc copyCandidate(a: var TCandidate, b: TCandidate) =
|
||||||
a.baseTypeMatch = b.baseTypeMatch
|
a.baseTypeMatch = b.baseTypeMatch
|
||||||
copyIdTable(a.bindings, b.bindings)
|
copyIdTable(a.bindings, b.bindings)
|
||||||
|
|
||||||
proc cmpCandidates(a, b: TCandidate): int =
|
proc cmpCandidates*(a, b: TCandidate): int =
|
||||||
result = a.exactMatches - b.exactMatches
|
result = a.exactMatches - b.exactMatches
|
||||||
if result != 0: return
|
if result != 0: return
|
||||||
result = a.genericMatches - b.genericMatches
|
result = a.genericMatches - b.genericMatches
|
||||||
|
|
@ -88,7 +92,7 @@ proc writeMatches(c: TCandidate) =
|
||||||
Writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
Writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
||||||
Writeln(stdout, "generic matches: " & $c.genericMatches)
|
Writeln(stdout, "generic matches: " & $c.genericMatches)
|
||||||
|
|
||||||
proc getNotFoundError(c: PContext, n: PNode): string =
|
proc getNotFoundError*(c: PContext, n: PNode): string =
|
||||||
# Gives a detailed error message; this is separated from semDirectCall,
|
# Gives a detailed error message; this is separated from semDirectCall,
|
||||||
# as semDirectCall is already pretty slow (and we need this information only
|
# as semDirectCall is already pretty slow (and we need this information only
|
||||||
# in case of an error).
|
# in case of an error).
|
||||||
|
|
@ -425,7 +429,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
else: nil
|
else: nil
|
||||||
else: internalError("typeRel(" & $f.kind & ')')
|
else: internalError("typeRel(" & $f.kind & ')')
|
||||||
|
|
||||||
proc cmpTypes(f, a: PType): TTypeRelation =
|
proc cmpTypes*(f, a: PType): TTypeRelation =
|
||||||
var mapping: TIdTable
|
var mapping: TIdTable
|
||||||
InitIdTable(mapping)
|
InitIdTable(mapping)
|
||||||
result = typeRel(mapping, f, a)
|
result = typeRel(mapping, f, a)
|
||||||
|
|
@ -552,7 +556,7 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
markUsed(arg, arg.sons[best].sym)
|
markUsed(arg, arg.sons[best].sym)
|
||||||
result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best])
|
result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best])
|
||||||
|
|
||||||
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
|
proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode =
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
initCandidate(m, f)
|
initCandidate(m, f)
|
||||||
result = paramTypesMatch(c, m, f, a, arg)
|
result = paramTypesMatch(c, m, f, a, arg)
|
||||||
|
|
@ -561,7 +565,7 @@ proc setSon(father: PNode, at: int, son: PNode) =
|
||||||
if sonsLen(father) <= at: setlen(father.sons, at + 1)
|
if sonsLen(father) <= at: setlen(father.sons, at + 1)
|
||||||
father.sons[at] = son
|
father.sons[at] = son
|
||||||
|
|
||||||
proc matches(c: PContext, n: PNode, m: var TCandidate) =
|
proc matches*(c: PContext, n: PNode, m: var TCandidate) =
|
||||||
var f = 1 # iterates over formal parameters
|
var f = 1 # iterates over formal parameters
|
||||||
var a = 1 # iterates over the actual given arguments
|
var a = 1 # iterates over the actual given arguments
|
||||||
m.state = csMatch # until proven otherwise
|
m.state = csMatch # until proven otherwise
|
||||||
|
|
@ -670,90 +674,3 @@ proc matches(c: PContext, n: PNode, m: var TCandidate) =
|
||||||
setSon(m.call, formal.position + 1, copyTree(formal.ast))
|
setSon(m.call, formal.position + 1, copyTree(formal.ast))
|
||||||
inc(f)
|
inc(f)
|
||||||
|
|
||||||
proc sameMethodDispatcher(a, b: PSym): bool =
|
|
||||||
result = false
|
|
||||||
if a.kind == skMethod and b.kind == skMethod:
|
|
||||||
var aa = lastSon(a.ast)
|
|
||||||
var bb = lastSon(b.ast)
|
|
||||||
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym:
|
|
||||||
result = true
|
|
||||||
|
|
||||||
proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
|
|
||||||
initialBinding: PNode): PNode =
|
|
||||||
var
|
|
||||||
o: TOverloadIter
|
|
||||||
x, y, z: TCandidate
|
|
||||||
#Message(n.info, warnUser, renderTree(n))
|
|
||||||
var sym = initOverloadIter(o, c, f)
|
|
||||||
result = nil
|
|
||||||
if sym == nil: return
|
|
||||||
initCandidate(x, sym, initialBinding)
|
|
||||||
initCandidate(y, sym, initialBinding)
|
|
||||||
|
|
||||||
while sym != nil:
|
|
||||||
if sym.kind in filter:
|
|
||||||
initCandidate(z, sym, initialBinding)
|
|
||||||
z.calleeSym = sym
|
|
||||||
matches(c, n, z)
|
|
||||||
if z.state == csMatch:
|
|
||||||
case x.state
|
|
||||||
of csEmpty, csNoMatch: x = z
|
|
||||||
of csMatch:
|
|
||||||
var cmp = cmpCandidates(x, z)
|
|
||||||
if cmp < 0: x = z # z is better than x
|
|
||||||
elif cmp == 0: y = z # z is as good as x
|
|
||||||
else: nil
|
|
||||||
sym = nextOverloadIter(o, c, f)
|
|
||||||
if x.state == csEmpty:
|
|
||||||
# no overloaded proc found
|
|
||||||
# do not generate an error yet; the semantic checking will check for
|
|
||||||
# an overloaded () operator
|
|
||||||
elif y.state == csMatch and cmpCandidates(x, y) == 0 and
|
|
||||||
not sameMethodDispatcher(x.calleeSym, y.calleeSym):
|
|
||||||
if x.state != csMatch:
|
|
||||||
InternalError(n.info, "x.state is not csMatch")
|
|
||||||
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
|
|
||||||
getProcHeader(x.calleeSym), getProcHeader(y.calleeSym),
|
|
||||||
x.calleeSym.Name.s])
|
|
||||||
else:
|
|
||||||
# only one valid interpretation found:
|
|
||||||
markUsed(n, x.calleeSym)
|
|
||||||
if x.calleeSym.ast == nil:
|
|
||||||
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
|
|
||||||
if x.calleeSym.ast.sons[genericParamsPos].kind != nkEmpty:
|
|
||||||
# a generic proc!
|
|
||||||
x.calleeSym = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
|
||||||
x.callee = x.calleeSym.typ
|
|
||||||
result = x.call
|
|
||||||
result.sons[0] = newSymNode(x.calleeSym)
|
|
||||||
result.typ = x.callee.sons[0]
|
|
||||||
|
|
||||||
proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
|
|
||||||
# process the bindings once:
|
|
||||||
var initialBinding: PNode
|
|
||||||
var f = n.sons[0]
|
|
||||||
if f.kind == nkBracketExpr:
|
|
||||||
# fill in the bindings:
|
|
||||||
initialBinding = f
|
|
||||||
f = f.sons[0]
|
|
||||||
else:
|
|
||||||
initialBinding = nil
|
|
||||||
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
|
|
||||||
|
|
||||||
proc explictGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
|
||||||
assert n.kind == nkBracketExpr
|
|
||||||
for i in 1..sonsLen(n)-1:
|
|
||||||
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
|
|
||||||
# we cannot check for the proper number of type parameters because in
|
|
||||||
# `f[a,b](x, y)` `f` is not resolved yet properly.
|
|
||||||
# XXX: BUG this should be checked somehow!
|
|
||||||
assert n.sons[0].kind == nkSym
|
|
||||||
|
|
||||||
var x: TCandidate
|
|
||||||
initCandidate(x, s, n)
|
|
||||||
var newInst = generateInstance(c, s, x.bindings, n.info)
|
|
||||||
|
|
||||||
markUsed(n, s)
|
|
||||||
result = newSymNode(newInst)
|
|
||||||
result.info = n.info
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
## This file implements features required for IDE support.
|
## This file implements features required for IDE support.
|
||||||
|
|
||||||
import scanner, ast, astalgo, semdata, msgs, types
|
import scanner, ast, astalgo, semdata, msgs, types, sigmatch
|
||||||
|
|
||||||
const
|
const
|
||||||
sep = '\t'
|
sep = '\t'
|
||||||
|
|
@ -33,23 +33,83 @@ proc SymToStr(s: PSym, isLocal: bool): string =
|
||||||
result.add(sep)
|
result.add(sep)
|
||||||
result.add($ToColumn(s.info))
|
result.add($ToColumn(s.info))
|
||||||
|
|
||||||
proc suggestSym(s: PSym): bool {.inline.} =
|
proc filterSym(s: PSym): bool {.inline.} =
|
||||||
result = s.name.s[0] in scanner.SymChars
|
result = s.name.s[0] in scanner.SymChars
|
||||||
|
|
||||||
|
proc suggestField(s: PSym) =
|
||||||
|
if filterSym(s):
|
||||||
|
MessageOut(SymToStr(s, isLocal=true))
|
||||||
|
|
||||||
proc suggestExpr*(c: PContext, n: PNode) =
|
proc suggestExpr*(c: PContext, n: PNode) =
|
||||||
if not msgs.inCheckpoint(n.info): return
|
if not msgs.inCheckpoint(n.info): return
|
||||||
|
|
||||||
for i in countdown(c.tab.tos-1, 0):
|
for i in countdown(c.tab.tos-1, 0):
|
||||||
for it in items(c.tab.stack[i]):
|
for it in items(c.tab.stack[i]):
|
||||||
if suggestSym(it):
|
if filterSym(it):
|
||||||
MessageOut(SymToStr(it, i > ModuleTablePos))
|
MessageOut(SymToStr(it, isLocal = i > ModuleTablePos))
|
||||||
quit(0)
|
quit(0)
|
||||||
|
|
||||||
proc suggestStmt*(c: PContext, n: PNode) =
|
proc suggestStmt*(c: PContext, n: PNode) =
|
||||||
suggestExpr(c, n)
|
suggestExpr(c, n)
|
||||||
|
|
||||||
|
proc suggestSymList(list: PNode) =
|
||||||
|
for i in countup(0, sonsLen(list) - 1):
|
||||||
|
if list.sons[i].kind != nkSym: InternalError(list.info, "getSymFromList")
|
||||||
|
suggestField(list.sons[i].sym)
|
||||||
|
|
||||||
|
proc suggestObject(n: PNode) =
|
||||||
|
case n.kind
|
||||||
|
of nkRecList:
|
||||||
|
for i in countup(0, sonsLen(n) - 1): suggestObject(n.sons[i])
|
||||||
|
of nkRecCase:
|
||||||
|
var L = sonsLen(n)
|
||||||
|
if L > 0:
|
||||||
|
suggestObject(n.sons[0])
|
||||||
|
for i in countup(1, L-1):
|
||||||
|
suggestObject(lastSon(n.sons[i]))
|
||||||
|
of nkSym: suggestField(n.sym)
|
||||||
|
else: nil
|
||||||
|
|
||||||
|
proc suggestOperations(c: PContext, n: PNode, typ: PType) =
|
||||||
|
nil
|
||||||
|
|
||||||
proc suggestFieldAccess*(c: PContext, n: PNode) =
|
proc suggestFieldAccess*(c: PContext, n: PNode) =
|
||||||
suggestExpr(c, n)
|
# special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but
|
||||||
# XXX provide a better implementation based on n[0].typ
|
# ``myObj``.
|
||||||
|
var typ = n.Typ
|
||||||
|
if typ == nil:
|
||||||
|
# a module symbol has no type for example:
|
||||||
|
if n.kind == nkSym and n.sym.kind == skModule:
|
||||||
|
if n.sym == c.module:
|
||||||
|
# all symbols accessible, because we are in the current module:
|
||||||
|
for it in items(c.tab.stack[ModuleTablePos]):
|
||||||
|
if filterSym(it): MessageOut(SymToStr(it, isLocal=false))
|
||||||
|
else:
|
||||||
|
for it in items(n.sym.tab):
|
||||||
|
if filterSym(it): MessageOut(SymToStr(it, isLocal=false))
|
||||||
|
else:
|
||||||
|
# fallback:
|
||||||
|
suggestExpr(c, n)
|
||||||
|
elif typ.kind == tyEnum:
|
||||||
|
# look up if the identifier belongs to the enum:
|
||||||
|
var t = typ
|
||||||
|
while t != nil:
|
||||||
|
suggestSymList(t.n)
|
||||||
|
t = t.sons[0]
|
||||||
|
suggestOperations(c, n, typ)
|
||||||
|
else:
|
||||||
|
typ = skipTypes(typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||||
|
if typ.kind == tyObject:
|
||||||
|
var t = typ
|
||||||
|
while true:
|
||||||
|
suggestObject(t.n)
|
||||||
|
if t.sons[0] == nil: break
|
||||||
|
t = skipTypes(t.sons[0], {tyGenericInst})
|
||||||
|
suggestOperations(c, n, typ)
|
||||||
|
elif typ.kind == tyTuple and typ.n != nil:
|
||||||
|
suggestSymList(typ.n)
|
||||||
|
suggestOperations(c, n, typ)
|
||||||
|
else:
|
||||||
|
# fallback:
|
||||||
|
suggestExpr(c, n)
|
||||||
|
|
||||||
|
|
|
||||||
57
tests/accept/run/tgenerics1.nim
Executable file
57
tests/accept/run/tgenerics1.nim
Executable file
|
|
@ -0,0 +1,57 @@
|
||||||
|
discard """
|
||||||
|
output: "256 100"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# A min-heap.
|
||||||
|
type
|
||||||
|
TNode[T] = tuple[priority: int, data: T]
|
||||||
|
|
||||||
|
TBinHeap[T] = object
|
||||||
|
heap: seq[TNode[T]]
|
||||||
|
last: int
|
||||||
|
|
||||||
|
PBinHeap[T] = ref TBinHeap[T]
|
||||||
|
|
||||||
|
proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
|
||||||
|
new(heap)
|
||||||
|
heap.last = 0
|
||||||
|
newSeq(heap.seq, size)
|
||||||
|
|
||||||
|
when false:
|
||||||
|
|
||||||
|
proc parent(elem: int): int =
|
||||||
|
return (elem-1) div 2
|
||||||
|
|
||||||
|
proc siftUp[T](heap: PBinHeap[T], elem: int) =
|
||||||
|
var idx = elem
|
||||||
|
while idx != 0:
|
||||||
|
var p = parent(idx)
|
||||||
|
if heap.heap[idx] < heap.heap[p]:
|
||||||
|
var tmp = heap.heap[idx]
|
||||||
|
heap.heap[idx] = heap.heap[p]
|
||||||
|
heap.heap[p] = tmp
|
||||||
|
idx = p
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
|
||||||
|
var node: TNode
|
||||||
|
new(node)
|
||||||
|
node.priority = int
|
||||||
|
node.data = data
|
||||||
|
heap.heap[heap.last] = node
|
||||||
|
siftUp(heap, heap.last)
|
||||||
|
inc(heap.last)
|
||||||
|
|
||||||
|
proc print*[T](heap: PBinHeap[T]) =
|
||||||
|
for i in countup(0, heap.last):
|
||||||
|
echo($heap.heap[i])
|
||||||
|
|
||||||
|
var
|
||||||
|
heap: PBinHeap[int]
|
||||||
|
|
||||||
|
newBinHeap(heap, 256)
|
||||||
|
add(heap, 1, 100)
|
||||||
|
print(heap)
|
||||||
|
|
||||||
|
|
||||||
32
tests/accept/run/tmacros1.nim
Normal file
32
tests/accept/run/tmacros1.nim
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
discard """
|
||||||
|
output: "hellow"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import
|
||||||
|
macros, strutils
|
||||||
|
|
||||||
|
macro outterMacro*(n: stmt): stmt =
|
||||||
|
var j : string = "hi"
|
||||||
|
proc innerProc(i: int): string =
|
||||||
|
echo "Using arg ! " & n.repr
|
||||||
|
result = "Got: '" & $n.kind & "' " & $j
|
||||||
|
if n.kind != TNimrodNodeKind.nnkMacroStmt:
|
||||||
|
error("Macro " & n[0].repr & " requires a block.")
|
||||||
|
var callNode = n[0]
|
||||||
|
expectKind(callNode, TNimrodNodeKind.nnkCall)
|
||||||
|
if callNode.len != 2 or callNode[1].kind != TNimrodNodeKind.nnkIdent:
|
||||||
|
error("Macro " & callNode.repr &
|
||||||
|
" requires the ident passed as parameter (eg: " & callNode.repr &
|
||||||
|
"(the_name_you_want)): statements.")
|
||||||
|
result = newNimNode(TNimrodNodeKind.nnkStmtList)
|
||||||
|
var ass : PNimrodNode = newNimNode(TNimrodNodeKind.nnkAsgn)
|
||||||
|
ass.add(newIdentNode(callNode[1].ident))
|
||||||
|
ass.add(newStrLitNode(innerProc(4)))
|
||||||
|
result.add(ass)
|
||||||
|
|
||||||
|
var str: string
|
||||||
|
outterMacro(str):
|
||||||
|
"hellow"
|
||||||
|
echo str
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue