diff options
author | Eelco Dolstra <e.dolstra@tudelft.nl> | 2008-08-14T10·04+0000 |
---|---|---|
committer | Eelco Dolstra <e.dolstra@tudelft.nl> | 2008-08-14T10·04+0000 |
commit | efe4b690ae4de5f0adea99abb1176a64a099d433 (patch) | |
tree | 3ee26b49848b04b5f6dad8edc06509fe4d4ee067 /src/libexpr/eval.cc | |
parent | c03b729319997b4e38c3f586d7c76352228b22e7 (diff) |
* Refactoring: combine functions that take an attribute set and
functions that take a single argument (plain lambdas) into one AST node (Function) that contains a Pattern node describing the arguments. Current patterns are single lazy arguments (VarPat) and matching against an attribute set (AttrsPat). This refactoring allows other kinds of patterns to be added easily, such as Haskell-style @-patterns, or list pattern matching.
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) |