diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 7ee157c316..b4d76a137a 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 ce1c4673d7..9637fd304d 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 8fe5d379af..0d14623ccc 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(, )", formals, + return ATmake("Function(, )", + substitute(subs, (ATerm) formals), substitute(subs2, body)); } + if (atMatch(m, e) >> "Function" >> name >> body) { + ATermMap subs2(subs); + subs2.remove(name); + return ATmake("Function1(, )", 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 bfd539a3f0..44d1e06abe 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(, )", $2, $5); } + | ID ':' expr_function + { $$ = ATmake("Function1(, )", $1, $3); } | expr_assert ; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 92683fcac5..6c2bb33e46 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; - - 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 ""; - int n; - if (atMatch(m, e) >> "Int" >> n) { + + 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(""); + + 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, "[]", &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;