about summary refs log tree commit diff
path: root/src/libexpr/eval.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r--src/libexpr/eval.cc152
1 files changed, 82 insertions, 70 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 15cccc6b7f56..95a70ac2736b 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -74,63 +74,87 @@ LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2,
 }
 
 
-/* Substitute an argument set into the body of a function. */
-static Expr substArgs(EvalState & state,
-    Expr body, ATermList formals, Expr arg)
+static void patternMatch(EvalState & state,
+    Pattern pat, Expr arg, ATermMap & subs)
 {
-    unsigned int nrFormals = ATgetLength(formals);
-    ATermMap subs(nrFormals);
-
-    /* Get the actual arguments and put them in the substitution. */
-    ATermMap args;
-    queryAllAttrs(arg, args);
-    for (ATermMap::const_iterator i = args.begin(); i != args.end(); ++i)
-        subs.set(i->key, i->value);
+    ATerm name;
+    ATermList formals;
     
-    /* Get the formal arguments. */
-    ATermVector defsUsed;
-    ATermList recAttrs = ATempty;
-    for (ATermIterator i(formals); i; ++i) {
-        Expr name, def;
-        DefaultValue def2;
-        if (!matchFormal(*i, name, def2)) abort(); /* can't happen */
-
-        Expr value = subs[name];
-        
-        if (value == 0) {
-            if (!matchDefaultValue(def2, def)) def = 0;
-            if (def == 0) throw TypeError(format("the argument named `%1%' required by the function is missing")
-                % aterm2String(name));
-            value = def;
-            defsUsed.push_back(name);
-            recAttrs = ATinsert(recAttrs, makeBind(name, def, makeNoPos()));
-        }
-    }
+    if (matchVarPat(pat, name)) 
+        subs.set(name, arg);
+
+    else if (matchAttrsPat(pat, formals)) {
+
+        arg = evalExpr(state, arg);
+
+        unsigned int nrFormals = ATgetLength(formals);
 
-    /* Make a recursive attribute set out of the (argument-name,
-       value) tuples.  This is so that we can support default
-       parameters that refer to each other, e.g.  ({x, y ? x + x}: y)
-       {x = "foo";} evaluates to "foofoo". */
-    if (defsUsed.size() != 0) {
+        /* Get the actual arguments and put them in the substitution.
+           !!! shouldn't do this once we add `...'.*/
+        ATermMap args;
+        queryAllAttrs(arg, args);
         for (ATermMap::const_iterator i = args.begin(); i != args.end(); ++i)
-            recAttrs = ATinsert(recAttrs, makeBind(i->key, i->value, makeNoPos()));
-        Expr rec = makeRec(recAttrs, ATempty);
-        for (ATermVector::iterator i = defsUsed.begin(); i != defsUsed.end(); ++i)
-            subs.set(*i, makeSelect(rec, *i));
-    }
-    
-    if (subs.size() != nrFormals) {
-        /* One or more actual arguments were not declared as formal
-           arguments.  Find out which. */
+            subs.set(i->key, i->value);
+        
+        /* Get the formal arguments. */
+        ATermVector defsUsed;
+        ATermList recAttrs = ATempty;
         for (ATermIterator i(formals); i; ++i) {
-            Expr name; ATerm d1;
-            if (!matchFormal(*i, name, d1)) abort();
-            subs.remove(name);
+            Expr name, def;
+            DefaultValue def2;
+            if (!matchFormal(*i, name, def2)) abort(); /* can't happen */
+
+            Expr value = subs[name];
+        
+            if (value == 0) {
+                if (!matchDefaultValue(def2, def)) def = 0;
+                if (def == 0) throw TypeError(format("the argument named `%1%' required by the function is missing")
+                    % aterm2String(name));
+                value = def;
+                defsUsed.push_back(name);
+                recAttrs = ATinsert(recAttrs, makeBind(name, def, makeNoPos()));
+            }
+
+        }
+        
+        /* Make a recursive attribute set out of the (argument-name,
+           value) tuples.  This is so that we can support default
+           parameters that refer to each other, e.g.  ({x, y ? x + x}:
+           y) {x = "foo";} evaluates to "foofoo". */
+        if (defsUsed.size() != 0) {
+            for (ATermMap::const_iterator i = args.begin(); i != args.end(); ++i)
+                recAttrs = ATinsert(recAttrs, makeBind(i->key, i->value, makeNoPos()));
+            Expr rec = makeRec(recAttrs, ATempty);
+            for (ATermVector::iterator i = defsUsed.begin(); i != defsUsed.end(); ++i)
+                subs.set(*i, makeSelect(rec, *i));
+        }
+    
+        if (subs.size() != nrFormals) {
+            /* One or more actual arguments were not declared as
+               formal arguments.  Find out which. */
+            for (ATermIterator i(formals); i; ++i) {
+                Expr name; ATerm d1;
+                if (!matchFormal(*i, name, d1)) abort();
+                subs.remove(name);
+            }
+            throw TypeError(format("the function does not expect an argument named `%1%'")
+                % aterm2String(subs.begin()->key));
         }
-        throw TypeError(format("the function does not expect an argument named `%1%'")
-            % aterm2String(subs.begin()->key));
+
     }
 
+    else abort();
+}
+
+
+/* Substitute an argument set into the body of a function. */
+static Expr substArgs(EvalState & state,
+    Expr body, Pattern pat, Expr arg)
+{
+    ATermMap subs(16);
+    
+    patternMatch(state, pat, arg, subs);
+
     return substitute(Substitution(0, &subs), body);
 }
 
@@ -370,10 +394,12 @@ Path coerceToPath(EvalState & state, Expr e, PathSet & context)
 
 Expr autoCallFunction(Expr e, const ATermMap & args)
 {
-    ATermList formals;
+    Pattern pat;
     ATerm body, pos;
-    
-    if (matchFunction(e, formals, body, pos)) {
+    ATermList formals;
+
+    /* !!! this should be more general */
+    if (matchFunction(e, pat, body, pos) && matchAttrsPat(pat, formals)) {
         ATermMap actualArgs(ATgetLength(formals));
         
         for (ATermIterator i(formals); i; ++i) {
@@ -418,8 +444,8 @@ LocalNoInline(Expr evalVar(EvalState & state, ATerm name))
 
 LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
 {
-    ATermList formals;
-    ATerm pos, name;
+    Pattern pat;
+    ATerm pos;
     Expr body;
         
     /* Evaluate the left-hand side. */
@@ -445,10 +471,9 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
             return makePrimOp(arity, funBlob, args);
     }
 
-    else if (matchFunction(fun, formals, body, pos)) {
-        arg = evalExpr(state, arg);
+    else if (matchFunction(fun, pat, body, pos)) {
         try {
-            return evalExpr(state, substArgs(state, body, formals, arg));
+            return evalExpr(state, substArgs(state, body, pat, arg));
         } catch (Error & e) {
             addErrorPrefix(e, "while evaluating the function at %1%:\n",
                 showPos(pos));
@@ -456,18 +481,6 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
         }
     }
         
-    else if (matchFunction1(fun, name, body, pos)) {
-        try {
-            ATermMap subs(1);
-            subs.set(name, arg);
-            return evalExpr(state, substitute(Substitution(0, &subs), body));
-        } catch (Error & e) {
-            addErrorPrefix(e, "while evaluating the function at %1%:\n",
-                showPos(pos));
-            throw;
-        }
-    }
-
     else throwTypeError(
         "attempt to call something which is neither a function nor a primop (built-in operation) but %1%",
         showType(fun));
@@ -624,7 +637,6 @@ Expr evalExpr2(EvalState & state, Expr e)
         sym == symInt ||
         sym == symBool ||
         sym == symFunction ||
-        sym == symFunction1 ||
         sym == symAttrs ||
         sym == symList ||
         sym == symPrimOp)