Skip to content

Commit

Permalink
register explicitly injected procs, refactor semtempl
Browse files Browse the repository at this point in the history
  • Loading branch information
metagn committed Sep 11, 2023
1 parent 90f87bc commit 37a5d43
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 53 deletions.
90 changes: 37 additions & 53 deletions compiler/semtempl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -136,24 +136,32 @@ type
noGenSym: int
inTemplateHeader: int

proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
proc isTemplParam(c: TemplCtx, s: PSym): bool {.inline.} =
result = s.kind == skParam and
s.owner == c.owner and sfTemplateParam in s.flags

proc getIdentReplaceParams(c: var TemplCtx, n: var PNode): tuple[node: PNode, hasParam: bool] =
case n.kind
of nkPostfix: result = getIdentNode(c, n[1])
of nkPragmaExpr: result = getIdentNode(c, n[0])
of nkPostfix: result = getIdentReplaceParams(c, n[1])
of nkPragmaExpr: result = getIdentReplaceParams(c, n[0])
of nkIdent:
result = n
result = (n, false)
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
result = newSymNode(s, n.info)
of nkAccQuoted, nkSym: result = n
if s != nil and isTemplParam(c, s):
n = newSymNode(s, n.info)
result = (n, true)
of nkSym:
result = (n, isTemplParam(c, n.sym))
of nkAccQuoted:
result = (n, false)
for i in 0..<n.safeLen:
let (ident, hasParam) = getIdentReplaceParams(c, n[i])
if hasParam:
result.node[i] = ident
result.hasParam = true
else:
illFormedAst(n, c.c.config)
result = n

proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
result = n.kind == nkSym and n.sym.kind == skParam and
n.sym.owner == c.owner and sfTemplateParam in n.sym.flags
result = (n, false)

proc semTemplBody(c: var TemplCtx, n: PNode): PNode

Expand All @@ -168,19 +176,6 @@ proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
result = semTemplBody(c, n)
closeScope(c)

proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
result = n
if n.kind == nkIdent:
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
else:
for i in 0..<n.safeLen:
result[i] = onlyReplaceParams(c, n[i])

proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
result = newSym(kind, considerQuotedIdent(c.c, n), c.c.idgen, c.owner, n.info)
incl(result.flags, sfGenSym)
Expand All @@ -192,24 +187,10 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
k == skField:
# even if injected, don't produce a sym choice here:
#n = semTemplBody(c, n)
var x = n
while true:
case x.kind
of nkPostfix: x = x[1]
of nkPragmaExpr: x = x[0]
of nkIdent: break
of nkAccQuoted:
# consider: type `T TemplParam` {.inject.}
# it suffices to return to treat it like 'inject':
n = onlyReplaceParams(c, n)
return
else:
illFormedAst(x, c.c.config)
let ident = getIdentNode(c, x)
if not isTemplParam(c, ident):
if k != skField: c.toInject.incl(x.ident.id)
else:
replaceIdentBySym(c.c, n, ident)
let (ident, hasParam) = getIdentReplaceParams(c, n)
if not hasParam:
if k != skField:
c.toInject.incl(considerQuotedIdent(c.c, ident).id)
else:
if (n.kind == nkPragmaExpr and n.len >= 2 and n[1].kind == nkPragma):
let pragmaNode = n[1]
Expand All @@ -226,8 +207,8 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
openScope(c)
pragmaNode[i] = semTemplBody(c, pragmaNode[i])
closeScope(c)
let ident = getIdentNode(c, n)
if not isTemplParam(c, ident):
let (ident, hasParam) = getIdentReplaceParams(c, n)
if not hasParam:
if n.kind != nkSym and not (n.kind == nkIdent and n.ident.id == ord(wUnderscore)):
let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local)
Expand All @@ -236,8 +217,6 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
replaceIdentBySym(c.c, n, newSymNode(local, n.info))
if k == skParam and c.inTemplateHeader > 0:
local.flags.incl sfTemplateParam
else:
replaceIdentBySym(c.c, n, ident)

proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
incl(s.flags, sfUsed)
Expand Down Expand Up @@ -294,19 +273,24 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
result = n
checkSonsLen(n, bodyPos + 1, c.c.config)
# routines default to 'inject':
if n.kind notin nkLambdaKinds and symBinding(n[pragmasPos]) == spGenSym:
let ident = getIdentNode(c, n[namePos])
if not isTemplParam(c, ident):
var binding = spNone
if n.kind notin nkLambdaKinds:
binding = symBinding(n[pragmasPos])
if binding == spGenSym:
let (ident, hasParam) = getIdentReplaceParams(c, n[namePos])
if not hasParam:
var s = newGenSym(k, ident, c)
s.ast = n
addPrelimDecl(c.c, s)
styleCheckDef(c.c, n.info, s)
onDef(n.info, s)
n[namePos] = newSymNode(s, n[namePos].info)
else:
n[namePos] = ident
else:
n[namePos] = semRoutineInTemplName(c, n[namePos])
if binding == spInject:
let (ident, hasParam) = getIdentReplaceParams(c, n[namePos])
if not hasParam:
c.toInject.incl(considerQuotedIdent(c.c, ident).id)
# open scope for parameters
openScope(c)
for i in patternPos..paramsPos-1:
Expand Down
8 changes: 8 additions & 0 deletions tests/template/tprocinject.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
block:
proc bar(x: int): int = 10
template foo =
proc bar(x: int): int {.inject.} = x + 2
doAssert bar(3) == 5
doAssert 3.bar == 5
block:
foo()

0 comments on commit 37a5d43

Please sign in to comment.