diff options
Diffstat (limited to 'compiler/evaltempl.nim')
-rw-r--r-- | compiler/evaltempl.nim | 75 |
1 files changed, 50 insertions, 25 deletions
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 2a01a7911..77c136d63 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -9,28 +9,43 @@ ## Template evaluation engine. Now hygienic. -import - strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents +import options, ast, astalgo, msgs, renderer, lineinfos, idents, trees +import std/strutils type TemplCtx = object owner, genSymOwner: PSym instLines: bool # use the instantiation lines numbers isDeclarative: bool - mapping: TIdTable # every gensym'ed symbol needs to be mapped to some - # new symbol + mapping: SymMapping # every gensym'ed symbol needs to be mapped to some + # new symbol config: ConfigRef ic: IdentCache + instID: int + idgen: IdGenerator proc copyNode(ctx: TemplCtx, a, b: PNode): PNode = result = copyNode(a) - if ctx.instLines: result.info = b.info + if ctx.instLines: setInfoRecursive(result, b.info) 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) + elif nfDefaultRefsParam in x.flags: + # value of default param needs to be evaluated like template body + # if it contains other template params + var res: PNode + if isAtom(x): + res = newNodeI(nkPar, x.info) + evalTemplateAux(x, actual, c, res) + if res.len == 1: res = res[0] + else: + res = copyNode(x) + for i in 0..<x.safeLen: + evalTemplateAux(x[i], actual, c, res) + result.add res else: result.add copyTree(x) @@ -42,19 +57,20 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = handleParam actual[s.position] elif (s.owner != nil) and (s.kind == skGenericParam or s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam): - handleParam actual[s.owner.typ.len + s.position - 1] + handleParam actual[s.owner.typ.signatureLen + s.position - 1] else: internalAssert c.config, sfGenSym in s.flags or s.kind == skType - var x = PSym(idTableGet(c.mapping, s)) + var x = idTableGet(c.mapping, s) if x == nil: - x = copySym(s) + x = copySym(s, c.idgen) # sem'check needs to set the owner properly later, see bug #9476 x.owner = nil # c.genSymOwner #if x.kind == skParam and x.owner.kind == skModule: # internalAssert c.config, false idTablePut(c.mapping, s, x) - if sfGenSym in s.flags and optNimV019 notin c.config.globalOptions: - result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $x.id), + if sfGenSym in s.flags: + # TODO: getIdent(c.ic, "`" & x.name.s & "`gensym" & $c.instID) + result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID), if c.instLines: actual.info else: templ.info) else: result.add newSymNode(x, if c.instLines: actual.info else: templ.info) @@ -81,10 +97,14 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = not c.isDeclarative: c.isDeclarative = true isDeclarative = true - var res = copyNode(c, templ, actual) - for i in 0..<templ.len: - evalTemplateAux(templ[i], actual, c, res) - result.add res + if (not c.isDeclarative) and templ.kind in nkCallKinds and isRunnableExamples(templ[0]): + # fixes bug #16993, bug #18054 + discard + else: + var res = copyNode(c, templ, actual) + for i in 0..<templ.len: + evalTemplateAux(templ[i], actual, c, res) + result.add res if isDeclarative: c.isDeclarative = false const @@ -110,7 +130,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode # now that we have working untyped parameters. genericParams = if fromHlo: 0 else: s.ast[genericParamsPos].len - expectedRegularParams = s.typ.len-1 + expectedRegularParams = s.typ.paramsLen givenRegularParams = totalParams - genericParams if givenRegularParams < 0: givenRegularParams = 0 @@ -166,7 +186,8 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode = proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; conf: ConfigRef; - ic: IdentCache; + ic: IdentCache; instID: ref int; + idgen: IdGenerator; fromHlo=false): PNode = inc(conf.evalTemplateCounter) if conf.evalTemplateCounter > evalTemplateLimit: @@ -175,14 +196,16 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; # replace each param by the corresponding node: var args = evalTemplateArgs(n, tmpl, conf, fromHlo) - var ctx: TemplCtx - ctx.owner = tmpl - ctx.genSymOwner = genSymOwner - ctx.config = conf - ctx.ic = ic - initIdTable(ctx.mapping) - - let body = tmpl.getBody + var ctx = TemplCtx(owner: tmpl, + genSymOwner: genSymOwner, + config: conf, + ic: ic, + mapping: initSymMapping(), + instID: instID[], + idgen: idgen + ) + + let body = tmpl.ast[bodyPos] #echo "instantion of ", renderTree(body, {renderIds}) if isAtom(body): result = newNodeI(nkPar, body.info) @@ -195,7 +218,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; result = copyNode(body) ctx.instLines = sfCallsite in tmpl.flags if ctx.instLines: - result.info = n.info + setInfoRecursive(result, n.info) for i in 0..<body.safeLen: evalTemplateAux(body[i], args, ctx, result) result.flags.incl nfFromTemplate @@ -203,3 +226,5 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; #if ctx.debugActive: # echo "instantion of ", renderTree(result, {renderIds}) dec(conf.evalTemplateCounter) + # The instID must be unique for every template instantiation, so we increment it here + inc instID[] |