* 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.
This commit is contained in:
parent
c03b729319
commit
efe4b690ae
12 changed files with 184 additions and 148 deletions
|
@ -74,62 +74,86 @@ LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void patternMatch(EvalState & state,
|
||||||
|
Pattern pat, Expr arg, ATermMap & subs)
|
||||||
|
{
|
||||||
|
ATerm name;
|
||||||
|
ATermList formals;
|
||||||
|
|
||||||
|
if (matchVarPat(pat, name))
|
||||||
|
subs.set(name, arg);
|
||||||
|
|
||||||
|
else if (matchAttrsPat(pat, formals)) {
|
||||||
|
|
||||||
|
arg = evalExpr(state, arg);
|
||||||
|
|
||||||
|
unsigned int nrFormals = ATgetLength(formals);
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
subs.set(i->key, i->value);
|
||||||
|
|
||||||
|
/* 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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Substitute an argument set into the body of a function. */
|
/* Substitute an argument set into the body of a function. */
|
||||||
static Expr substArgs(EvalState & state,
|
static Expr substArgs(EvalState & state,
|
||||||
Expr body, ATermList formals, Expr arg)
|
Expr body, Pattern pat, Expr arg)
|
||||||
{
|
{
|
||||||
unsigned int nrFormals = ATgetLength(formals);
|
ATermMap subs(16);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Get the formal arguments. */
|
patternMatch(state, pat, arg, subs);
|
||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
return substitute(Substitution(0, &subs), body);
|
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)
|
Expr autoCallFunction(Expr e, const ATermMap & args)
|
||||||
{
|
{
|
||||||
ATermList formals;
|
Pattern pat;
|
||||||
ATerm body, pos;
|
ATerm body, pos;
|
||||||
|
ATermList formals;
|
||||||
if (matchFunction(e, formals, body, pos)) {
|
|
||||||
|
/* !!! this should be more general */
|
||||||
|
if (matchFunction(e, pat, body, pos) && matchAttrsPat(pat, formals)) {
|
||||||
ATermMap actualArgs(ATgetLength(formals));
|
ATermMap actualArgs(ATgetLength(formals));
|
||||||
|
|
||||||
for (ATermIterator i(formals); i; ++i) {
|
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))
|
LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
|
||||||
{
|
{
|
||||||
ATermList formals;
|
Pattern pat;
|
||||||
ATerm pos, name;
|
ATerm pos;
|
||||||
Expr body;
|
Expr body;
|
||||||
|
|
||||||
/* Evaluate the left-hand side. */
|
/* Evaluate the left-hand side. */
|
||||||
|
@ -445,10 +471,9 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
|
||||||
return makePrimOp(arity, funBlob, args);
|
return makePrimOp(arity, funBlob, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (matchFunction(fun, formals, body, pos)) {
|
else if (matchFunction(fun, pat, body, pos)) {
|
||||||
arg = evalExpr(state, arg);
|
|
||||||
try {
|
try {
|
||||||
return evalExpr(state, substArgs(state, body, formals, arg));
|
return evalExpr(state, substArgs(state, body, pat, arg));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
addErrorPrefix(e, "while evaluating the function at %1%:\n",
|
addErrorPrefix(e, "while evaluating the function at %1%:\n",
|
||||||
showPos(pos));
|
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(
|
else throwTypeError(
|
||||||
"attempt to call something which is neither a function nor a primop (built-in operation) but %1%",
|
"attempt to call something which is neither a function nor a primop (built-in operation) but %1%",
|
||||||
showType(fun));
|
showType(fun));
|
||||||
|
@ -624,7 +637,6 @@ Expr evalExpr2(EvalState & state, Expr e)
|
||||||
sym == symInt ||
|
sym == symInt ||
|
||||||
sym == symBool ||
|
sym == symBool ||
|
||||||
sym == symFunction ||
|
sym == symFunction ||
|
||||||
sym == symFunction1 ||
|
|
||||||
sym == symAttrs ||
|
sym == symAttrs ||
|
||||||
sym == symList ||
|
sym == symList ||
|
||||||
sym == symPrimOp)
|
sym == symPrimOp)
|
||||||
|
|
|
@ -40,6 +40,23 @@ static void showAttrs(const ATermMap & attrs, XMLWriter & doc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void printPatternAsXML(Pattern pat, XMLWriter & doc, PathSet & context)
|
||||||
|
{
|
||||||
|
ATerm name;
|
||||||
|
ATermList formals;
|
||||||
|
if (matchVarPat(pat, name))
|
||||||
|
doc.writeEmptyElement("varpat", singletonAttrs("name", aterm2String(name)));
|
||||||
|
else if (matchAttrsPat(pat, formals)) {
|
||||||
|
XMLOpenElement _(doc, "attrspat");
|
||||||
|
for (ATermIterator i(formals); i; ++i) {
|
||||||
|
Expr name; ATerm dummy;
|
||||||
|
if (!matchFormal(*i, name, dummy)) abort();
|
||||||
|
doc.writeEmptyElement("attr", singletonAttrs("name", aterm2String(name)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
|
static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
|
||||||
ExprSet & drvsSeen)
|
ExprSet & drvsSeen)
|
||||||
{
|
{
|
||||||
|
@ -47,8 +64,8 @@ static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
|
||||||
string s;
|
string s;
|
||||||
ATerm s2;
|
ATerm s2;
|
||||||
int i;
|
int i;
|
||||||
ATermList as, es, formals;
|
ATermList as, es;
|
||||||
ATerm body, pos;
|
ATerm pat, body, pos;
|
||||||
|
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
|
@ -109,14 +126,9 @@ static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
|
||||||
printTermAsXML(*i, doc, context, drvsSeen);
|
printTermAsXML(*i, doc, context, drvsSeen);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (matchFunction(e, formals, body, pos)) {
|
else if (matchFunction(e, pat, body, pos)) {
|
||||||
XMLOpenElement _(doc, "function");
|
XMLOpenElement _(doc, "function");
|
||||||
|
printPatternAsXML(pat, doc, context);
|
||||||
for (ATermIterator i(formals); i; ++i) {
|
|
||||||
Expr name; ATerm dummy;
|
|
||||||
if (!matchFormal(*i, name, dummy)) abort();
|
|
||||||
XMLOpenElement _(doc, "arg", singletonAttrs("name", aterm2String(name)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
|
@ -3,8 +3,7 @@ init initNixExprHelpers
|
||||||
Pos | string int int | Pos |
|
Pos | string int int | Pos |
|
||||||
NoPos | | Pos |
|
NoPos | | Pos |
|
||||||
|
|
||||||
Function | ATermList Expr Pos | Expr |
|
Function | Pattern Expr Pos | Expr |
|
||||||
Function1 | string Expr Pos | Expr |
|
|
||||||
Assert | Expr Expr Pos | Expr |
|
Assert | Expr Expr Pos | Expr |
|
||||||
With | Expr Expr Pos | Expr |
|
With | Expr Expr Pos | Expr |
|
||||||
If | Expr Expr Expr | Expr |
|
If | Expr Expr Expr | Expr |
|
||||||
|
@ -76,6 +75,9 @@ Inherit | Expr ATermList Pos | ATerm |
|
||||||
|
|
||||||
Scope | | Expr |
|
Scope | | Expr |
|
||||||
|
|
||||||
|
VarPat | string | Pattern |
|
||||||
|
AttrsPat | ATermList | Pattern |
|
||||||
|
|
||||||
Formal | string DefaultValue | ATerm |
|
Formal | string DefaultValue | ATerm |
|
||||||
|
|
||||||
DefaultValue | Expr | DefaultValue |
|
DefaultValue | Expr | DefaultValue |
|
||||||
|
|
|
@ -110,6 +110,25 @@ Expr makeAttrs(const ATermMap & attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void varsBoundByPattern(ATermMap & map, Pattern pat)
|
||||||
|
{
|
||||||
|
ATerm name;
|
||||||
|
ATermList formals;
|
||||||
|
/* Use makeRemoved() so that it can be used directly in
|
||||||
|
substitute(). */
|
||||||
|
if (matchVarPat(pat, name))
|
||||||
|
map.set(name, makeRemoved());
|
||||||
|
else if (matchAttrsPat(pat, formals)) {
|
||||||
|
for (ATermIterator i(formals); i; ++i) {
|
||||||
|
ATerm d1;
|
||||||
|
if (!matchFormal(*i, name, d1)) abort();
|
||||||
|
map.set(name, makeRemoved());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr substitute(const Substitution & subs, Expr e)
|
Expr substitute(const Substitution & subs, Expr e)
|
||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
@ -135,27 +154,17 @@ Expr substitute(const Substitution & subs, Expr e)
|
||||||
|
|
||||||
/* In case of a function, filter out all variables bound by this
|
/* In case of a function, filter out all variables bound by this
|
||||||
function. */
|
function. */
|
||||||
ATermList formals;
|
Pattern pat;
|
||||||
ATerm body;
|
ATerm body;
|
||||||
if (matchFunction(e, formals, body, pos)) {
|
if (matchFunction(e, pat, body, pos)) {
|
||||||
ATermMap map(ATgetLength(formals));
|
ATermMap map(16);
|
||||||
for (ATermIterator i(formals); i; ++i) {
|
varsBoundByPattern(map, pat);
|
||||||
ATerm d1;
|
|
||||||
if (!matchFormal(*i, name, d1)) abort();
|
|
||||||
map.set(name, makeRemoved());
|
|
||||||
}
|
|
||||||
Substitution subs2(&subs, &map);
|
Substitution subs2(&subs, &map);
|
||||||
return makeFunction(
|
return makeFunction(
|
||||||
(ATermList) substitute(subs2, (ATerm) formals),
|
(Pattern) substitute(subs2, (Expr) pat),
|
||||||
substitute(subs2, body), pos);
|
substitute(subs2, body), pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchFunction1(e, name, body, pos)) {
|
|
||||||
ATermMap map(1);
|
|
||||||
map.set(name, makeRemoved());
|
|
||||||
return makeFunction1(name, substitute(Substitution(&subs, &map), body), pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Idem for a mutually recursive attribute set. */
|
/* Idem for a mutually recursive attribute set. */
|
||||||
ATermList rbnds, nrbnds;
|
ATermList rbnds, nrbnds;
|
||||||
if (matchRec(e, rbnds, nrbnds)) {
|
if (matchRec(e, rbnds, nrbnds)) {
|
||||||
|
@ -213,9 +222,9 @@ static void checkVarDefs2(set<Expr> & done, const ATermMap & defs, Expr e)
|
||||||
done.insert(e);
|
done.insert(e);
|
||||||
|
|
||||||
ATerm name, pos, value;
|
ATerm name, pos, value;
|
||||||
ATermList formals;
|
|
||||||
ATerm with, body;
|
ATerm with, body;
|
||||||
ATermList rbnds, nrbnds;
|
ATermList rbnds, nrbnds;
|
||||||
|
Pattern pat;
|
||||||
|
|
||||||
/* Closed terms don't have free variables, so we don't have to
|
/* Closed terms don't have free variables, so we don't have to
|
||||||
check by definition. */
|
check by definition. */
|
||||||
|
@ -227,27 +236,11 @@ static void checkVarDefs2(set<Expr> & done, const ATermMap & defs, Expr e)
|
||||||
% aterm2String(name));
|
% aterm2String(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (matchFunction(e, formals, body, pos)) {
|
else if (matchFunction(e, pat, body, pos)) {
|
||||||
ATermMap defs2(defs);
|
ATermMap defs2(defs);
|
||||||
for (ATermIterator i(formals); i; ++i) {
|
varsBoundByPattern(defs2, pat);
|
||||||
ATerm d1;
|
|
||||||
if (!matchFormal(*i, name, d1)) abort();
|
|
||||||
defs2.set(name, (ATerm) ATempty);
|
|
||||||
}
|
|
||||||
for (ATermIterator i(formals); i; ++i) {
|
|
||||||
ATerm deflt;
|
|
||||||
set<Expr> done2;
|
|
||||||
if (!matchFormal(*i, name, deflt)) abort();
|
|
||||||
checkVarDefs2(done2, defs2, deflt);
|
|
||||||
}
|
|
||||||
set<Expr> done2;
|
|
||||||
checkVarDefs2(done2, defs2, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchFunction1(e, name, body, pos)) {
|
|
||||||
ATermMap defs2(defs);
|
|
||||||
defs2.set(name, (ATerm) ATempty);
|
|
||||||
set<Expr> done2;
|
set<Expr> done2;
|
||||||
|
checkVarDefs2(done2, defs2, pat);
|
||||||
checkVarDefs2(done2, defs2, body);
|
checkVarDefs2(done2, defs2, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,13 +358,13 @@ string showType(Expr e)
|
||||||
ATermList l1;
|
ATermList l1;
|
||||||
ATermBlob b1;
|
ATermBlob b1;
|
||||||
int i1;
|
int i1;
|
||||||
|
Pattern p1;
|
||||||
if (matchStr(e, t1, l1)) return "a string";
|
if (matchStr(e, t1, l1)) return "a string";
|
||||||
if (matchPath(e, t1)) return "a path";
|
if (matchPath(e, t1)) return "a path";
|
||||||
if (matchNull(e)) return "null";
|
if (matchNull(e)) return "null";
|
||||||
if (matchInt(e, i1)) return "an integer";
|
if (matchInt(e, i1)) return "an integer";
|
||||||
if (matchBool(e, t1)) return "a boolean";
|
if (matchBool(e, t1)) return "a boolean";
|
||||||
if (matchFunction(e, l1, t1, t2)) return "a function";
|
if (matchFunction(e, p1, t1, t2)) return "a function";
|
||||||
if (matchFunction1(e, t1, t2, t3)) return "a function";
|
|
||||||
if (matchAttrs(e, l1)) return "an attribute set";
|
if (matchAttrs(e, l1)) return "an attribute set";
|
||||||
if (matchList(e, l1)) return "a list";
|
if (matchList(e, l1)) return "a list";
|
||||||
if (matchPrimOp(e, i1, b1, l1)) return "a partially applied built-in function";
|
if (matchPrimOp(e, i1, b1, l1)) return "a partially applied built-in function";
|
||||||
|
|
|
@ -21,11 +21,9 @@ MakeError(TypeError, EvalError)
|
||||||
property of the ATerm library allows us to implement caching of
|
property of the ATerm library allows us to implement caching of
|
||||||
normals forms efficiently. */
|
normals forms efficiently. */
|
||||||
typedef ATerm Expr;
|
typedef ATerm Expr;
|
||||||
|
|
||||||
typedef ATerm DefaultValue;
|
typedef ATerm DefaultValue;
|
||||||
typedef ATerm ValidValues;
|
|
||||||
|
|
||||||
typedef ATerm Pos;
|
typedef ATerm Pos;
|
||||||
|
typedef ATerm Pattern;
|
||||||
|
|
||||||
|
|
||||||
/* A STL vector of ATerms. Should be used with great care since it's
|
/* A STL vector of ATerms. Should be used with great care since it's
|
||||||
|
|
|
@ -237,9 +237,9 @@ expr: expr_function;
|
||||||
|
|
||||||
expr_function
|
expr_function
|
||||||
: '{' formals '}' ':' expr_function
|
: '{' formals '}' ':' expr_function
|
||||||
{ $$ = makeFunction($2, $5, CUR_POS); }
|
{ $$ = makeFunction(makeAttrsPat($2), $5, CUR_POS); }
|
||||||
| ID ':' expr_function
|
| ID ':' expr_function
|
||||||
{ $$ = makeFunction1($1, $3, CUR_POS); }
|
{ $$ = makeFunction(makeVarPat($1), $3, CUR_POS); }
|
||||||
| ASSERT expr ';' expr_function
|
| ASSERT expr ';' expr_function
|
||||||
{ $$ = makeAssert($2, $4, CUR_POS); }
|
{ $$ = makeAssert($2, $4, CUR_POS); }
|
||||||
| WITH expr ';' expr_function
|
| WITH expr ';' expr_function
|
||||||
|
@ -387,22 +387,37 @@ static void checkAttrs(ATermMap & names, ATermList bnds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void checkAttrSets(ATerm e)
|
static void checkPatternVars(ATerm pos, ATermMap & map, Pattern pat)
|
||||||
{
|
{
|
||||||
|
ATerm name;
|
||||||
ATermList formals;
|
ATermList formals;
|
||||||
ATerm body, pos;
|
if (matchVarPat(pat, name)) {
|
||||||
if (matchFunction(e, formals, body, pos)) {
|
if (map.get(name))
|
||||||
ATermMap names(ATgetLength(formals));
|
throw EvalError(format("duplicate formal function argument `%1%' at %2%")
|
||||||
|
% aterm2String(name) % showPos(pos));
|
||||||
|
map.set(name, name);
|
||||||
|
}
|
||||||
|
else if (matchAttrsPat(pat, formals)) {
|
||||||
for (ATermIterator i(formals); i; ++i) {
|
for (ATermIterator i(formals); i; ++i) {
|
||||||
ATerm name;
|
|
||||||
ATerm d1;
|
ATerm d1;
|
||||||
if (!matchFormal(*i, name, d1)) abort();
|
if (!matchFormal(*i, name, d1)) abort();
|
||||||
if (names.get(name))
|
if (map.get(name))
|
||||||
throw EvalError(format("duplicate formal function argument `%1%' at %2%")
|
throw EvalError(format("duplicate formal function argument `%1%' at %2%")
|
||||||
% aterm2String(name) % showPos(pos));
|
% aterm2String(name) % showPos(pos));
|
||||||
names.set(name, name);
|
map.set(name, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void checkAttrSets(ATerm e)
|
||||||
|
{
|
||||||
|
ATerm pat, body, pos;
|
||||||
|
if (matchFunction(e, pat, body, pos)) {
|
||||||
|
ATermMap map(16);
|
||||||
|
checkPatternVars(pos, map, pat);
|
||||||
|
}
|
||||||
|
|
||||||
ATermList bnds;
|
ATermList bnds;
|
||||||
if (matchAttrs(e, bnds)) {
|
if (matchAttrs(e, bnds)) {
|
||||||
|
|
|
@ -120,11 +120,9 @@ static Expr prim_isNull(EvalState & state, const ATermVector & args)
|
||||||
static Expr prim_isFunction(EvalState & state, const ATermVector & args)
|
static Expr prim_isFunction(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
Expr e = evalExpr(state, args[0]);
|
Expr e = evalExpr(state, args[0]);
|
||||||
ATermList formals;
|
Pattern pat;
|
||||||
ATerm name, body, pos;
|
ATerm body, pos;
|
||||||
return makeBool(
|
return makeBool(matchFunction(e, pat, body, pos));
|
||||||
matchFunction(e, formals, body, pos) ||
|
|
||||||
matchFunction1(e, name, body, pos));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,16 @@
|
||||||
</attr>
|
</attr>
|
||||||
<attr name="f">
|
<attr name="f">
|
||||||
<function>
|
<function>
|
||||||
<arg name="z">
|
<attrspat>
|
||||||
</arg>
|
<attr name="z" />
|
||||||
<arg name="x">
|
<attr name="x" />
|
||||||
</arg>
|
<attr name="y" />
|
||||||
<arg name="y">
|
</attrspat>
|
||||||
</arg>
|
</function>
|
||||||
|
</attr>
|
||||||
|
<attr name="id">
|
||||||
|
<function>
|
||||||
|
<varpat name="x" />
|
||||||
</function>
|
</function>
|
||||||
</attr>
|
</attr>
|
||||||
<attr name="x">
|
<attr name="x">
|
||||||
|
|
|
@ -10,4 +10,6 @@ rec {
|
||||||
|
|
||||||
f = {z, x, y}: if y then x else z;
|
f = {z, x, y}: if y then x else z;
|
||||||
|
|
||||||
}
|
id = x: x;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Function([Formal("x",NoDefaultValue),Formal("y",NoDefaultValue),Formal("z",NoDefaultValue)],OpPlus(OpPlus(Var("x"),Var("y")),Var("z")),NoPos)
|
Function(AttrsPat([Formal("x",NoDefaultValue),Formal("y",NoDefaultValue),Formal("z",NoDefaultValue)]),OpPlus(OpPlus(Var("x"),Var("y")),Var("z")),NoPos)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Function([Formal("stdenv",NoDefaultValue),Formal("fetchurl",NoDefaultValue)],Call(Select(Var("stdenv"),"mkDerivation"),Attrs([Bind("name",Str("libXi-6.0.1",[]),NoPos),Bind("src",Call(Var("fetchurl"),Attrs([Bind("md5",Str("7e935a42428d63a387b3c048be0f2756",[]),NoPos),Bind("url",Str("http://freedesktop.org/~xlibs/release/libXi-6.0.1.tar.bz2",[]),NoPos)])),NoPos)])),NoPos)
|
Function(AttrsPat([Formal("stdenv",NoDefaultValue),Formal("fetchurl",NoDefaultValue)]),Call(Select(Var("stdenv"),"mkDerivation"),Attrs([Bind("name",Str("libXi-6.0.1",[]),NoPos),Bind("src",Call(Var("fetchurl"),Attrs([Bind("md5",Str("7e935a42428d63a387b3c048be0f2756",[]),NoPos),Bind("url",Str("http://freedesktop.org/~xlibs/release/libXi-6.0.1.tar.bz2",[]),NoPos)])),NoPos)])),NoPos)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Function([Formal("localServer",DefaultValue(Var("false"))),Formal("httpServer",DefaultValue(Var("false"))),Formal("sslSupport",DefaultValue(Var("false"))),Formal("pythonBindings",DefaultValue(Var("false"))),Formal("javaSwigBindings",DefaultValue(Var("false"))),Formal("javahlBindings",DefaultValue(Var("false"))),Formal("stdenv",NoDefaultValue),Formal("fetchurl",NoDefaultValue),Formal("openssl",DefaultValue(Var("null"))),Formal("httpd",DefaultValue(Var("null"))),Formal("db4",DefaultValue(Var("null"))),Formal("expat",NoDefaultValue),Formal("swig",DefaultValue(Var("null"))),Formal("j2sdk",DefaultValue(Var("null")))],Assert(OpNEq(Var("expat"),Var("null")),Assert(OpImpl(Var("localServer"),OpNEq(Var("db4"),Var("null"))),Assert(OpImpl(Var("httpServer"),OpAnd(OpNEq(Var("httpd"),Var("null")),OpEq(Select(Var("httpd"),"expat"),Var("expat")))),Assert(OpImpl(Var("sslSupport"),OpAnd(OpNEq(Var("openssl"),Var("null")),OpImpl(Var("httpServer"),OpEq(Select(Var("httpd"),"openssl"),Var("openssl"))))),Assert(OpImpl(Var("pythonBindings"),OpAnd(OpNEq(Var("swig"),Var("null")),Select(Var("swig"),"pythonSupport"))),Assert(OpImpl(Var("javaSwigBindings"),OpAnd(OpNEq(Var("swig"),Var("null")),Select(Var("swig"),"javaSupport"))),Assert(OpImpl(Var("javahlBindings"),OpNEq(Var("j2sdk"),Var("null"))),Call(Select(Var("stdenv"),"mkDerivation"),Attrs([Bind("builder",Path("/foo/bar"),NoPos),Bind("db4",If(Var("localServer"),Var("db4"),Var("null")),NoPos),Bind("expat",Var("expat"),NoPos),Bind("httpServer",Var("httpServer"),NoPos),Bind("httpd",If(Var("httpServer"),Var("httpd"),Var("null")),NoPos),Bind("j2sdk",If(Var("javaSwigBindings"),Select(Var("swig"),"j2sdk"),If(Var("javahlBindings"),Var("j2sdk"),Var("null"))),NoPos),Bind("javaSwigBindings",Var("javaSwigBindings"),NoPos),Bind("javahlBindings",Var("javahlBindings"),NoPos),Bind("localServer",Var("localServer"),NoPos),Bind("name",Str("subversion-1.1.1",[]),NoPos),Bind("openssl",If(Var("sslSupport"),Var("openssl"),Var("null")),NoPos),Bind("patches",If(Var("javahlBindings"),List([Path("/javahl.patch")]),List([])),NoPos),Bind("python",If(Var("pythonBindings"),Select(Var("swig"),"python"),Var("null")),NoPos),Bind("pythonBindings",Var("pythonBindings"),NoPos),Bind("src",Call(Var("fetchurl"),Attrs([Bind("md5",Str("a180c3fe91680389c210c99def54d9e0",[]),NoPos),Bind("url",Str("http://subversion.tigris.org/tarballs/subversion-1.1.1.tar.bz2",[]),NoPos)])),NoPos),Bind("sslSupport",Var("sslSupport"),NoPos),Bind("swig",If(OpOr(Var("pythonBindings"),Var("javaSwigBindings")),Var("swig"),Var("null")),NoPos)])),NoPos),NoPos),NoPos),NoPos),NoPos),NoPos),NoPos),NoPos)
|
Function(AttrsPat([Formal("localServer",DefaultValue(Var("false"))),Formal("httpServer",DefaultValue(Var("false"))),Formal("sslSupport",DefaultValue(Var("false"))),Formal("pythonBindings",DefaultValue(Var("false"))),Formal("javaSwigBindings",DefaultValue(Var("false"))),Formal("javahlBindings",DefaultValue(Var("false"))),Formal("stdenv",NoDefaultValue),Formal("fetchurl",NoDefaultValue),Formal("openssl",DefaultValue(Var("null"))),Formal("httpd",DefaultValue(Var("null"))),Formal("db4",DefaultValue(Var("null"))),Formal("expat",NoDefaultValue),Formal("swig",DefaultValue(Var("null"))),Formal("j2sdk",DefaultValue(Var("null")))]),Assert(OpNEq(Var("expat"),Var("null")),Assert(OpImpl(Var("localServer"),OpNEq(Var("db4"),Var("null"))),Assert(OpImpl(Var("httpServer"),OpAnd(OpNEq(Var("httpd"),Var("null")),OpEq(Select(Var("httpd"),"expat"),Var("expat")))),Assert(OpImpl(Var("sslSupport"),OpAnd(OpNEq(Var("openssl"),Var("null")),OpImpl(Var("httpServer"),OpEq(Select(Var("httpd"),"openssl"),Var("openssl"))))),Assert(OpImpl(Var("pythonBindings"),OpAnd(OpNEq(Var("swig"),Var("null")),Select(Var("swig"),"pythonSupport"))),Assert(OpImpl(Var("javaSwigBindings"),OpAnd(OpNEq(Var("swig"),Var("null")),Select(Var("swig"),"javaSupport"))),Assert(OpImpl(Var("javahlBindings"),OpNEq(Var("j2sdk"),Var("null"))),Call(Select(Var("stdenv"),"mkDerivation"),Attrs([Bind("builder",Path("/foo/bar"),NoPos),Bind("db4",If(Var("localServer"),Var("db4"),Var("null")),NoPos),Bind("expat",Var("expat"),NoPos),Bind("httpServer",Var("httpServer"),NoPos),Bind("httpd",If(Var("httpServer"),Var("httpd"),Var("null")),NoPos),Bind("j2sdk",If(Var("javaSwigBindings"),Select(Var("swig"),"j2sdk"),If(Var("javahlBindings"),Var("j2sdk"),Var("null"))),NoPos),Bind("javaSwigBindings",Var("javaSwigBindings"),NoPos),Bind("javahlBindings",Var("javahlBindings"),NoPos),Bind("localServer",Var("localServer"),NoPos),Bind("name",Str("subversion-1.1.1",[]),NoPos),Bind("openssl",If(Var("sslSupport"),Var("openssl"),Var("null")),NoPos),Bind("patches",If(Var("javahlBindings"),List([Path("/javahl.patch")]),List([])),NoPos),Bind("python",If(Var("pythonBindings"),Select(Var("swig"),"python"),Var("null")),NoPos),Bind("pythonBindings",Var("pythonBindings"),NoPos),Bind("src",Call(Var("fetchurl"),Attrs([Bind("md5",Str("a180c3fe91680389c210c99def54d9e0",[]),NoPos),Bind("url",Str("http://subversion.tigris.org/tarballs/subversion-1.1.1.tar.bz2",[]),NoPos)])),NoPos),Bind("sslSupport",Var("sslSupport"),NoPos),Bind("swig",If(OpOr(Var("pythonBindings"),Var("javaSwigBindings")),Var("swig"),Var("null")),NoPos)])),NoPos),NoPos),NoPos),NoPos),NoPos),NoPos),NoPos),NoPos)
|
||||||
|
|
Loading…
Reference in a new issue