diff options
Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r-- | src/libexpr/eval.cc | 152 |
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) |