aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2008-07-11 13:29:04 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2008-07-11 13:29:04 +0000
commit7cd88b1dec29f33188e789d780ec2e4ebb155d20 (patch)
treec2a3934a763e6968af7fce554a5840516fa6208e /src/libexpr
parentd567baabbd99fdb92e67295a77aef76ef970e65c (diff)
* Generalised the dependencyClosure primop to builtins.genericClosure,
which is hopefully more useful. * New primops: length, mul, div.
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/primops.cc192
1 files changed, 55 insertions, 137 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index fbef22722..c747f46c4 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -128,59 +128,7 @@ static Expr prim_isFunction(EvalState & state, const ATermVector & args)
}
-static Path findDependency(Path dir, string dep)
-{
- if (dep[0] == '/') throw EvalError(
- format("illegal absolute dependency `%1%'") % dep);
-
- Path p = canonPath(dir + "/" + dep);
-
- if (pathExists(p))
- return p;
- else
- return "";
-}
-
-
-/* Make path `p' relative to directory `pivot'. E.g.,
- relativise("/a/b/c", "a/b/x/y") => "../x/y". Both input paths
- should be in absolute canonical form. */
-static string relativise(Path pivot, Path p)
-{
- assert(pivot.size() > 0 && pivot[0] == '/');
- assert(p.size() > 0 && p[0] == '/');
-
- if (pivot == p) return ".";
-
- /* `p' is in `pivot'? */
- Path pivot2 = pivot + "/";
- if (p.substr(0, pivot2.size()) == pivot2) {
- return p.substr(pivot2.size());
- }
-
- /* Otherwise, `p' is in a parent of `pivot'. Find up till which
- path component `p' and `pivot' match, and add an appropriate
- number of `..' components. */
- string::size_type i = 1;
- while (1) {
- string::size_type j = pivot.find('/', i);
- if (j == string::npos) break;
- j++;
- if (pivot.substr(0, j) != p.substr(0, j)) break;
- i = j;
- }
-
- string prefix;
- unsigned int slashes = count(pivot.begin() + i, pivot.end(), '/') + 1;
- while (slashes--) {
- prefix += "../";
- }
-
- return prefix + p.substr(i);
-}
-
-
-static Expr prim_dependencyClosure(EvalState & state, const ATermVector & args)
+static Expr prim_genericClosure(EvalState & state, const ATermVector & args)
{
startNest(nest, lvlDebug, "finding dependencies");
@@ -191,87 +139,40 @@ static Expr prim_dependencyClosure(EvalState & state, const ATermVector & args)
if (!startSet) throw EvalError("attribute `startSet' required");
ATermList startSet2 = evalList(state, startSet);
- Path pivot;
- PathSet workSet;
- for (ATermIterator i(startSet2); i; ++i) {
- PathSet context; /* !!! what to do? */
- Path p = coerceToPath(state, *i, context);
- workSet.insert(p);
- pivot = dirOf(p);
- }
-
- /* Get the search path. */
- PathSet searchPath;
- Expr e = queryAttr(attrs, "searchPath");
- if (e) {
- ATermList list = evalList(state, e);
- for (ATermIterator i(list); i; ++i) {
- PathSet context; /* !!! what to do? */
- Path p = coerceToPath(state, *i, context);
- searchPath.insert(p);
- }
- }
+ set<Expr> workSet; // !!! gc roots
+ for (ATermIterator i(startSet2); i; ++i) workSet.insert(*i);
- Expr scanner = queryAttr(attrs, "scanner");
- if (!scanner) throw EvalError("attribute `scanner' required");
+ /* Get the operator. */
+ Expr op = queryAttr(attrs, "operator");
+ if (!op) throw EvalError("attribute `operator' required");
- /* Construct the dependency closure by querying the dependency of
- each path in `workSet', adding the dependencies to
- `workSet'. */
- PathSet doneSet;
+ /* Construct the closure by applying the operator to element of
+ `workSet', adding the result to `workSet', continuing until
+ no new elements are found. */
+ ATermList res = ATempty;
+ set<Expr> doneKeys; // !!! gc roots
while (!workSet.empty()) {
- Path path = *(workSet.begin());
- workSet.erase(path);
+ Expr e = *(workSet.begin());
+ workSet.erase(e);
- if (doneSet.find(path) != doneSet.end()) continue;
- doneSet.insert(path);
+ e = strictEvalExpr(state, e);
- try {
-
- /* Call the `scanner' function with `path' as argument. */
- debug(format("finding dependencies in `%1%'") % path);
- ATermList deps = evalList(state, makeCall(scanner, makeStr(path)));
-
- /* Try to find the dependencies relative to the `path'. */
- for (ATermIterator i(deps); i; ++i) {
- string s = evalStringNoCtx(state, *i);
-
- Path dep = findDependency(dirOf(path), s);
-
- if (dep == "") {
- for (PathSet::iterator j = searchPath.begin();
- j != searchPath.end(); ++j)
- {
- dep = findDependency(*j, s);
- if (dep != "") break;
- }
- }
-
- if (dep == "")
- debug(format("did NOT find dependency `%1%'") % s);
- else {
- debug(format("found dependency `%1%'") % dep);
- workSet.insert(dep);
- }
- }
+ Expr key = queryAttr(e, "key");
+ if (!key) throw EvalError("attribute `key' required");
- } catch (Error & e) {
- e.addPrefix(format("while finding dependencies in `%1%':\n")
- % path);
- throw;
- }
- }
+ if (doneKeys.find(key) != doneKeys.end()) continue;
+ doneKeys.insert(key);
+ res = ATinsert(res, e);
+
+ /* Call the `operator' function with `e' as argument. */
+ ATermList res = evalList(state, makeCall(op, e));
- /* Return a list of the dependencies we've just found. */
- ATermList deps = ATempty;
- for (PathSet::iterator i = doneSet.begin(); i != doneSet.end(); ++i) {
- deps = ATinsert(deps, makeStr(relativise(pivot, *i)));
- deps = ATinsert(deps, makeStr(*i));
+ /* Try to find the dependencies relative to the `path'. */
+ for (ATermIterator i(res); i; ++i)
+ workSet.insert(evalExpr(state, *i));
}
- debug(format("dependency list is `%1%'") % makeList(deps));
-
- return makeList(deps);
+ return makeList(res);
}
@@ -311,15 +212,6 @@ static Expr prim_trace(EvalState & state, const ATermVector & args)
}
-static Expr prim_relativise(EvalState & state, const ATermVector & args)
-{
- PathSet context; /* !!! what to do? */
- Path pivot = coerceToPath(state, args[0], context);
- Path path = coerceToPath(state, args[1], context);
- return makeStr(relativise(pivot, path));
-}
-
-
/*************************************************************
* Derivations
*************************************************************/
@@ -874,6 +766,14 @@ static Expr prim_map(EvalState & state, const ATermVector & args)
}
+/* Return the length of a list. This is an O(1) time operation. */
+static Expr prim_length(EvalState & state, const ATermVector & args)
+{
+ ATermList list = evalList(state, args[0]);
+ return makeInt(ATgetLength(list));
+}
+
+
/*************************************************************
* Integer arithmetic
*************************************************************/
@@ -895,6 +795,23 @@ static Expr prim_sub(EvalState & state, const ATermVector & args)
}
+static Expr prim_mul(EvalState & state, const ATermVector & args)
+{
+ int i1 = evalInt(state, args[0]);
+ int i2 = evalInt(state, args[1]);
+ return makeInt(i1 * i2);
+}
+
+
+static Expr prim_div(EvalState & state, const ATermVector & args)
+{
+ int i1 = evalInt(state, args[0]);
+ int i2 = evalInt(state, args[1]);
+ if (i2 == 0) throw EvalError("division by zero");
+ return makeInt(i1 / i2);
+}
+
+
static Expr prim_lessThan(EvalState & state, const ATermVector & args)
{
int i1 = evalInt(state, args[0]);
@@ -1019,7 +936,7 @@ void EvalState::addPrimOps()
addPrimOp("import", 1, prim_import);
addPrimOp("isNull", 1, prim_isNull);
addPrimOp("__isFunction", 1, prim_isFunction);
- addPrimOp("dependencyClosure", 1, prim_dependencyClosure);
+ addPrimOp("__genericClosure", 1, prim_genericClosure);
addPrimOp("abort", 1, prim_abort);
addPrimOp("throw", 1, prim_throw);
addPrimOp("__getEnv", 1, prim_getEnv);
@@ -1029,8 +946,6 @@ void EvalState::addPrimOps()
addPrimOp("__exprToString", 1, prim_exprToString);
addPrimOp("__stringToExpr", 1, prim_stringToExpr);
- addPrimOp("relativise", 2, prim_relativise);
-
// Derivations
addPrimOp("derivation!", 1, prim_derivationStrict);
addPrimOp("derivation", 1, prim_derivationLazy);
@@ -1060,10 +975,13 @@ void EvalState::addPrimOps()
addPrimOp("__head", 1, prim_head);
addPrimOp("__tail", 1, prim_tail);
addPrimOp("map", 2, prim_map);
+ addPrimOp("__length", 1, prim_length);
// Integer arithmetic
addPrimOp("__add", 2, prim_add);
addPrimOp("__sub", 2, prim_sub);
+ addPrimOp("__mul", 2, prim_mul);
+ addPrimOp("__div", 2, prim_div);
addPrimOp("__lessThan", 2, prim_lessThan);
// String manipulation