summary refs log tree commit diff stats
path: root/compiler/evaltempl.nim
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2015-01-05 03:51:18 +0200
committerZahary Karadjov <zahary@gmail.com>2015-01-05 03:53:31 +0200
commit5e4ae8dbb4f5e3ca8cf8c1fb356ca0f500f32746 (patch)
treec82179fc1484c78bcebc85b74e9ef9ad5a5ac362 /compiler/evaltempl.nim
parent13a18663d21bff04be0ae4659d5e6fe9b1f31a28 (diff)
downloadNim-5e4ae8dbb4f5e3ca8cf8c1fb356ca0f500f32746.tar.gz
fix #1858; Add support for generic templates and macros
Implementation notes:
Just after overload resolution, the resolved generic params will be added to the
call expression to be later processed in evalTemplate and evalMacroCall. These
procs have been modified to handle the increased number of parameters, but one
remaining issue is that immediate templates and macros don't go through the same
process. The next commit will outlaw the use of generic parameters with such macros.
Diffstat (limited to 'compiler/evaltempl.nim')
-rw-r--r--compiler/evaltempl.nim50
1 files changed, 33 insertions, 17 deletions
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 78cc691c0..ecb898d8a 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -25,16 +25,22 @@ proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
   if ctx.instLines: result.info = b.info
 
 proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
+  template handleParam(param) =
+    let x = param
+    if x.kind == nkArgList:
+      for y in items(x): result.add(y)
+    else:
+      result.add copyTree(x)
+
   case templ.kind
   of nkSym:
     var s = templ.sym
     if s.owner.id == c.owner.id:
-      if s.kind == skParam:
-        let x = actual.sons[s.position]
-        if x.kind == nkArgList:
-          for y in items(x): result.add(y)
-        else:
-          result.add copyTree(x)
+      case s.kind
+      of skParam:
+        handleParam actual.sons[s.position]
+      of skGenericParam:
+        handleParam actual.sons[s.owner.typ.len + s.position - 1]
       else:
         internalAssert sfGenSym in s.flags
         var x = PSym(idTableGet(c.mapping, s))
@@ -56,21 +62,31 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
 proc evalTemplateArgs(n: PNode, s: PSym): PNode =
   # if the template has zero arguments, it can be called without ``()``
   # `n` is then a nkSym or something similar
-  var a: int
-  case n.kind
-  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
-    a = sonsLen(n)
-  else: a = 0
-  var f = s.typ.sonsLen
-  if a > f: globalError(n.info, errWrongNumberOfArguments)
+  var totalParams = case n.kind
+    of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: <n.len
+    else: 0
+
+  var
+    genericParams = s.ast[genericParamsPos].len
+    expectedRegularParams = <s.typ.len
+    givenRegularParams = totalParams - genericParams
+
+  if totalParams > expectedRegularParams + genericParams:
+    globalError(n.info, errWrongNumberOfArguments)
 
   result = newNodeI(nkArgList, n.info)
-  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:
+  for i in 1 .. givenRegularParams:
+    result.addSon n.sons[i]
+
+  for i in givenRegularParams+1 .. expectedRegularParams:
+    let default = s.typ.n.sons[i].sym.ast
+    if default.kind == nkEmpty:
       localError(n.info, errWrongNumberOfArguments)
-    addSon(result, arg)
+    result.addSon default.copyTree
 
+  for i in 1 .. genericParams:
+    result.addSon n.sons[givenRegularParams + i]
+  
 var evalTemplateCounter* = 0
   # to prevent endless recursion in templates instantiation