summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-08-24 01:18:03 +0200
committerAraq <rumpf_a@web.de>2012-08-24 01:18:03 +0200
commitc7ba6f5eb6f555ae650417c6f3bf9cdc0bad1427 (patch)
treee76ddea5dc65e48b16854fa69905f5618998acc1 /compiler
parentbdf3bee05510718581510cb78fa70ca183039d55 (diff)
downloadNim-c7ba6f5eb6f555ae650417c6f3bf9cdc0bad1427.tar.gz
implemented 'bind' for macros
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim1
-rwxr-xr-xcompiler/evals.nim36
-rwxr-xr-xcompiler/semstmts.nim18
3 files changed, 55 insertions, 0 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 36cafe6f3..bb78fcd57 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -439,6 +439,7 @@ type
     mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, 
     mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
     mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, 
+    mNGetBoundSym,
     mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError, 
     mInstantiationInfo, mGetTypeInfo
 
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 58f797e14..b107015eb 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -40,6 +40,7 @@ type
     lastException*: PNode
     mode*: TEvalMode
     globals*: TIdNodeTable    # state of global vars
+    boundSyms: TStrTable      # for 'bind' support within macros
   
   PEvalContext* = ref TEvalContext
 
@@ -65,6 +66,7 @@ proc newEvalContext*(module: PSym, filename: string,
   result.module = module
   result.mode = mode
   initIdNodeTable(result.globals)
+  initStrTable(result.boundSyms)
 
 proc pushStackFrame*(c: PEvalContext, t: PStackFrame) {.inline.} = 
   t.next = c.tos
@@ -931,6 +933,26 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
       "ExpandToAst: expanded symbol is no macro or template")
     result = emptyNode
 
+proc getBoundSym(c: PEvalContext, n: PNode): PNode =
+  # we return either an nkSym or an nkSymChoice; XXX we really need
+  # to distinguish between open and closed nkSymChoice somehow.
+  var ident = getIdent(n.strVal)
+
+  # semantic checking requires a type; ``fitNode`` deals with it
+  # appropriately
+  result = newNodeIT(nkSymChoice, n.info, newType(tyNone, c.module))
+
+  var ii: TIdentIter
+  var a = InitIdentIter(ii, c.boundSyms, ident)
+  while a != nil:
+    incl(a.flags, sfUsed)
+    addSon(result, newSymNode(a, n.info))
+    a = NextIdentIter(ii, c.boundSyms)
+  case result.len
+  of 0: stackTrace(c, n, errUndeclaredIdentifier, n.strVal)
+  of 1: result = result.sons[0]
+  else: nil
+
 proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = 
   var m = getMagic(n)
   case m
@@ -1151,6 +1173,13 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
     result = evalAux(c, n.sons[1], {efLValue})
     if isSpecial(result): return 
     result = copyTree(result)
+  of mNGetBoundSym:
+    result = evalAux(c, n.sons[1], {})
+    if isSpecial(result): return 
+    if not (result.kind in {nkStrLit..nkTripleStrLit}): 
+      stackTrace(c, n, errFieldXNotFound, "getBoundSym")
+      return
+    result = getBoundSym(c, result)
   of mStrToIdent: 
     result = evalAux(c, n.sons[1], {})
     if isSpecial(result): return 
@@ -1240,6 +1269,11 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
     if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode
     else: result = evalOp(m, n, a, b, cc)
   
+proc evalBindStmt(c: PEvalContext, n: PNode) =
+  for i in 0 .. < n.len:
+    let a = n.sons[i]
+    if a.kind == nkSym: StrTableAdd(c.boundSyms, a.sym)
+  
 proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = 
   result = emptyNode
   dec(gNestedEvals)
@@ -1310,6 +1344,8 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
     result.typ = n.typ
   of nkPragmaBlock:
     result = evalAux(c, n.sons[1], flags)
+  of nkBindStmt:
+    evalBindStmt(c, n)
   of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, 
      nkLambdaKinds, nkContinueStmt, nkIdent, nkParForStmt: 
     result = raiseCannotEval(c, n.info)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index b8bf9e970..3bd368b7e 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1118,6 +1118,22 @@ proc insertDestructors(c: PContext, varSection: PNode):
 
       return
 
+proc semBindStmtForMacro(c: PContext, n: PNode): PNode =
+  if c.p.owner.kind != skMacro:
+    LocalError(n.info, errXNotAllowedHere, "bind")
+  result = newNodeI(nkBindStmt, n.info)
+  for i in 0 .. < n.len:
+    var a = n.sons[i]
+    let s = QualifiedLookUp(c, a)
+    if s != nil:
+      # we need to mark all symbols:
+      let sc = symChoice(c, a, s)
+      if sc.kind == nkSym: result.add(sc)
+      else:
+        for x in items(sc): result.add(x)
+    else:
+      illFormedAst(a)
+
 proc SemStmt(c: PContext, n: PNode): PNode = 
   const                       # must be last statements in a block:
     LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
@@ -1206,6 +1222,8 @@ proc SemStmt(c: PContext, n: PNode): PNode =
     result = semPragmaBlock(c, n)
   of nkStaticStmt:
     result = semStaticStmt(c, n)
+  of nkBindStmt:
+    result = semBindStmtForMacro(c, n)
   else: 
     # in interactive mode, we embed the expression in an 'echo':
     if gCmd == cmdInteractive: