summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-08-26 02:47:17 +0200
committerAraq <rumpf_a@web.de>2012-08-26 02:47:17 +0200
commitb5b5e6e76df228f573ae86780c66889f4b426301 (patch)
tree10471ab5c2d742e6ea09974b1420002112459b3a
parent9a7f0cd8510a534a3f1e9d4275b8abd7825a94c6 (diff)
downloadNim-b5b5e6e76df228f573ae86780c66889f4b426301.tar.gz
distinguish properly between nkOpen and nkClosedSymChoice
-rwxr-xr-xcompiler/ast.nim8
-rwxr-xr-xcompiler/lookups.nim4
-rwxr-xr-xcompiler/renderer.nim5
-rwxr-xr-xcompiler/semcall.nim11
-rwxr-xr-xcompiler/semexprs.nim20
-rwxr-xr-xcompiler/semgnrc.nim13
-rw-r--r--compiler/semmagic.nim12
-rwxr-xr-xcompiler/semtempl.nim26
-rwxr-xr-xcompiler/sigmatch.nim2
-rwxr-xr-xcompiler/suggest.nim2
-rwxr-xr-xcompiler/trees.nim3
-rwxr-xr-xcompiler/types.nim2
-rwxr-xr-xdoc/manual.txt13
-rwxr-xr-xlib/core/macros.nim28
-rwxr-xr-xtodo.txt8
15 files changed, 107 insertions, 50 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index a6f169384..79adafcf8 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -104,7 +104,8 @@ type
 
     nkTableConstr,        # a table constructor {expr: expr}
     nkBind,               # ``bind expr`` node
-    nkSymChoice,          # symbol choice node
+    nkClosedSymChoice,    # symbol choice node; a list of nkSyms (closed)
+    nkOpenSymChoice,      # symbol choice node; a list of nkSyms (open)
     nkHiddenStdConv,      # an implicit standard type conversion
     nkHiddenSubConv,      # an implicit type conversion from a subtype
                           # to a supertype
@@ -473,6 +474,11 @@ const
     mInRange, mInSet, mRepr,
     mRand, 
     mCopyStr, mCopyStrLast}
+  # magics that require special semantic checking and
+  # thus cannot be overloaded (also documented in the spec!):
+  SpecialSemMagics* = {
+    mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf, 
+    mEcho, mShallowCopy, mExpandToAst}
 
 type 
   PNode* = ref TNode
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 9ab5d2c48..1717ab4fb 100755
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -230,7 +230,7 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
         LocalError(n.sons[1].info, errIdentifierExpected, 
                    renderTree(n.sons[1]))
         result = errorSym(c, n.sons[1])
-  of nkSymChoice: 
+  of nkClosedSymChoice, nkOpenSymChoice:
     o.mode = oimSymChoice
     result = n.sons[0].sym
     o.stackPtr = 1
@@ -269,7 +269,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
       result = n.sons[o.stackPtr].sym
       Incl(o.inSymChoice, result.id)
       inc(o.stackPtr)
-    else:
+    elif n.kind == nkOpenSymChoice:
       # try 'local' symbols too for Koenig's lookup:
       o.mode = oimSymChoiceLocalLookup
       o.stackPtr = c.tab.tos-1
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index a1a6de984..c24a22fd5 100755
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -379,7 +379,8 @@ proc lsub(n: PNode): int =
   of nkPar, nkCurly, nkBracket, nkClosure: result = lcomma(n) + 2
   of nkTableConstr:
     result = if n.len > 0: lcomma(n) + 2 else: len("{:}")
-  of nkSymChoice: result = lsons(n) + len("()") + sonsLen(n) - 1
+  of nkClosedSymChoice, nkOpenSymChoice: 
+    result = lsons(n) + len("()") + sonsLen(n) - 1
   of nkTupleTy: result = lcomma(n) + len("tuple[]")
   of nkDotExpr: result = lsons(n) + 1
   of nkBind: result = lsons(n) + len("bind_")
@@ -833,7 +834,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkParLe, "(")
     gcomma(g, n, 1)
     put(g, tkParRi, ")")
-  of nkSymChoice: 
+  of nkClosedSymChoice, nkOpenSymChoice:
     put(g, tkParLe, "(")
     for i in countup(0, sonsLen(n) - 1): 
       if i > 0: put(g, tkOpr, "|")
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index e4655c5ba..a5107bf64 100755
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -10,7 +10,7 @@
 ## This module implements semantic checking for calls. 
 # included from sem.nim
 
-proc sameMethodDispatcher(a, b: PSym): bool = 
+proc sameMethodDispatcher(a, b: PSym): bool =
   result = false
   if a.kind == skMethod and b.kind == skMethod: 
     var aa = lastSon(a.ast)
@@ -132,11 +132,11 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
     if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
       return explicitGenericInstError(n)
     result = explicitGenericSym(c, n, s)
-  elif a.kind == nkSymChoice:
+  elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
     # choose the generic proc with the proper number of type parameters.
     # XXX I think this could be improved by reusing sigmatch.ParamTypesMatch.
     # It's good enough for now.
-    result = newNodeI(nkSymChoice, n.info)
+    result = newNodeI(a.kind, n.info)
     for i in countup(0, len(a)-1): 
       var candidate = a.sons[i].sym
       if candidate.kind in {skProc, skMethod, skConverter, skIterator}: 
@@ -144,8 +144,9 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
         # type parameters:
         if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
           result.add(explicitGenericSym(c, n, candidate))
-    # get rid of nkSymChoice if not ambiguous:
-    if result.len == 1: result = result[0]
+    # get rid of nkClosedSymChoice if not ambiguous:
+    if result.len == 1 and a.kind == nkClosedSymChoice:
+      result = result[0]
     # candidateCount != 1: return explicitGenericInstError(n)
   else:
     result = explicitGenericInstError(n)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index cd53d6501..06014bf6f 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -58,7 +58,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     result.typ = errorType(c)
 
 proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
-  result = symChoice(c, n, s)
+  result = symChoice(c, n, s, scClosed)
   
 proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
   result = copyTree(s.ast)
@@ -72,7 +72,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     if sfProcVar notin s.flags and s.typ.callConv == ccDefault and
         smoduleId != c.module.id and smoduleId != c.friendModule.id: 
       LocalError(n.info, errXCannotBePassedToProcVar, s.name.s)
-    result = symChoice(c, n, s)
+    result = symChoice(c, n, s, scClosed)
     if result.kind == nkSym:
       markIndirect(c, result.sym)
       if isGenericRoutine(result.sym):
@@ -182,6 +182,9 @@ proc isCastable(dst, src: PType): bool =
         (skipTypes(dst, abstractInst).kind in IntegralTypes) or
         (skipTypes(src, abstractInst).kind in IntegralTypes)
   
+proc isSymChoice(n: PNode): bool {.inline.} =
+  result = n.kind in {nkClosedSymChoice, nkOpenSymChoice}
+
 proc semConv(c: PContext, n: PNode, s: PSym): PNode = 
   if sonsLen(n) != 2: 
     LocalError(n.info, errConvNeedsOneArg)
@@ -191,7 +194,7 @@ proc semConv(c: PContext, n: PNode, s: PSym): PNode =
   addSon(result, copyTree(n.sons[0]))
   addSon(result, semExprWithType(c, n.sons[1]))
   var op = result.sons[1]
-  if op.kind != nkSymChoice: 
+  if not isSymChoice(op):
     checkConvertible(result.info, result.typ, op.typ)
   else: 
     for i in countup(0, sonsLen(op) - 1):
@@ -830,7 +833,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if it's not a built-in field access
   checkSonsLen(n, 2)
   # early exit for this; see tests/compile/tbindoverload.nim:
-  if n.sons[1].kind == nkSymChoice: return
+  if isSymChoice(n.sons[1]): return
 
   var s = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
   if s != nil:
@@ -910,7 +913,7 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # in Nimrod. We first allow types in the semantic checking.
   result = builtinFieldAccess(c, n, flags)
   if result == nil:
-    if n.sons[1].kind == nkSymChoice: 
+    if isSymChoice(n.sons[1]):
       result = newNodeI(nkDotCall, n.info)
       addSon(result, n.sons[1])
       addSon(result, copyTree(n[0]))
@@ -1222,6 +1225,7 @@ proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
 proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = 
   # this is a hotspot in the compiler!
+  # DON'T forget to update ast.SpecialSemMagics if you add a magic here!
   result = n
   case s.magic # magics that need special treatment
   of mDefined: result = semDefined(c, setMs(n, s), false)
@@ -1518,8 +1522,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       else:
         #liMessage(n.info, warnUser, renderTree(n));
         result = semIndirectOp(c, n, flags)
-    elif n.sons[0].kind == nkSymChoice or n[0].kind == nkBracketExpr and 
-        n[0][0].kind == nkSymChoice:
+    elif isSymChoice(n.sons[0]) or n[0].kind == nkBracketExpr and 
+        isSymChoice(n[0][0]):
       result = semDirectOp(c, n, flags)
     else:
       result = semIndirectOp(c, n, flags)
@@ -1576,7 +1580,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     checkMinSonsLen(n, 2)
   of nkTableConstr:
     result = semTableConstr(c, n)
-  of nkSymChoice:
+  of nkClosedSymChoice, nkOpenSymChoice:
     LocalError(n.info, errExprXAmbiguous, renderTree(n, {renderNoComments}))
     # error correction: Pick first element:
     result = n.sons[0]
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 3a11f87ce..849d04fb1 100755
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -13,7 +13,7 @@
 # A problem is that it cannot be detected if the symbol is introduced
 # as in ``var x = ...`` or used because macros/templates can hide this!
 # So we have to eval templates/macros right here so that symbol
-# lookup can be accurate.
+# lookup can be accurate. XXX But this can only be done for immediate macros!
 
 # included from sem.nim
 
@@ -47,8 +47,8 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
     # Introduced in this pass! Leave it as an identifier.
     result = n
   of skProc, skMethod, skIterator, skConverter: 
-    result = symChoice(c, n, s)
-  of skTemplate: 
+    result = symChoice(c, n, s, scOpen)
+  of skTemplate:
     result = semTemplateExpr(c, n, s, false)
   of skMacro: 
     result = semMacroExpr(c, n, s, false)
@@ -75,7 +75,8 @@ proc semGenericStmt(c: PContext, n: PNode,
       if withinBind in flags:
         localError(n.info, errUndeclaredIdentifier, n.ident.s)
     else:
-      if withinBind in flags or s.id in toBind: result = symChoice(c, n, s)
+      if withinBind in flags or s.id in toBind:
+        result = symChoice(c, n, s, scClosed)
       else: result = semGenericStmtSymbol(c, n, s)
   of nkDotExpr:
     var s = QualifiedLookUp(c, n, {})
@@ -104,7 +105,7 @@ proc semGenericStmt(c: PContext, n: PNode,
       of skUnknown, skParam: 
         # Leave it as an identifier.
       of skProc, skMethod, skIterator, skConverter: 
-        result.sons[0] = symChoice(c, n.sons[0], s)
+        result.sons[0] = symChoice(c, n.sons[0], s, scOpen)
         first = 1
       of skGenericParam: 
         result.sons[0] = newSymNode(s, n.sons[0].info)
@@ -114,7 +115,7 @@ proc semGenericStmt(c: PContext, n: PNode,
         if (s.typ != nil) and (s.typ.kind != tyGenericParam): 
           result.sons[0] = newSymNode(s, n.sons[0].info)
           first = 1
-      else: 
+      else:
         result.sons[0] = newSymNode(s, n.sons[0].info)
         first = 1
     for i in countup(first, sonsLen(result) - 1): 
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index b4cc1727d..da179f0a7 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -49,16 +49,22 @@ proc semBindSym(c: PContext, n: PNode): PNode =
   result = copyNode(n)
   result.add(n.sons[0])
   
-  let sl = c.semConstExpr(c, n.sons[1])
+  let sl = semConstExpr(c, n.sons[1])
   if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}: 
-    LocalError(n.info, errStringLiteralExpected)
+    LocalError(n.sons[1].info, errStringLiteralExpected)
+    return errorNode(c, n)
+  
+  let isMixin = semConstExpr(c, n.sons[2])
+  if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
+      isMixin.intVal > high(TSymChoiceRule).int:
+    LocalError(n.sons[2].info, errConstExprExpected)
     return errorNode(c, n)
   
   let id = newIdentNode(getIdent(sl.strVal), n.info)
   let s = QualifiedLookUp(c, id)
   if s != nil:
     # we need to mark all symbols:
-    let sc = symChoice(c, id, s)
+    var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
     result.add(sc)
   else:
     LocalError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 780dded82..c16f4ce09 100755
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -40,8 +40,12 @@ proc symBinding(n: PNode): TSymBinding =
       of wInject: return spInject
       else: nil
 
-proc symChoice(c: PContext, n: PNode, s: PSym): PNode = 
-  var 
+type
+  TSymChoiceRule = enum
+    scClosed, scOpen, scForceOpen
+
+proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
+  var
     a: PSym
     o: TOverloadIter
   var i = 0
@@ -50,17 +54,17 @@ proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
     a = nextOverloadIter(o, c, n)
     inc(i)
     if i > 1: break
-  if i <= 1:
+  if i <= 1 and r != scForceOpen:
     # XXX this makes more sense but breaks bootstrapping for now:
     # (s.kind notin routineKinds or s.magic != mNone):
-    # for some reason 'nextTry' is copied and considered as a candidate in
-    # tables.nim
+    # for instance 'nextTry' is both in tables.nim and astalgo.nim ...
     result = newSymNode(s, n.info)
     markUsed(n, s)
   else:
     # semantic checking requires a type; ``fitNode`` deals with it
     # appropriately
-    result = newNodeIT(nkSymChoice, n.info, newTypeS(tyNone, c))
+    let kind = if r == scClosed: nkClosedSymChoice else: nkOpenSymChoice
+    result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
     a = initOverloadIter(o, c, n)
     while a != nil:
       incl(a.flags, sfUsed)
@@ -78,7 +82,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
     let s = QualifiedLookUp(c, a)
     if s != nil:
       # we need to mark all symbols:
-      let sc = symChoice(c, n, s)
+      let sc = symChoice(c, n, s, scClosed)
       if sc.kind == nkSym:
         toBind.incl(sc.sym.id)
       else:
@@ -178,7 +182,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
       elif Contains(c.toBind, s.id):
-        result = symChoice(c.c, n, s)
+        result = symChoice(c.c, n, s, scClosed)
       elif s.owner == c.owner:
         InternalAssert sfGenSym in s.flags
         incl(s.flags, sfUsed)
@@ -294,7 +298,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     if n.kind == nkDotExpr or n.kind == nkAccQuoted:
       let s = QualifiedLookUp(c.c, n, {})
       if s != nil and Contains(c.toBind, s.id):
-        return symChoice(c.c, n, s)
+        return symChoice(c.c, n, s, scClosed)
     result = n
     for i in countup(0, sonsLen(n) - 1):
       result.sons[i] = semTemplBody(c, n.sons[i])
@@ -308,7 +312,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam:
         result = newSymNode(s, n.info)
       elif Contains(c.toBind, s.id):
-        result = symChoice(c.c, n, s)
+        result = symChoice(c.c, n, s, scClosed)
   of nkBind:
     result = semTemplBodyDirty(c, n.sons[0])
   of nkBindStmt:
@@ -321,7 +325,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
     if n.kind == nkDotExpr or n.kind == nkAccQuoted:
       let s = QualifiedLookUp(c.c, n, {})
       if s != nil and Contains(c.toBind, s.id):
-        return symChoice(c.c, n, s)
+        return symChoice(c.c, n, s, scClosed)
     result = n
     for i in countup(0, sonsLen(n) - 1):
       result.sons[i] = semTemplBodyDirty(c, n.sons[i])
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index aab847c94..5057883c7 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -703,7 +703,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
 
 proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType, 
                      arg, argOrig: PNode): PNode = 
-  if arg == nil or arg.kind != nkSymChoice: 
+  if arg == nil or arg.kind != nkClosedSymChoice:
     result = ParamTypesMatchAux(c, m, f, a, arg, argOrig)
   else: 
     # CAUTION: The order depends on the used hashing scheme. Thus it is
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 3b9c77336..daecf44b8 100755
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -85,7 +85,7 @@ proc suggestObject(c: PContext, n: PNode, outputs: var int) =
 
 proc nameFits(c: PContext, s: PSym, n: PNode): bool = 
   var op = n.sons[0]
-  if op.kind == nkSymChoice: op = op.sons[0]
+  if op.kind in {nkOpenSymChoice, nkClosedSymChoice}: op = op.sons[0]
   var opr: PIdent
   case op.kind
   of nkSym: opr = op.sym.name
diff --git a/compiler/trees.nim b/compiler/trees.nim
index fb2e68548..e2c9b1b16 100755
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -143,7 +143,8 @@ proc SwapOperands*(op: PNode) =
 proc IsRange*(n: PNode): bool {.inline.} = 
   if n.kind == nkInfix:
     if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
-        n[0].kind == nkSymChoice and n[0][1].sym.name.id == ord(wDotDot):
+        n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and 
+        n[0][1].sym.name.id == ord(wDotDot):
       result = true
 
 proc whichPragma*(n: PNode): TSpecialWord = 
diff --git a/compiler/types.nim b/compiler/types.nim
index 8dae14924..aca168ba8 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -117,7 +117,7 @@ proc isCompatibleToCString(a: PType): bool =
       result = true
   
 proc getProcHeader(sym: PSym): string = 
-  result = sym.name.s & '('
+  result = sym.owner.name.s & '.' & sym.name.s & '('
   var n = sym.typ.n
   for i in countup(1, sonsLen(n) - 1): 
     var p = n.sons[i]
diff --git a/doc/manual.txt b/doc/manual.txt
index a78af89a6..e10c934f1 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -2362,6 +2362,19 @@ notation. (Thus an operator can have more than two parameters):
 

   assert `*+`(3, 4, 6) == `*`(a, `+`(b, c))

 

+
+Nonoverloadable builtins
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following builtin procs cannot be overloaded for reasons of implementation
+simplicity (they require specialized semantic checking)::
+
+  defined, definedInScope, compiles, low, high, sizeOf, 
+  is, of, echo, shallowCopy, getAst

+
+Thus they act more like keywords than like ordinary identifiers; unlike a 
+keyword however, a redefinition may `shadow`:id: the definition in 
+the ``system`` module.

 

 

 Var parameters

diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 30248528e..fac935430 100755
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -27,7 +27,10 @@ type
     nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange, 

     nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr, 

     nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted, 

-    nnkTableConstr, nnkBind, nnkSymChoice, nnkHiddenStdConv, 

+    nnkTableConstr, nnkBind,
+    nnkClosedSymChoice,
+    nnkOpenSymChoice,
+    nnkHiddenStdConv,

     nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast, nnkStaticExpr,

     nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, 

     nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, 

@@ -186,12 +189,29 @@ proc newIdentNode*(i: string): PNimrodNode {.compileTime.} =
   result = newNimNode(nnkIdent)

   result.ident = !i

 
-proc bindSym*(ident: string): PNimrodNode {.magic: "NBindSym".}
+type
+  TBindSymRule* = enum   ## specifies how ``bindSym`` behaves
+    brClosed,            ## only the symbols in current scope are bound
+    brOpen,              ## open wrt overloaded symbols, but may be a single
+                         ## symbol if not ambiguous (the rules match that of
+                         ## binding in generics)
+    brForceOpen          ## same as brOpen, but it will always be open even
+                         ## if not ambiguous (this cannot be achieved with
+                         ## any other means in the language currently)
+
+proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
+              magic: "NBindSym".}
   ## creates a node that binds `ident` to a symbol node. The bound symbol
-  ## needs to be predeclared in a ``bind`` statement!
+  ## may be an overloaded symbol.
+  ## If ``rule == brClosed`` either an ``nkClosedSymChoice`` tree is
+  ## returned or ``nkSym`` if the symbol is not ambiguous.
+  ## If ``rule == brOpen`` either an ``nkOpenSymChoice`` tree is
+  ## returned or ``nkSym`` if the symbol is not ambiguous.
+  ## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
+  ## returned even if the symbol is not ambiguous.
 

 proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =

-  ## converts the AST `n` to the concrete Nimrod code and wraps that 

+  ## converts the AST `n` to the concrete Nimrod code and wraps that

   ## in a string literal node

   return newStrLitNode(repr(n))

 

diff --git a/todo.txt b/todo.txt
index 58e3e067e..9d9917786 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,6 +1,10 @@
 version 0.9.0
 =============
 
+- make 'bind' default for templates and introduce 'mixin'
+- introduce 'callsite' magic and make macros and templates the same
+- implement generic templates/macros
+
 - implement "closure tuple consists of a single 'ref'" optimization
 - implement for loop transformation for first class iterators
 
@@ -29,8 +33,6 @@ Bugs
 version 0.9.XX
 ==============
 
-- make 'bind' default for templates and introduce 'mixin'
-- distinguish between open and closed nkSymChoice
 - JS gen:
   - fix exception handling
 
@@ -44,7 +46,6 @@ version 0.9.XX
 - ``hoist`` pragma for loop hoisting
 - document destructors; don't work yet when used as expression
 - make use of ``tyIter`` to fix the implicit items/pairs issue
-- introduce 'callsite' magic and make macros and templates the same
 - better support for macros that rewrite procs
 - macros need access to types and symbols
 - document nimdoc properly finally
@@ -56,7 +57,6 @@ version 0.9.XX
 - proc specialization in the code gen for write barrier specialization
 - tlastmod returns wrong results on BSD (Linux, MacOS X: works)
 - nested tuple unpacking; tuple unpacking in non-var-context
-- 'nimrod def': does not always work?
 - test branch coverage
 - make pegs support a compile-time option and make c2nim use regexes instead
   per default?