summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2012-03-26 04:36:26 +0300
committerZahary Karadjov <zahary@gmail.com>2012-03-26 04:36:26 +0300
commit6216046bc6b2794d15705f5d2621f602bda636c4 (patch)
tree8a70def0c70dc634ee92d1144c4b12e661042343 /compiler
parentbc2eb0ea9b8a806ddafdb7726c94363fbd2c2f20 (diff)
downloadNim-6216046bc6b2794d15705f5d2621f602bda636c4.tar.gz
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
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/evals.nim15
-rw-r--r--compiler/idgen.nim7
-rwxr-xr-xcompiler/lookups.nim7
-rwxr-xr-xcompiler/semexprs.nim2
-rwxr-xr-xcompiler/semtempl.nim61
5 files changed, 22 insertions, 70 deletions
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.. <n.len:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 147f38abb..f5ceee7c0 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -13,7 +13,7 @@
 proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = 
   markUsed(n, s)
   pushInfoContext(n.info)
-  result = evalTemplate(c, n, s)
+  result = evalTemplate(n, s)
   if semCheck: result = semAfterMacroCall(c, result, s)
   popInfoContext()
 
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 2600d80cb..b0debc75b 100755
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -9,67 +9,6 @@
 
 # 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 = 
   var 
     a: PSym