fix #1858 again; restores the support for static macro params
This commit is contained in:
parent
7af92708af
commit
02f97489b7
6 changed files with 179 additions and 41 deletions
|
|
@ -25,16 +25,21 @@ proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
|
||||||
if ctx.instLines: result.info = b.info
|
if ctx.instLines: result.info = b.info
|
||||||
|
|
||||||
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||||
|
template handleParam(param) =
|
||||||
|
let x = param
|
||||||
|
if x.kind == nkArgList:
|
||||||
|
for y in items(x): result.add(y)
|
||||||
|
else:
|
||||||
|
result.add copyTree(x)
|
||||||
|
|
||||||
case templ.kind
|
case templ.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
var s = templ.sym
|
var s = templ.sym
|
||||||
if s.owner.id == c.owner.id:
|
if s.owner.id == c.owner.id:
|
||||||
if s.kind == skParam and sfGenSym notin s.flags:
|
if s.kind == skParam and sfGenSym notin s.flags:
|
||||||
let x = actual.sons[s.position]
|
handleParam actual.sons[s.position]
|
||||||
if x.kind == nkArgList:
|
elif s.kind == skGenericParam:
|
||||||
for y in items(x): result.add(y)
|
handleParam actual.sons[s.owner.typ.len + s.position - 1]
|
||||||
else:
|
|
||||||
result.add copyTree(x)
|
|
||||||
else:
|
else:
|
||||||
internalAssert sfGenSym in s.flags
|
internalAssert sfGenSym in s.flags
|
||||||
var x = PSym(idTableGet(c.mapping, s))
|
var x = PSym(idTableGet(c.mapping, s))
|
||||||
|
|
@ -56,22 +61,35 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||||
proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
||||||
# if the template has zero arguments, it can be called without ``()``
|
# if the template has zero arguments, it can be called without ``()``
|
||||||
# `n` is then a nkSym or something similar
|
# `n` is then a nkSym or something similar
|
||||||
var a: int
|
var totalParams = case n.kind
|
||||||
case n.kind
|
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: <n.len
|
||||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
else: 0
|
||||||
a = sonsLen(n)
|
|
||||||
else: a = 0
|
var
|
||||||
var f = s.typ.sonsLen
|
genericParams = s.ast[genericParamsPos].len
|
||||||
if a > f: globalError(n.info, errWrongNumberOfArguments)
|
expectedRegularParams = <s.typ.len
|
||||||
|
givenRegularParams = totalParams - genericParams
|
||||||
|
|
||||||
|
if totalParams > expectedRegularParams + genericParams:
|
||||||
|
globalError(n.info, errWrongNumberOfArguments)
|
||||||
|
|
||||||
result = newNodeI(nkArgList, n.info)
|
result = newNodeI(nkArgList, n.info)
|
||||||
for i in countup(1, f - 1):
|
for i in 1 .. givenRegularParams:
|
||||||
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
|
result.addSon n.sons[i]
|
||||||
if arg == nil or arg.kind == nkEmpty:
|
|
||||||
|
# handle parameters with default values, which were
|
||||||
|
# not supplied by the user
|
||||||
|
for i in givenRegularParams+1 .. expectedRegularParams:
|
||||||
|
let default = s.typ.n.sons[i].sym.ast
|
||||||
|
if default.kind == nkEmpty:
|
||||||
localError(n.info, errWrongNumberOfArguments)
|
localError(n.info, errWrongNumberOfArguments)
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, ast.emptyNode)
|
||||||
else:
|
else:
|
||||||
addSon(result, arg)
|
addSon(result, default.copyTree)
|
||||||
|
|
||||||
|
# add any generic paramaters
|
||||||
|
for i in 1 .. genericParams:
|
||||||
|
result.addSon n.sons[givenRegularParams + i]
|
||||||
|
|
||||||
var evalTemplateCounter* = 0
|
var evalTemplateCounter* = 0
|
||||||
# to prevent endless recursion in templates instantiation
|
# to prevent endless recursion in templates instantiation
|
||||||
|
|
|
||||||
|
|
@ -305,8 +305,22 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||||
if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
|
if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
|
||||||
result.typ = newTypeS(x.fauxMatch, c)
|
result.typ = newTypeS(x.fauxMatch, c)
|
||||||
return
|
return
|
||||||
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
let gp = finalCallee.ast.sons[genericParamsPos]
|
||||||
|
if gp.kind != nkEmpty:
|
||||||
|
if x.calleeSym.kind notin {skMacro, skTemplate}:
|
||||||
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
||||||
|
else:
|
||||||
|
# For macros and templates, the resolved generic params
|
||||||
|
# are added as normal params.
|
||||||
|
for s in instantiateGenericParamList(c, gp, x.bindings):
|
||||||
|
case s.kind
|
||||||
|
of skConst:
|
||||||
|
x.call.add s.ast
|
||||||
|
of skType:
|
||||||
|
x.call.add newSymNode(s, n.info)
|
||||||
|
else:
|
||||||
|
internalAssert false
|
||||||
|
|
||||||
result = x.call
|
result = x.call
|
||||||
instGenericConvertersSons(c, result, x)
|
instGenericConvertersSons(c, result, x)
|
||||||
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,10 @@
|
||||||
# This module implements the instantiation of generic procs.
|
# This module implements the instantiation of generic procs.
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
|
||||||
entry: var TInstantiation) =
|
internalAssert n.kind == nkGenericParams
|
||||||
if n.kind != nkGenericParams:
|
|
||||||
internalError(n.info, "instantiateGenericParamList; no generic params")
|
|
||||||
newSeq(entry.concreteTypes, n.len)
|
|
||||||
for i, a in n.pairs:
|
for i, a in n.pairs:
|
||||||
if a.kind != nkSym:
|
internalAssert a.kind == nkSym
|
||||||
internalError(a.info, "instantiateGenericParamList; no symbol")
|
|
||||||
var q = a.sym
|
var q = a.sym
|
||||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
|
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
|
||||||
continue
|
continue
|
||||||
|
|
@ -42,8 +38,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
#t = ReplaceTypeVarsT(cl, t)
|
#t = ReplaceTypeVarsT(cl, t)
|
||||||
s.typ = t
|
s.typ = t
|
||||||
if t.kind == tyStatic: s.ast = t.n
|
if t.kind == tyStatic: s.ast = t.n
|
||||||
addDecl(c, s)
|
yield s
|
||||||
entry.concreteTypes[i] = t
|
|
||||||
|
|
||||||
proc sameInstantiation(a, b: TInstantiation): bool =
|
proc sameInstantiation(a, b: TInstantiation): bool =
|
||||||
if a.concreteTypes.len == b.concreteTypes.len:
|
if a.concreteTypes.len == b.concreteTypes.len:
|
||||||
|
|
@ -217,7 +212,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
## The `pt` parameter is a type-unsafe mapping table used to link generic
|
## The `pt` parameter is a type-unsafe mapping table used to link generic
|
||||||
## parameters to their concrete types within the generic instance.
|
## parameters to their concrete types within the generic instance.
|
||||||
# no need to instantiate generic templates/macros:
|
# no need to instantiate generic templates/macros:
|
||||||
if fn.kind in {skTemplate, skMacro}: return fn
|
internalAssert fn.kind notin {skMacro, skTemplate}
|
||||||
# generates an instantiated proc
|
# generates an instantiated proc
|
||||||
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
|
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
|
||||||
inc(c.instCounter)
|
inc(c.instCounter)
|
||||||
|
|
@ -234,12 +229,18 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
result.ast = n
|
result.ast = n
|
||||||
pushOwner(result)
|
pushOwner(result)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
internalAssert n.sons[genericParamsPos].kind != nkEmpty
|
let gp = n.sons[genericParamsPos]
|
||||||
|
internalAssert gp.kind != nkEmpty
|
||||||
n.sons[namePos] = newSymNode(result)
|
n.sons[namePos] = newSymNode(result)
|
||||||
pushInfoContext(info)
|
pushInfoContext(info)
|
||||||
var entry = TInstantiation.new
|
var entry = TInstantiation.new
|
||||||
entry.sym = result
|
entry.sym = result
|
||||||
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
|
newSeq(entry.concreteTypes, gp.len)
|
||||||
|
var i = 0
|
||||||
|
for s in instantiateGenericParamList(c, gp, pt):
|
||||||
|
addDecl(c, s)
|
||||||
|
entry.concreteTypes[i] = s.typ
|
||||||
|
inc i
|
||||||
pushProcCon(c, result)
|
pushProcCon(c, result)
|
||||||
instantiateProcType(c, pt, result, info)
|
instantiateProcType(c, pt, result, info)
|
||||||
n.sons[genericParamsPos] = ast.emptyNode
|
n.sons[genericParamsPos] = ast.emptyNode
|
||||||
|
|
|
||||||
|
|
@ -1467,12 +1467,20 @@ proc evalStaticStmt*(module: PSym, e: PNode, prc: PSym) =
|
||||||
proc setupCompileTimeVar*(module: PSym, n: PNode) =
|
proc setupCompileTimeVar*(module: PSym, n: PNode) =
|
||||||
discard evalConstExprAux(module, nil, n, emStaticStmt)
|
discard evalConstExprAux(module, nil, n, emStaticStmt)
|
||||||
|
|
||||||
proc setupMacroParam(x: PNode): PNode =
|
proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
||||||
result = x
|
case typ.kind
|
||||||
if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
|
of tyStatic:
|
||||||
result = canonValue(result)
|
putIntoReg(result, x)
|
||||||
result.flags.incl nfIsRef
|
of tyTypeDesc:
|
||||||
result.typ = x.typ
|
putIntoReg(result, x)
|
||||||
|
else:
|
||||||
|
result.kind = rkNode
|
||||||
|
var n = x
|
||||||
|
if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n.sons[1]
|
||||||
|
n = n.canonValue
|
||||||
|
n.flags.incl nfIsRef
|
||||||
|
n.typ = x.typ
|
||||||
|
result.node = n
|
||||||
|
|
||||||
var evalMacroCounter: int
|
var evalMacroCounter: int
|
||||||
|
|
||||||
|
|
@ -1508,10 +1516,16 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
||||||
# return value:
|
# return value:
|
||||||
tos.slots[0].kind = rkNode
|
tos.slots[0].kind = rkNode
|
||||||
tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
|
tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
|
||||||
|
|
||||||
# setup parameters:
|
# setup parameters:
|
||||||
for i in 1 .. < min(tos.slots.len, L):
|
for i in 1.. <sym.typ.len:
|
||||||
tos.slots[i].kind = rkNode
|
tos.slots[i] = setupMacroParam(n.sons[i], sym.typ.sons[i])
|
||||||
tos.slots[i].node = setupMacroParam(n.sons[i])
|
|
||||||
|
let gp = sym.ast[genericParamsPos]
|
||||||
|
for i in 0 .. <gp.len:
|
||||||
|
let idx = sym.typ.len + i
|
||||||
|
tos.slots[idx] = setupMacroParam(n.sons[idx], gp[i].sym.typ)
|
||||||
|
|
||||||
# temporary storage:
|
# temporary storage:
|
||||||
#for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
|
#for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||||
result = rawExecute(c, start, tos).regToNode
|
result = rawExecute(c, start, tos).regToNode
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,8 @@ const
|
||||||
proc bestEffort(c: PCtx): TLineInfo =
|
proc bestEffort(c: PCtx): TLineInfo =
|
||||||
(if c.prc == nil: c.module.info else: c.prc.sym.info)
|
(if c.prc == nil: c.module.info else: c.prc.sym.info)
|
||||||
|
|
||||||
proc getTemp(cc: PCtx; typ: PType): TRegister =
|
proc getTemp(cc: PCtx; tt: PType): TRegister =
|
||||||
|
let typ = tt.skipTypesOrNil({tyStatic})
|
||||||
let c = cc.prc
|
let c = cc.prc
|
||||||
# we prefer the same slot kind here for efficiency. Unfortunately for
|
# we prefer the same slot kind here for efficiency. Unfortunately for
|
||||||
# discardable return types we may not know the desired type. This can happen
|
# discardable return types we may not know the desired type. This can happen
|
||||||
|
|
@ -707,7 +708,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
c.gABC(n, opc, dest, tmp)
|
c.gABC(n, opc, dest, tmp)
|
||||||
c.gABx(n, opc, 0, genType(c, n.typ))
|
c.gABx(n, opc, 0, genType(c, n.typ))
|
||||||
c.gABx(n, opc, 0, genType(c, arg.typ))
|
c.gABx(n, opc, 0, genType(c, arg.typ.skipTypes({tyStatic})))
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
proc genCard(c: PCtx; n: PNode; dest: var TDest) =
|
proc genCard(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
|
|
@ -1617,6 +1618,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||||
c.gABx(n, opcLdConst, dest, lit)
|
c.gABx(n, opcLdConst, dest, lit)
|
||||||
of skType:
|
of skType:
|
||||||
genTypeLit(c, s.typ, dest)
|
genTypeLit(c, s.typ, dest)
|
||||||
|
of skGenericParam:
|
||||||
|
if c.prc.sym.kind == skMacro:
|
||||||
|
genRdVar(c, n, dest, flags)
|
||||||
|
else:
|
||||||
|
internalError(n.info, "cannot generate code for: " & s.name.s)
|
||||||
else:
|
else:
|
||||||
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
|
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
|
|
@ -1767,6 +1773,14 @@ proc finalJumpTarget(c: PCtx; pc, diff: int) =
|
||||||
c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
|
c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
|
||||||
uint32(diff+wordExcess) shl 16'u32).TInstr
|
uint32(diff+wordExcess) shl 16'u32).TInstr
|
||||||
|
|
||||||
|
proc genGenericParams(c: PCtx; gp: PNode) =
|
||||||
|
var base = c.prc.maxSlots
|
||||||
|
for i in 0.. <gp.len:
|
||||||
|
var param = gp.sons[i].sym
|
||||||
|
param.position = base + i # XXX: fix this earlier; make it consistent with templates
|
||||||
|
c.prc.slots[base + i] = (inUse: true, kind: slotFixedLet)
|
||||||
|
c.prc.maxSlots = base + gp.len
|
||||||
|
|
||||||
proc optimizeJumps(c: PCtx; start: int) =
|
proc optimizeJumps(c: PCtx; start: int) =
|
||||||
const maxIterations = 10
|
const maxIterations = 10
|
||||||
for i in start .. <c.code.len:
|
for i in start .. <c.code.len:
|
||||||
|
|
@ -1831,6 +1845,9 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||||
c.prc = p
|
c.prc = p
|
||||||
# iterate over the parameters and allocate space for them:
|
# iterate over the parameters and allocate space for them:
|
||||||
genParams(c, s.typ.n)
|
genParams(c, s.typ.n)
|
||||||
|
# allocate additional space for any generically bound parameters
|
||||||
|
if s.kind == skMacro and s.ast[genericParamsPos].kind != nkEmpty:
|
||||||
|
genGenericParams(c, s.ast[genericParamsPos])
|
||||||
if tfCapturesEnv in s.typ.flags:
|
if tfCapturesEnv in s.typ.flags:
|
||||||
#let env = s.ast.sons[paramsPos].lastSon.sym
|
#let env = s.ast.sons[paramsPos].lastSon.sym
|
||||||
#assert env.position == 2
|
#assert env.position == 2
|
||||||
|
|
|
||||||
74
tests/macros/tstaticparamsmacro.nim
Normal file
74
tests/macros/tstaticparamsmacro.nim
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
discard """
|
||||||
|
msg: '''letters
|
||||||
|
aa
|
||||||
|
bb
|
||||||
|
numbers
|
||||||
|
11
|
||||||
|
22
|
||||||
|
AST a
|
||||||
|
[(11, 22), (33, 44)]
|
||||||
|
AST b
|
||||||
|
(e: [55, 66], f: [77, 88])
|
||||||
|
55
|
||||||
|
10
|
||||||
|
20Test
|
||||||
|
20
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
type
|
||||||
|
TConfig = tuple
|
||||||
|
letters: seq[string]
|
||||||
|
numbers:seq[int]
|
||||||
|
|
||||||
|
const data: Tconfig = (@["aa", "bb"], @[11, 22])
|
||||||
|
|
||||||
|
macro mymacro(data: static[TConfig]): stmt =
|
||||||
|
echo "letters"
|
||||||
|
for s in items(data.letters):
|
||||||
|
echo s
|
||||||
|
echo "numbers"
|
||||||
|
for n in items(data.numbers):
|
||||||
|
echo n
|
||||||
|
|
||||||
|
mymacro(data)
|
||||||
|
|
||||||
|
type
|
||||||
|
Ta = seq[tuple[c:int, d:int]]
|
||||||
|
Tb = tuple[e:seq[int], f:seq[int]]
|
||||||
|
|
||||||
|
const
|
||||||
|
a : Ta = @[(11, 22), (33, 44)]
|
||||||
|
b : Tb = (@[55,66], @[77, 88])
|
||||||
|
|
||||||
|
macro mA(data: static[Ta]): stmt =
|
||||||
|
echo "AST a \n", repr(data)
|
||||||
|
|
||||||
|
macro mB(data: static[Tb]): stmt =
|
||||||
|
echo "AST b \n", repr(data)
|
||||||
|
echo data.e[0]
|
||||||
|
|
||||||
|
mA(a)
|
||||||
|
mB(b)
|
||||||
|
|
||||||
|
type
|
||||||
|
Foo[N: static[int], Z: static[string]] = object
|
||||||
|
|
||||||
|
macro staticIntMacro(f: static[int]): stmt = echo f
|
||||||
|
staticIntMacro 10
|
||||||
|
|
||||||
|
var
|
||||||
|
x: Foo[20, "Test"]
|
||||||
|
|
||||||
|
macro genericMacro[N; Z: static[string]](f: Foo[N, Z], ll = 3, zz = 12): stmt =
|
||||||
|
echo N, Z
|
||||||
|
|
||||||
|
genericMacro x
|
||||||
|
|
||||||
|
template genericTemplate[N, Z](f: Foo[N, Z], ll = 3, zz = 12): int = N
|
||||||
|
|
||||||
|
static:
|
||||||
|
echo genericTemplate(x)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue