From 6216046bc6b2794d15705f5d2621f602bda636c4 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 26 Mar 2012 04:36:26 +0300 Subject: [PATCH] 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 --- compiler/evals.nim | 15 ++++++---- compiler/idgen.nim | 7 +++-- compiler/lookups.nim | 7 ++++- compiler/semexprs.nim | 2 +- compiler/semtempl.nim | 61 --------------------------------------- tests/compile/tgensym.nim | 12 ++++++++ 6 files changed, 34 insertions(+), 70 deletions(-) create mode 100644 tests/compile/tgensym.nim diff --git a/compiler/evals.nim b/compiler/evals.nim index 72c37a5d9..84d3023a5 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -16,7 +16,7 @@ import strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets, msgs, os, condsyms, idents, renderer, types, passes, semfold, transf, - parser, ropes, rodread + parser, ropes, rodread, idgen type PStackFrame* = ref TStackFrame @@ -843,6 +843,7 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode = result.typ = newType(tyStmt, c.module) proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode = + inc genSymBaseId case templ.kind of nkSym: var p = templ.sym @@ -866,26 +867,29 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode = of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: a = sonsLen(n) else: a = 0 - var f = sonsLen(s.typ) + var f = s.typ.sonsLen if a > f: GlobalError(n.info, errWrongNumberOfArguments) result = copyNode(n) for i in countup(1, f - 1): 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) -var evalTemplateCounter = 0 +var evalTemplateCounter* = 0 # to prevent endless recursion in templates instantation -proc evalTemplate(n: PNode, sym: PSym): PNode = +proc evalTemplate*(n: PNode, sym: PSym): PNode = inc(evalTemplateCounter) if evalTemplateCounter > 100: GlobalError(n.info, errTemplateInstantiationTooNested) + result = n # replace each param by the corresponding node: var args = evalTemplateArgs(n, sym) result = evalTemplateAux(sym.getBody, args, sym) - + dec(evalTemplateCounter) proc evalExpandToAst(c: PEvalContext, original: PNode): PNode = @@ -1312,6 +1316,7 @@ proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode = if evalTemplateCounter > 100: GlobalError(n.info, errTemplateInstantiationTooNested) + inc genSymBaseId var s = newStackFrame() s.call = n setlen(s.params, 2) diff --git a/compiler/idgen.nim b/compiler/idgen.nim index 6dc19474d..d2e322796 100644 --- a/compiler/idgen.nim +++ b/compiler/idgen.nim @@ -11,7 +11,7 @@ import idents, strutils, os, options -var gFrontEndId, gBackendId*: int +var gFrontEndId, gBackendId*, genSymBaseId*: int const debugIds* = false @@ -25,7 +25,7 @@ proc registerID*(id: PIdObj) = when debugIDs: if id.id == -1 or ContainsOrIncl(usedIds, id.id): InternalError("ID already used: " & $id.id) - + proc getID*(): int {.inline.} = result = gFrontEndId inc(gFrontEndId) @@ -34,6 +34,9 @@ proc backendId*(): int {.inline.} = result = gBackendId inc(gBackendId) +proc genSym*(basename: string): PIdent = + result = getIdent(basename & $genSymBaseId) + proc setId*(id: int) {.inline.} = gFrontEndId = max(gFrontEndId, id + 1) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index ee77b3633..62f4a3391 100755 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -11,7 +11,7 @@ import intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread, - renderer + renderer, wordrecg, idgen proc considerAcc*(n: PNode): PIdent = case n.kind @@ -21,6 +21,11 @@ proc considerAcc*(n: PNode): PIdent = case n.len of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n)) 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: var id = "" for i in 0.. 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 = var a: PSym diff --git a/tests/compile/tgensym.nim b/tests/compile/tgensym.nim new file mode 100644 index 000000000..3c0405136 --- /dev/null +++ b/tests/compile/tgensym.nim @@ -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 +