* New language feature: domain checks, which check whether a function

argument has a valid value, i.e., is in a certain domain.  E.g.,

    { foo : [true false]
    , bar : ["a" "b" "c"]
    }: ...

  This previously could be done using assertions, but domain checks
  will allow the buildfarm to automatically extract the configuration
  space from functions.
This commit is contained in:
Eelco Dolstra 2006-07-24 16:35:34 +00:00
parent 88acffa20a
commit f4c5531d92
4 changed files with 40 additions and 13 deletions

View File

@ -22,7 +22,8 @@ void EvalState::addPrimOp(const string & name,
/* Substitute an argument set into the body of a function. */ /* Substitute an argument set into the body of a function. */
static Expr substArgs(Expr body, ATermList formals, Expr arg) static Expr substArgs(EvalState & state,
Expr body, ATermList formals, Expr arg)
{ {
unsigned int nrFormals = ATgetLength(formals); unsigned int nrFormals = ATgetLength(formals);
ATermMap subs(nrFormals); ATermMap subs(nrFormals);
@ -37,17 +38,35 @@ static Expr substArgs(Expr body, ATermList formals, Expr arg)
ATermVector defsUsed; ATermVector defsUsed;
ATermList recAttrs = ATempty; ATermList recAttrs = ATempty;
for (ATermIterator i(formals); i; ++i) { for (ATermIterator i(formals); i; ++i) {
Expr name, def; DefaultValue def2; ATerm dummy; Expr name, def;
if (!matchFormal(*i, name, dummy, def2)) abort(); /* can't happen */ ValidValues valids2;
if (!matchDefaultValue(def2, def)) def = 0; DefaultValue def2;
if (subs[name] == 0) { if (!matchFormal(*i, name, valids2, 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") if (def == 0) throw TypeError(format("the argument named `%1%' required by the function is missing")
% aterm2String(name)); % aterm2String(name));
value = def;
defsUsed.push_back(name); defsUsed.push_back(name);
recAttrs = ATinsert(recAttrs, makeBind(name, def, makeNoPos())); recAttrs = ATinsert(recAttrs, makeBind(name, def, makeNoPos()));
} }
/* !!! check that the argument are in the valid values list,
if present */ ATermList valids;
if (matchValidValues(valids2, valids)) {
bool found = false;
for (ATermIterator j(valids); j; ++j) {
Expr v = evalExpr(state, *j);
if (value == v) {
found = true;
break;
}
}
if (!found) throw TypeError(format("the argument named `%1%' has an illegal value")
% aterm2String(name));
}
} }
/* Make a recursive attribute set out of the (argument-name, /* Make a recursive attribute set out of the (argument-name,
@ -340,7 +359,7 @@ Expr evalExpr2(EvalState & state, Expr e)
else if (matchFunction(e1, formals, e4, pos)) { else if (matchFunction(e1, formals, e4, pos)) {
e2 = evalExpr(state, e2); e2 = evalExpr(state, e2);
try { try {
return evalExpr(state, substArgs(e4, formals, e2)); return evalExpr(state, substArgs(state, e4, formals, e2));
} catch (Error & e) { } catch (Error & e) {
e.addPrefix(format("while evaluating the function at %1%:\n") e.addPrefix(format("while evaluating the function at %1%:\n")
% showPos(pos)); % showPos(pos));

View File

@ -220,15 +220,16 @@ static void checkVarDefs2(set<Expr> & done, const ATermMap & defs, Expr e)
else if (matchFunction(e, formals, body, pos)) { else if (matchFunction(e, formals, body, pos)) {
ATermMap defs2(defs); ATermMap defs2(defs);
for (ATermIterator i(formals); i; ++i) { for (ATermIterator i(formals); i; ++i) {
Expr d1, d2; ATerm d1, d2;
if (!matchFormal(*i, name, d1, d2)) abort(); if (!matchFormal(*i, name, d1, d2)) abort();
defs2.set(name, (ATerm) ATempty); defs2.set(name, (ATerm) ATempty);
} }
for (ATermIterator i(formals); i; ++i) { for (ATermIterator i(formals); i; ++i) {
Expr dummy, deflt; ATerm valids, deflt;
set<Expr> done2; set<Expr> done2;
if (matchFormal(*i, name, dummy, deflt)) /* !!! check dummy */ matchFormal(*i, name, valids, deflt);
checkVarDefs2(done2, defs2, deflt); checkVarDefs2(done, defs, valids);
checkVarDefs2(done2, defs2, deflt);
} }
set<Expr> done2; set<Expr> done2;
checkVarDefs2(done2, defs2, body); checkVarDefs2(done2, defs2, body);

View File

@ -206,7 +206,7 @@ formals
formal formal
: ID { $$ = makeFormal($1, makeUnrestrictedValues(), makeNoDefaultValue()); } : ID { $$ = makeFormal($1, makeUnrestrictedValues(), makeNoDefaultValue()); }
// | ID ':' '[' expr_list ']' { $$ = makeDefFormal($1, $3); } | ID ':' '[' expr_list ']' { $$ = makeFormal($1, makeValidValues($4), makeNoDefaultValue()); }
| ID '?' expr { $$ = makeFormal($1, makeUnrestrictedValues(), makeDefaultValue($3)); } | ID '?' expr { $$ = makeFormal($1, makeUnrestrictedValues(), makeDefaultValue($3)); }
; ;

View File

@ -0,0 +1,7 @@
let {
f = {x, y : ["baz" "bar" z "bat"]}: x + y;
body = f {x = "foo"; y = "bar";};
}