lazy operand sem'checking (beware)
This commit is contained in:
parent
dc07732daa
commit
eebee0eff2
6 changed files with 88 additions and 43 deletions
|
|
@ -19,13 +19,9 @@ import
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
type
|
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
|
||||||
TExprFlag = enum
|
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.
|
||||||
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
|
procvar.}
|
||||||
TExprFlags = set[TExprFlag]
|
|
||||||
|
|
||||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
|
||||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
|
||||||
proc semExprNoType(c: PContext, n: PNode): PNode
|
proc semExprNoType(c: PContext, n: PNode): PNode
|
||||||
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
proc semProcBody(c: PContext, n: PNode): PNode
|
proc semProcBody(c: PContext, n: PNode): PNode
|
||||||
|
|
@ -200,14 +196,12 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
|
||||||
addSon(n, prc.ast)
|
addSon(n, prc.ast)
|
||||||
c.lastGenericIdx = c.generics.len
|
c.lastGenericIdx = c.generics.len
|
||||||
|
|
||||||
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
|
|
||||||
result = semExpr(c, n, {})
|
|
||||||
|
|
||||||
proc myOpen(module: PSym): PPassContext =
|
proc myOpen(module: PSym): PPassContext =
|
||||||
var c = newContext(module)
|
var c = newContext(module)
|
||||||
if c.p != nil: InternalError(module.info, "sem.myOpen")
|
if c.p != nil: InternalError(module.info, "sem.myOpen")
|
||||||
c.semConstExpr = semConstExpr
|
c.semConstExpr = semConstExpr
|
||||||
c.semExpr = semExprNoFlags
|
c.semExpr = semExpr
|
||||||
|
c.semExprWithType = semExprWithType
|
||||||
c.semConstBoolExpr = semConstBoolExpr
|
c.semConstBoolExpr = semConstBoolExpr
|
||||||
c.semOverloadedCall = semOverloadedCall
|
c.semOverloadedCall = semOverloadedCall
|
||||||
c.semTypeNode = semTypeNode
|
c.semTypeNode = semTypeNode
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@ type
|
||||||
genericSym*: PSym
|
genericSym*: PSym
|
||||||
inst*: PInstantiation
|
inst*: PInstantiation
|
||||||
|
|
||||||
|
TExprFlag* = enum
|
||||||
|
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
|
||||||
|
TExprFlags* = set[TExprFlag]
|
||||||
|
|
||||||
PContext* = ref TContext
|
PContext* = ref TContext
|
||||||
TContext* = object of TPassContext # a context represents a module
|
TContext* = object of TPassContext # a context represents a module
|
||||||
module*: PSym # the module sym belonging to the context
|
module*: PSym # the module sym belonging to the context
|
||||||
|
|
@ -64,7 +68,8 @@ type
|
||||||
# to some new symbol in a generic instantiation
|
# to some new symbol in a generic instantiation
|
||||||
libs*: TLinkedList # all libs used by this module
|
libs*: TLinkedList # all libs used by this module
|
||||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||||
semExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
|
semExprWithType*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||||
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
||||||
filter: TSymKinds): PNode {.nimcall.}
|
filter: TSymKinds): PNode {.nimcall.}
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,6 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
||||||
|
|
||||||
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
|
|
||||||
proc newDeref(n: PNode): PNode {.inline.} =
|
|
||||||
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
|
|
||||||
addSon(result, n)
|
|
||||||
|
|
||||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = semExpr(c, n, flags)
|
result = semExpr(c, n, flags)
|
||||||
if result.kind == nkEmpty:
|
if result.kind == nkEmpty:
|
||||||
|
|
@ -319,7 +315,7 @@ proc semIs(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
proc semOpAux(c: PContext, n: PNode) =
|
proc semOpAux(c: PContext, n: PNode) =
|
||||||
const flags = {efDetermineType}
|
const flags = {efDetermineType}
|
||||||
for i in countup(1, n.sonsLen- 1):
|
for i in countup(1, n.sonsLen-1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
|
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
|
||||||
var info = a.sons[0].info
|
var info = a.sons[0].info
|
||||||
|
|
@ -694,7 +690,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# this seems to be a hotspot in the compiler!
|
# this seems to be a hotspot in the compiler!
|
||||||
let nOrig = n.copyTree
|
let nOrig = n.copyTree
|
||||||
semOpAux(c, n)
|
#semLazyOpAux(c, n)
|
||||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = overloadedCallOpr(c, n)
|
result = overloadedCallOpr(c, n)
|
||||||
|
|
@ -706,6 +702,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
of skMacro: result = semMacroExpr(c, result, nOrig, callee)
|
of skMacro: result = semMacroExpr(c, result, nOrig, callee)
|
||||||
of skTemplate: result = semTemplateExpr(c, result, callee)
|
of skTemplate: result = semTemplateExpr(c, result, callee)
|
||||||
else:
|
else:
|
||||||
|
semFinishOperands(c, n)
|
||||||
activate(c, n)
|
activate(c, n)
|
||||||
fixAbstractType(c, result)
|
fixAbstractType(c, result)
|
||||||
analyseIfAddressTakenInCall(c, result)
|
analyseIfAddressTakenInCall(c, result)
|
||||||
|
|
@ -845,12 +842,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
return semSym(c, n, s, flags)
|
return semSym(c, n, s, flags)
|
||||||
|
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0], flags)
|
n.sons[0] = semExprWithType(c, n.sons[0], flags)
|
||||||
restoreOldStyleType(n.sons[0])
|
#restoreOldStyleType(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
|
||||||
result = nil
|
result = nil
|
||||||
if isTypeExpr(n.sons[0]):
|
if isTypeExpr(n.sons[0]) or ty.kind == tyTypeDesc and ty.len == 1:
|
||||||
|
if ty.kind == tyTypeDesc: ty = ty.sons[0]
|
||||||
case ty.kind
|
case ty.kind
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
# look up if the identifier belongs to the enum:
|
# look up if the identifier belongs to the enum:
|
||||||
|
|
|
||||||
|
|
@ -484,10 +484,17 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
||||||
n.sons[length-1] = SemStmt(c, n.sons[length-1])
|
n.sons[length-1] = SemStmt(c, n.sons[length-1])
|
||||||
Dec(c.p.nestedLoopCounter)
|
Dec(c.p.nestedLoopCounter)
|
||||||
|
|
||||||
|
proc newDeref(n: PNode): PNode {.inline.} =
|
||||||
|
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
|
||||||
|
addSon(result, n)
|
||||||
|
|
||||||
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
|
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
|
||||||
result = newNodeI(nkCall, arg.info)
|
result = newNodeI(nkCall, arg.info)
|
||||||
result.add(newIdentNode(it.getIdent, arg.info))
|
result.add(newIdentNode(it.getIdent, arg.info))
|
||||||
result.add(arg)
|
if arg.typ != nil and arg.typ.kind == tyVar:
|
||||||
|
result.add newDeref(arg)
|
||||||
|
else:
|
||||||
|
result.add arg
|
||||||
result = semExprNoDeref(c, result, {efWantIterator})
|
result = semExprNoDeref(c, result, {efWantIterator})
|
||||||
|
|
||||||
proc semFor(c: PContext, n: PNode): PNode =
|
proc semFor(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -776,8 +783,7 @@ proc activate(c: PContext, n: PNode) =
|
||||||
# XXX: This proc is part of my plan for getting rid of
|
# XXX: This proc is part of my plan for getting rid of
|
||||||
# forward declarations. stay tuned.
|
# forward declarations. stay tuned.
|
||||||
when false:
|
when false:
|
||||||
# well for now it breaks code ... I added the test case in main.nim of the
|
# well for now it breaks code ...
|
||||||
# compiler itself to break bootstrapping :P
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkLambdaKinds:
|
of nkLambdaKinds:
|
||||||
discard semLambda(c, n, {})
|
discard semLambda(c, n, {})
|
||||||
|
|
@ -1142,8 +1148,8 @@ proc instantiateDestructor*(c: PContext, typ: PType): bool =
|
||||||
else:
|
else:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc insertDestructors(c: PContext, varSection: PNode):
|
proc insertDestructors(c: PContext,
|
||||||
tuple[outer: PNode, inner: PNode] =
|
varSection: PNode): tuple[outer, inner: PNode] =
|
||||||
# Accepts a var or let section.
|
# Accepts a var or let section.
|
||||||
#
|
#
|
||||||
# When a var section has variables with destructors
|
# When a var section has variables with destructors
|
||||||
|
|
|
||||||
|
|
@ -799,6 +799,28 @@ 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
|
||||||
|
|
||||||
|
# we are allowed to modify the calling node in the 'prepare*' procs:
|
||||||
|
proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
|
||||||
|
if formal.kind == tyExpr and formal.len != 1:
|
||||||
|
# {tyTypeDesc, tyExpr, tyStmt, tyProxy}:
|
||||||
|
# a.typ == nil is valid
|
||||||
|
result = a
|
||||||
|
elif a.typ.isNil:
|
||||||
|
result = c.semExprWithType(c, a, {efDetermineType})
|
||||||
|
else:
|
||||||
|
result = a
|
||||||
|
|
||||||
|
proc prepareOperand(c: PContext; a: PNode): PNode =
|
||||||
|
if a.typ.isNil:
|
||||||
|
result = c.semExprWithType(c, a, {efDetermineType})
|
||||||
|
else:
|
||||||
|
result = a
|
||||||
|
|
||||||
|
proc prepareNamedParam(a: PNode) =
|
||||||
|
if a.sons[0].kind != nkIdent:
|
||||||
|
var info = a.sons[0].info
|
||||||
|
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
|
||||||
|
|
||||||
proc matchesAux(c: PContext, n, nOrig: PNode,
|
proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
m: var TCandidate, marker: var TIntSet) =
|
m: var TCandidate, marker: var TIntSet) =
|
||||||
template checkConstraint(n: expr) {.immediate, dirty.} =
|
template checkConstraint(n: expr) {.immediate, dirty.} =
|
||||||
|
|
@ -823,6 +845,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
if n.sons[a].kind == nkExprEqExpr:
|
if n.sons[a].kind == nkExprEqExpr:
|
||||||
# named param
|
# named param
|
||||||
# check if m.callee has such a param:
|
# check if m.callee has such a param:
|
||||||
|
prepareNamedParam(n.sons[a])
|
||||||
if n.sons[a].sons[0].kind != nkIdent:
|
if n.sons[a].sons[0].kind != nkIdent:
|
||||||
LocalError(n.sons[a].info, errNamedParamHasToBeIdent)
|
LocalError(n.sons[a].info, errNamedParamHasToBeIdent)
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
|
|
@ -838,6 +861,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
m.baseTypeMatch = false
|
m.baseTypeMatch = false
|
||||||
|
n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
|
||||||
|
n.sons[a].typ = n.sons[a].sons[1].typ
|
||||||
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
||||||
n.sons[a].sons[1], nOrig.sons[a].sons[1])
|
n.sons[a].sons[1], nOrig.sons[a].sons[1])
|
||||||
if arg == nil:
|
if arg == nil:
|
||||||
|
|
@ -858,6 +883,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
# too many arguments?
|
# too many arguments?
|
||||||
if tfVarArgs in m.callee.flags:
|
if tfVarArgs in m.callee.flags:
|
||||||
# is ok... but don't increment any counters...
|
# is ok... but don't increment any counters...
|
||||||
|
# we have no formal here to snoop at:
|
||||||
|
n.sons[a] = prepareOperand(c, n.sons[a])
|
||||||
if skipTypes(n.sons[a].typ, abstractVar).kind == tyString:
|
if skipTypes(n.sons[a].typ, abstractVar).kind == tyString:
|
||||||
addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
|
addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
|
||||||
copyTree(n.sons[a]), m, c))
|
copyTree(n.sons[a]), m, c))
|
||||||
|
|
@ -865,6 +892,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
addSon(m.call, copyTree(n.sons[a]))
|
addSon(m.call, copyTree(n.sons[a]))
|
||||||
elif formal != nil:
|
elif formal != nil:
|
||||||
m.baseTypeMatch = false
|
m.baseTypeMatch = false
|
||||||
|
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||||
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
||||||
n.sons[a], nOrig.sons[a])
|
n.sons[a], nOrig.sons[a])
|
||||||
if (arg != nil) and m.baseTypeMatch and (container != nil):
|
if (arg != nil) and m.baseTypeMatch and (container != nil):
|
||||||
|
|
@ -886,6 +914,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
m.baseTypeMatch = false
|
m.baseTypeMatch = false
|
||||||
|
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||||
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
||||||
n.sons[a], nOrig.sons[a])
|
n.sons[a], nOrig.sons[a])
|
||||||
if arg == nil:
|
if arg == nil:
|
||||||
|
|
@ -904,6 +933,12 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
inc(a)
|
inc(a)
|
||||||
inc(f)
|
inc(f)
|
||||||
|
|
||||||
|
proc semFinishOperands*(c: PContext, n: PNode) =
|
||||||
|
# this needs to be called to ensure that after overloading resolution every
|
||||||
|
# argument has been sem'checked:
|
||||||
|
for i in 1 .. <n.len:
|
||||||
|
n.sons[i] = prepareOperand(c, n.sons[i])
|
||||||
|
|
||||||
proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||||
# for 'suggest' support:
|
# for 'suggest' support:
|
||||||
var marker = initIntSet()
|
var marker = initIntSet()
|
||||||
|
|
|
||||||
7
todo.txt
7
todo.txt
|
|
@ -1,6 +1,9 @@
|
||||||
version 0.9.2
|
version 0.9.2
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
- lazy overloading resolution:
|
||||||
|
* get rid of ``expr[typ]``, use perhaps ``static[typ]`` instead
|
||||||
|
* typedesc[T] needs to be documented in ast.nim
|
||||||
- FFI:
|
- FFI:
|
||||||
* test libffi on windows
|
* test libffi on windows
|
||||||
* test: times.format with the FFI
|
* test: times.format with the FFI
|
||||||
|
|
@ -15,6 +18,8 @@ version 0.9.2
|
||||||
version 0.9.4
|
version 0.9.4
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
- provide tool/API to track leaks/object counts
|
||||||
|
- use big blocks in the allocator
|
||||||
- make 'bind' default for templates and introduce 'mixin';
|
- make 'bind' default for templates and introduce 'mixin';
|
||||||
special rule for ``[]=``
|
special rule for ``[]=``
|
||||||
- implicit deref for parameter matching; overloading based on 'var T'
|
- implicit deref for parameter matching; overloading based on 'var T'
|
||||||
|
|
@ -123,3 +128,5 @@ Bugs
|
||||||
- blocks can "export" an identifier but the CCG generates {} for them ...
|
- blocks can "export" an identifier but the CCG generates {} for them ...
|
||||||
- JS gen: fix exception handling
|
- JS gen: fix exception handling
|
||||||
- the better scoping for locals is the wrong default for endb
|
- the better scoping for locals is the wrong default for endb
|
||||||
|
- osproc execProcesses can deadlock if all processes fail (as experienced
|
||||||
|
in c++ mode)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue