about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval.cc7
-rw-r--r--src/libexpr/lexer.l2
-rw-r--r--src/libexpr/nixexpr.cc19
-rw-r--r--src/libexpr/parser.y2
-rw-r--r--src/libexpr/primops.cc70
5 files changed, 63 insertions, 37 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 7ee157c316ac..b4d76a137a1a 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -195,6 +195,7 @@ Expr evalExpr2(EvalState & state, Expr e)
          cons == "Int" ||
          cons == "Bool" ||
          cons == "Function" ||
+         cons == "Function1" ||
          cons == "Attrs" ||
          cons == "List"))
         return e;
@@ -226,6 +227,12 @@ Expr evalExpr2(EvalState & state, Expr e)
             return evalExpr(state, 
                 substArgs(e4, formals, evalExpr(state, e2)));
         
+        else if (atMatch(m, e1) >> "Function1" >> name >> e4) {
+            ATermMap subs;
+            subs.set(name, e2);
+            return evalExpr(state, substitute(subs, e4));
+        }
+        
         else throw badTerm("expecting a function or primop", e1);
     }
 
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index ce1c4673d7a6..9637fd304db7 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -38,7 +38,7 @@ ID          [a-zA-Z\_][a-zA-Z0-9\_\']*
 INT         [0-9]+
 STR         \"[^\n\"]*\"
 PATH        [a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+
-URI         [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']*
+URI         [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+
 
 
 %%
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 8fe5d379af71..0d14623ccca0 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -194,10 +194,18 @@ Expr substitute(const ATermMap & subs, Expr e)
                 abort();
             subs2.remove(name);
         }
-        return ATmake("Function(<term>, <term>)", formals,
+        return ATmake("Function(<term>, <term>)",
+            substitute(subs, (ATerm) formals),
             substitute(subs2, body));
     }
 
+    if (atMatch(m, e) >> "Function" >> name >> body) {
+        ATermMap subs2(subs);
+        subs2.remove(name);
+        return ATmake("Function1(<term>, <term>)", name,
+            substitute(subs2, body));
+    }
+        
     /* Idem for a mutually recursive attribute set. */
     ATermList rbnds, nrbnds;
     if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) {
@@ -249,7 +257,6 @@ void checkVarDefs(const ATermMap & defs, Expr e)
         if (!defs.get(name))
             throw Error(format("undefined variable `%1%'")
                 % aterm2String(name));
-        return;
     }
 
     else if (atMatch(m, e) >> "Function" >> formals >> body) {
@@ -263,7 +270,13 @@ void checkVarDefs(const ATermMap & defs, Expr e)
                     abort();
             defs2.set(name, (ATerm) ATempty);
         }
-        return checkVarDefs(defs2, body);
+        checkVarDefs(defs2, body);
+    }
+        
+    else if (atMatch(m, e) >> "Function1" >> name >> body) {
+        ATermMap defs2(defs);
+        defs2.set(name, (ATerm) ATempty);
+        checkVarDefs(defs2, body);
     }
         
     else if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) {
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index bfd539a3f094..44d1e06abefa 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -54,6 +54,8 @@ expr: expr_function;
 expr_function
   : '{' formals '}' ':' expr_function
     { $$ = ATmake("Function(<term>, <term>)", $2, $5); }
+  | ID ':' expr_function
+    { $$ = ATmake("Function1(<term>, <term>)", $1, $3); }
   | expr_assert
   ;
 
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 92683fcac53d..6c2bb33e461f 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -76,27 +76,28 @@ static string addInput(EvalState & state,
 }
 
 
-static string processBinding(EvalState & state, Expr e, StoreExpr & ne)
+static void processBinding(EvalState & state, Expr e, StoreExpr & ne,
+    Strings & ss)
 {
     e = evalExpr(state, e);
 
     ATMatcher m;
     string s;
     ATermList es;
+    int n;
 
-    if (atMatch(m, e) >> "Str" >> s) return s;
-    if (atMatch(m, e) >> "Uri" >> s) return s;
-    if (atMatch(m, e) >> "Bool" >> "True") return "1";
-    if (atMatch(m, e) >> "Bool" >> "False") return "";
+    if (atMatch(m, e) >> "Str" >> s) ss.push_back(s);
+    else if (atMatch(m, e) >> "Uri" >> s) ss.push_back(s);
+    else if (atMatch(m, e) >> "Bool" >> "True") ss.push_back("1");
+    else if (atMatch(m, e) >> "Bool" >> "False") ss.push_back("");
 
-    int n;
-    if (atMatch(m, e) >> "Int" >> n) {
+    else if (atMatch(m, e) >> "Int" >> n) {
         ostringstream st;
         st << n;
-        return st.str();
+        ss.push_back(st.str());
     }
 
-    if (atMatch(m, e) >> "Attrs") {
+    else if (atMatch(m, e) >> "Attrs") {
         Expr a = queryAttr(e, "type");
         if (a && evalString(state, a) == "derivation") {
             a = queryAttr(e, "drvPath");
@@ -109,29 +110,38 @@ static string processBinding(EvalState & state, Expr e, StoreExpr & ne)
 
             state.drvHashes[drvPath] = drvHash;
             
-            return addInput(state, drvPath, ne);
-        }
+            ss.push_back(addInput(state, drvPath, ne));
+        } else
+            throw badTerm("invalid derivation binding", e);
     }
 
-    if (atMatch(m, e) >> "Path" >> s) {
+    else if (atMatch(m, e) >> "Path" >> s) {
         Path drvPath = copyAtom(state, s);
-        return addInput(state, drvPath, ne);
+        ss.push_back(addInput(state, drvPath, ne));
     }
     
-    if (atMatch(m, e) >> "List" >> es) {
-	string s;
-	bool first = true;
+    else if (atMatch(m, e) >> "List" >> es) {
         for (ATermIterator i(es); i; ++i) {
             startNest(nest, lvlVomit, format("processing list element"));
-	    if (!first) s = s + " "; else first = false;
-	    s += processBinding(state, evalExpr(state, *i), ne);
+	    processBinding(state, evalExpr(state, *i), ne, ss);
         }
-	return s;
     }
 
-    if (atMatch(m, e) >> "Null") return "";
+    else if (atMatch(m, e) >> "Null") ss.push_back("");
     
-    throw badTerm("invalid derivation binding", e);
+    else throw badTerm("invalid derivation binding", e);
+}
+
+
+static string concatStrings(const Strings & ss)
+{
+    string s;
+    bool first = true;
+    for (Strings::const_iterator i = ss.begin(); i != ss.end(); ++i) {
+        if (!first) s += " "; else first = false;
+        s += *i;
+    }
+    return s;
 }
 
 
@@ -157,26 +167,20 @@ Expr primDerivation(EvalState & state, Expr args)
         Expr value = attrs.get(key);
         startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
 
+        Strings ss;
+        processBinding(state, value, ne, ss);
+
         /* The `args' attribute is special: it supplies the
            command-line arguments to the builder. */
         if (key == "args") {
-            throw Error("args not implemented");
-#if 0
-            ATermList args;
-            if (!(ATmatch(value, "[<list>]", &args))
-                throw badTerm("list expected", value);
-            while (!ATisEmpty(args)) {
-                Expr arg = evalExpr(state, ATgetFirst(args));
-                ne.derivation.args.push_back(processBinding(state, arg, ne));
-                args = ATgetNext(args);
-            }
-#endif
+            for (Strings::iterator i = ss.begin(); i != ss.end(); ++i)
+                ne.derivation.args.push_back(*i);
         }
 
         /* All other attributes are passed to the builder through the
            environment. */
         else {
-            string s = processBinding(state, value, ne);
+            string s = concatStrings(ss);
             ne.derivation.env[key] = s;
             if (key == "builder") ne.derivation.builder = s;
             else if (key == "system") ne.derivation.platform = s;