genSym support for hygienic macros and templates.
example: template hygienic(val: expr) = var `*x` = val echo `*x` *x was chosen as mnemonic for "opposite of public" and thus private
This commit is contained in:
parent
bc2eb0ea9b
commit
6216046bc6
6 changed files with 34 additions and 70 deletions
|
|
@ -16,7 +16,7 @@
|
||||||
import
|
import
|
||||||
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
|
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
|
||||||
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
|
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
|
||||||
parser, ropes, rodread
|
parser, ropes, rodread, idgen
|
||||||
|
|
||||||
type
|
type
|
||||||
PStackFrame* = ref TStackFrame
|
PStackFrame* = ref TStackFrame
|
||||||
|
|
@ -843,6 +843,7 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
|
||||||
result.typ = newType(tyStmt, c.module)
|
result.typ = newType(tyStmt, c.module)
|
||||||
|
|
||||||
proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode =
|
proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode =
|
||||||
|
inc genSymBaseId
|
||||||
case templ.kind
|
case templ.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
var p = templ.sym
|
var p = templ.sym
|
||||||
|
|
@ -866,21 +867,24 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
||||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||||
a = sonsLen(n)
|
a = sonsLen(n)
|
||||||
else: a = 0
|
else: a = 0
|
||||||
var f = sonsLen(s.typ)
|
var f = s.typ.sonsLen
|
||||||
if a > f: GlobalError(n.info, errWrongNumberOfArguments)
|
if a > f: GlobalError(n.info, errWrongNumberOfArguments)
|
||||||
|
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
for i in countup(1, f - 1):
|
for i in countup(1, f - 1):
|
||||||
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
|
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
|
||||||
|
if arg == nil or arg.kind == nkEmpty:
|
||||||
|
LocalError(n.info, errWrongNumberOfArguments)
|
||||||
addSon(result, arg)
|
addSon(result, arg)
|
||||||
|
|
||||||
var evalTemplateCounter = 0
|
var evalTemplateCounter* = 0
|
||||||
# to prevent endless recursion in templates instantation
|
# to prevent endless recursion in templates instantation
|
||||||
|
|
||||||
proc evalTemplate(n: PNode, sym: PSym): PNode =
|
proc evalTemplate*(n: PNode, sym: PSym): PNode =
|
||||||
inc(evalTemplateCounter)
|
inc(evalTemplateCounter)
|
||||||
if evalTemplateCounter > 100:
|
if evalTemplateCounter > 100:
|
||||||
GlobalError(n.info, errTemplateInstantiationTooNested)
|
GlobalError(n.info, errTemplateInstantiationTooNested)
|
||||||
|
result = n
|
||||||
|
|
||||||
# replace each param by the corresponding node:
|
# replace each param by the corresponding node:
|
||||||
var args = evalTemplateArgs(n, sym)
|
var args = evalTemplateArgs(n, sym)
|
||||||
|
|
@ -1312,6 +1316,7 @@ proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode =
|
||||||
if evalTemplateCounter > 100:
|
if evalTemplateCounter > 100:
|
||||||
GlobalError(n.info, errTemplateInstantiationTooNested)
|
GlobalError(n.info, errTemplateInstantiationTooNested)
|
||||||
|
|
||||||
|
inc genSymBaseId
|
||||||
var s = newStackFrame()
|
var s = newStackFrame()
|
||||||
s.call = n
|
s.call = n
|
||||||
setlen(s.params, 2)
|
setlen(s.params, 2)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import idents, strutils, os, options
|
import idents, strutils, os, options
|
||||||
|
|
||||||
var gFrontEndId, gBackendId*: int
|
var gFrontEndId, gBackendId*, genSymBaseId*: int
|
||||||
|
|
||||||
const
|
const
|
||||||
debugIds* = false
|
debugIds* = false
|
||||||
|
|
@ -34,6 +34,9 @@ proc backendId*(): int {.inline.} =
|
||||||
result = gBackendId
|
result = gBackendId
|
||||||
inc(gBackendId)
|
inc(gBackendId)
|
||||||
|
|
||||||
|
proc genSym*(basename: string): PIdent =
|
||||||
|
result = getIdent(basename & $genSymBaseId)
|
||||||
|
|
||||||
proc setId*(id: int) {.inline.} =
|
proc setId*(id: int) {.inline.} =
|
||||||
gFrontEndId = max(gFrontEndId, id + 1)
|
gFrontEndId = max(gFrontEndId, id + 1)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
|
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
|
||||||
renderer
|
renderer, wordrecg, idgen
|
||||||
|
|
||||||
proc considerAcc*(n: PNode): PIdent =
|
proc considerAcc*(n: PNode): PIdent =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -21,6 +21,11 @@ proc considerAcc*(n: PNode): PIdent =
|
||||||
case n.len
|
case n.len
|
||||||
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
||||||
of 1: result = considerAcc(n.sons[0])
|
of 1: result = considerAcc(n.sons[0])
|
||||||
|
of 2:
|
||||||
|
if n[0].ident.id == ord(wStar):
|
||||||
|
result = genSym(n[1].ident.s)
|
||||||
|
else:
|
||||||
|
result = getIdent(n[0].ident.s & n[1].ident.s)
|
||||||
else:
|
else:
|
||||||
var id = ""
|
var id = ""
|
||||||
for i in 0.. <n.len:
|
for i in 0.. <n.len:
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
result = evalTemplate(c, n, s)
|
result = evalTemplate(n, s)
|
||||||
if semCheck: result = semAfterMacroCall(c, result, s)
|
if semCheck: result = semAfterMacroCall(c, result, s)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,67 +9,6 @@
|
||||||
|
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
proc isExpr(n: PNode): bool =
|
|
||||||
# returns true if ``n`` looks like an expression
|
|
||||||
case n.kind
|
|
||||||
of nkIdent..nkNilLit:
|
|
||||||
result = true
|
|
||||||
of nkCall..pred(nkAsgn):
|
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
|
||||||
if not isExpr(n.sons[i]):
|
|
||||||
return false
|
|
||||||
result = true
|
|
||||||
else: result = false
|
|
||||||
|
|
||||||
proc isTypeDesc(n: PNode): bool =
|
|
||||||
# returns true if ``n`` looks like a type desc
|
|
||||||
case n.kind
|
|
||||||
of nkIdent, nkSym, nkType:
|
|
||||||
result = true
|
|
||||||
of nkDotExpr, nkBracketExpr:
|
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
|
||||||
if not isTypeDesc(n.sons[i]):
|
|
||||||
return false
|
|
||||||
result = true
|
|
||||||
of nkTypeOfExpr..nkEnumTy:
|
|
||||||
result = true
|
|
||||||
else: result = false
|
|
||||||
|
|
||||||
var evalTemplateCounter: int = 0
|
|
||||||
# to prevend endless recursion in templates instantation
|
|
||||||
|
|
||||||
proc evalTemplateArgs(c: PContext, n: PNode, s: PSym): PNode =
|
|
||||||
var
|
|
||||||
f, a: int
|
|
||||||
arg: PNode
|
|
||||||
f = sonsLen(s.typ)
|
|
||||||
# if the template has zero arguments, it can be called without ``()``
|
|
||||||
# `n` is then a nkSym or something similar
|
|
||||||
case n.kind
|
|
||||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
|
||||||
a = sonsLen(n)
|
|
||||||
else: a = 0
|
|
||||||
if a > f: LocalError(n.info, errWrongNumberOfArguments)
|
|
||||||
result = copyNode(n)
|
|
||||||
for i in countup(1, f - 1):
|
|
||||||
if i < a: arg = n.sons[i]
|
|
||||||
else: arg = copyTree(s.typ.n.sons[i].sym.ast)
|
|
||||||
if arg == nil or arg.kind == nkEmpty:
|
|
||||||
LocalError(n.info, errWrongNumberOfArguments)
|
|
||||||
addSon(result, arg)
|
|
||||||
|
|
||||||
proc evalTemplate*(c: PContext, n: PNode, sym: PSym): PNode =
|
|
||||||
var args: PNode
|
|
||||||
inc(evalTemplateCounter)
|
|
||||||
if evalTemplateCounter <= 100:
|
|
||||||
# replace each param by the corresponding node:
|
|
||||||
args = evalTemplateArgs(c, n, sym)
|
|
||||||
result = evalTemplateAux(sym.getBody, args, sym)
|
|
||||||
dec(evalTemplateCounter)
|
|
||||||
else:
|
|
||||||
GlobalError(n.info, errTemplateInstantiationTooNested)
|
|
||||||
result = n
|
|
||||||
|
|
||||||
proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
|
proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
var
|
var
|
||||||
a: PSym
|
a: PSym
|
||||||
|
|
|
||||||
12
tests/compile/tgensym.nim
Normal file
12
tests/compile/tgensym.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
template hygienic(val: expr) =
|
||||||
|
var `*x` = val
|
||||||
|
stdout.write `*x`
|
||||||
|
|
||||||
|
var x = 100
|
||||||
|
|
||||||
|
hygienic 1
|
||||||
|
hygienic 2
|
||||||
|
hygienic 3
|
||||||
|
|
||||||
|
echo x
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue