summary refs log tree commit diff stats
path: root/compiler/evaltempl.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/evaltempl.nim')
-rw-r--r--compiler/evaltempl.nim60
1 files changed, 44 insertions, 16 deletions
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 2b3112909..82c4e8f57 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -25,16 +25,21 @@ 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 and sfGenSym notin s.flags:
-        let x = actual.sons[s.position]
-        if x.kind == nkArgList:
-          for y in items(x): result.add(y)
-        else:
-          result.add copyTree(x)
+        handleParam actual.sons[s.position]
+      elif s.kind == 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,22 +61,45 @@ 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
+    # XXX: Since immediate templates are not subjected to the
+    # standard sigmatching algorithm, they will have a number
+    # of deficiencies when it comes to generic params:
+    # Type dependencies between the parameters won't be honoured
+    # and the bound generic symbols won't be resolvable within
+    # their bodies. We could try to fix this, but it may be
+    # wiser to just deprecate immediate templates and macros
+    # now that we have working untyped parameters.
+    genericParams = if sfImmediate in s.flags: 0
+                    else: 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]
+
+  # handle parameters with default values, which were
+  # not supplied by the user
+  for i in givenRegularParams+1 .. expectedRegularParams:
+    let default = s.typ.n.sons[i].sym.ast
+    internalAssert default != nil
+    if default.kind == nkEmpty:
       localError(n.info, errWrongNumberOfArguments)
       addSon(result, ast.emptyNode)
     else:
-      addSon(result, arg)
+      addSon(result, default.copyTree)
+  
+  # add any generic paramaters
+  for i in 1 .. genericParams:
+    result.addSon n.sons[givenRegularParams + i]
 
 var evalTemplateCounter* = 0
   # to prevent endless recursion in templates instantiation