aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/primops.cc697
1 files changed, 376 insertions, 321 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 01806a6c9..6b9350cf8 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -17,6 +17,11 @@
namespace nix {
+/*************************************************************
+ * Constants
+ *************************************************************/
+
+
static Expr primBuiltins(EvalState & state, const ATermVector & args)
{
/* Return an attribute set containing all primops. This allows
@@ -41,6 +46,47 @@ static Expr primBuiltins(EvalState & state, const ATermVector & args)
}
+/* Boolean constructors. */
+static Expr primTrue(EvalState & state, const ATermVector & args)
+{
+ return eTrue;
+}
+
+
+static Expr primFalse(EvalState & state, const ATermVector & args)
+{
+ return eFalse;
+}
+
+
+/* Return the null value. */
+static Expr primNull(EvalState & state, const ATermVector & args)
+{
+ return makeNull();
+}
+
+
+/* Return a string constant representing the current platform. Note!
+ that differs between platforms, so Nix expressions using
+ `__currentSystem' can evaluate to different values on different
+ platforms. */
+static Expr primCurrentSystem(EvalState & state, const ATermVector & args)
+{
+ return makeStr(thisSystem);
+}
+
+
+static Expr primCurrentTime(EvalState & state, const ATermVector & args)
+{
+ return ATmake("Int(<int>)", time(0));
+}
+
+
+/*************************************************************
+ * Miscellaneous
+ *************************************************************/
+
+
/* Load and evaluate an expression from path specified by the
argument. */
static Expr primImport(EvalState & state, const ATermVector & args)
@@ -61,16 +107,201 @@ static Expr primImport(EvalState & state, const ATermVector & args)
}
-static Expr primPathExists(EvalState & state, const ATermVector & args)
+/* Convert the argument to a string. Paths are *not* copied to the
+ store, so `toString /foo/bar' yields `"/foo/bar"', not
+ `"/nix/store/whatever..."'. */
+static Expr primToString(EvalState & state, const ATermVector & args)
{
PathSet context;
- Path path = coerceToPath(state, args[0], context);
- if (!context.empty())
- throw EvalError(format("string `%1%' cannot refer to other paths") % path);
- return makeBool(pathExists(path));
+ string s = coerceToString(state, args[0], context, true, false);
+ return makeStr(s, context);
+}
+
+
+/* Determine whether the argument is the null value. */
+static Expr primIsNull(EvalState & state, const ATermVector & args)
+{
+ return makeBool(matchNull(evalExpr(state, args[0])));
+}
+
+
+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 primDependencyClosure(EvalState & state, const ATermVector & args)
+{
+ startNest(nest, lvlDebug, "finding dependencies");
+
+ Expr attrs = evalExpr(state, args[0]);
+
+ /* Get the start set. */
+ Expr startSet = queryAttr(attrs, "startSet");
+ 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);
+ }
+ }
+
+ Expr scanner = queryAttr(attrs, "scanner");
+ if (!scanner) throw EvalError("attribute `scanner' required");
+
+ /* Construct the dependency closure by querying the dependency of
+ each path in `workSet', adding the dependencies to
+ `workSet'. */
+ PathSet doneSet;
+ while (!workSet.empty()) {
+ Path path = *(workSet.begin());
+ workSet.erase(path);
+
+ if (doneSet.find(path) != doneSet.end()) continue;
+ doneSet.insert(path);
+
+ 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);
+ }
+ }
+
+ } catch (Error & e) {
+ e.addPrefix(format("while finding dependencies in `%1%':\n")
+ % path);
+ throw;
+ }
+ }
+
+ /* 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));
+ }
+
+ debug(format("dependency list is `%1%'") % makeList(deps));
+
+ return makeList(deps);
}
+static Expr primAbort(EvalState & state, const ATermVector & args)
+{
+ PathSet context;
+ throw Abort(format("evaluation aborted with the following error message: `%1%'") %
+ evalString(state, args[0], context));
+}
+
+
+/* Return an environment variable. Use with care. */
+static Expr primGetEnv(EvalState & state, const ATermVector & args)
+{
+ string name = evalStringNoCtx(state, args[0]);
+ return makeStr(getEnv(name));
+}
+
+
+static Expr primRelativise(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
+ *************************************************************/
+
+
/* Returns the hash of a derivation modulo fixed-output
subderivations. A fixed-output derivation is a derivation with one
output (`out') for which an expected hash and hash algorithm are
@@ -324,6 +555,30 @@ static Expr primDerivationLazy(EvalState & state, const ATermVector & args)
}
+/*************************************************************
+ * Paths
+ *************************************************************/
+
+
+/* Convert the argument to a path. !!! obsolete? */
+static Expr primToPath(EvalState & state, const ATermVector & args)
+{
+ PathSet context;
+ string path = coerceToPath(state, args[0], context);
+ return makeStr(canonPath(path), context);
+}
+
+
+static Expr primPathExists(EvalState & state, const ATermVector & args)
+{
+ PathSet context;
+ Path path = coerceToPath(state, args[0], context);
+ if (!context.empty())
+ throw EvalError(format("string `%1%' cannot refer to other paths") % path);
+ return makeBool(pathExists(path));
+}
+
+
/* Return the base name of the given string, i.e., everything
following the last slash. */
static Expr primBaseNameOf(EvalState & state, const ATermVector & args)
@@ -346,24 +601,9 @@ static Expr primDirOf(EvalState & state, const ATermVector & args)
}
-/* Convert the argument to a string. Paths are *not* copied to the
- store, so `toString /foo/bar' yields `"/foo/bar"', not
- `"/nix/store/whatever..."'. */
-static Expr primToString(EvalState & state, const ATermVector & args)
-{
- PathSet context;
- string s = coerceToString(state, args[0], context, true, false);
- return makeStr(s, context);
-}
-
-
-/* Convert the argument to a path. !!! obsolete? */
-static Expr primToPath(EvalState & state, const ATermVector & args)
-{
- PathSet context;
- string path = coerceToPath(state, args[0], context);
- return makeStr(canonPath(path), context);
-}
+/*************************************************************
+ * Creating files
+ *************************************************************/
/* Convert the argument (which can be any Nix expression) to an XML
@@ -406,193 +646,120 @@ static Expr primToFile(EvalState & state, const ATermVector & args)
}
-/* Boolean constructors. */
-static Expr primTrue(EvalState & state, const ATermVector & args)
+struct FilterFromExpr : PathFilter
{
- return eTrue;
-}
+ EvalState & state;
+ Expr filter;
+
+ FilterFromExpr(EvalState & state, Expr filter)
+ : state(state), filter(filter)
+ {
+ }
+ bool operator () (const Path & path)
+ {
+ struct stat st;
+ if (lstat(path.c_str(), &st))
+ throw SysError(format("getting attributes of path `%1%'") % path);
-static Expr primFalse(EvalState & state, const ATermVector & args)
-{
- return eFalse;
-}
+ Expr call =
+ makeCall(
+ makeCall(filter, makeStr(path)),
+ makeStr(
+ S_ISREG(st.st_mode) ? "regular" :
+ S_ISDIR(st.st_mode) ? "directory" :
+ S_ISLNK(st.st_mode) ? "symlink" :
+ "unknown" /* not supported, will fail! */
+ ));
+
+ return evalBool(state, call);
+ }
+};
-/* Return the null value. */
-static Expr primNull(EvalState & state, const ATermVector & args)
+static Expr primFilterSource(EvalState & state, const ATermVector & args)
{
- return makeNull();
-}
-
+ PathSet context;
+ Path path = coerceToPath(state, args[1], context);
+ if (!context.empty())
+ throw EvalError(format("string `%1%' cannot refer to other paths") % path);
-/* Determine whether the argument is the null value. */
-static Expr primIsNull(EvalState & state, const ATermVector & args)
-{
- return makeBool(matchNull(evalExpr(state, args[0])));
-}
+ FilterFromExpr filter(state, args[0]);
+ Path dstPath = readOnlyMode
+ ? computeStorePathForPath(path, false, false, "", filter).first
+ : store->addToStore(path, false, false, "", filter);
-/* Determine whether the argument is a list. */
-static Expr primIsList(EvalState & state, const ATermVector & args)
-{
- ATermList list;
- return makeBool(matchList(evalExpr(state, args[0]), list));
+ return makeStr(dstPath, singleton<PathSet>(dstPath));
}
-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 "";
-}
+/*************************************************************
+ * Attribute sets
+ *************************************************************/
-/* 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)
+/* Return the names of the attributes in an attribute set as a sorted
+ list of strings. */
+static Expr primAttrNames(EvalState & state, const ATermVector & args)
{
- 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());
- }
+ ATermMap attrs;
+ queryAllAttrs(evalExpr(state, args[0]), attrs);
- /* 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;
- }
+ StringSet names;
+ for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i)
+ names.insert(aterm2String(i->key));
- string prefix;
- unsigned int slashes = count(pivot.begin() + i, pivot.end(), '/') + 1;
- while (slashes--) {
- prefix += "../";
- }
+ ATermList list = ATempty;
+ for (StringSet::const_reverse_iterator i = names.rbegin();
+ i != names.rend(); ++i)
+ list = ATinsert(list, makeStr(*i, PathSet()));
- return prefix + p.substr(i);
+ return makeList(list);
}
-static Expr primDependencyClosure(EvalState & state, const ATermVector & args)
+/* Dynamic version of the `.' operator. */
+static Expr primGetAttr(EvalState & state, const ATermVector & args)
{
- startNest(nest, lvlDebug, "finding dependencies");
-
- Expr attrs = evalExpr(state, args[0]);
+ string attr = evalStringNoCtx(state, args[0]);
+ return evalExpr(state, makeSelect(args[1], toATerm(attr)));
+}
- /* Get the start set. */
- Expr startSet = queryAttr(attrs, "startSet");
- 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);
- }
+/* Dynamic version of the `?' operator. */
+static Expr primHasAttr(EvalState & state, const ATermVector & args)
+{
+ string attr = evalStringNoCtx(state, args[0]);
+ return evalExpr(state, makeOpHasAttr(args[1], toATerm(attr)));
+}
- /* 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);
- }
- }
- Expr scanner = queryAttr(attrs, "scanner");
- if (!scanner) throw EvalError("attribute `scanner' required");
+static Expr primRemoveAttrs(EvalState & state, const ATermVector & args)
+{
+ ATermMap attrs;
+ queryAllAttrs(evalExpr(state, args[0]), attrs, true);
- /* Construct the dependency closure by querying the dependency of
- each path in `workSet', adding the dependencies to
- `workSet'. */
- PathSet doneSet;
- while (!workSet.empty()) {
- Path path = *(workSet.begin());
- workSet.erase(path);
-
- if (doneSet.find(path) != doneSet.end()) continue;
- doneSet.insert(path);
-
- 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);
+ ATermList list = evalList(state, args[1]);
- 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);
- }
- }
+ for (ATermIterator i(list); i; ++i)
+ /* It's not an error for *i not to exist. */
+ attrs.remove(toATerm(evalStringNoCtx(state, *i)));
- } catch (Error & e) {
- e.addPrefix(format("while finding dependencies in `%1%':\n")
- % path);
- throw;
- }
- }
+ return makeAttrs(attrs);
+}
- /* 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));
- }
- debug(format("dependency list is `%1%'") % makeList(deps));
-
- return makeList(deps);
-}
+/*************************************************************
+ * Lists
+ *************************************************************/
-static Expr primAbort(EvalState & state, const ATermVector & args)
+/* Determine whether the argument is a list. */
+static Expr primIsList(EvalState & state, const ATermVector & args)
{
- PathSet context;
- throw Abort(format("evaluation aborted with the following error message: `%1%'") %
- evalString(state, args[0], context));
+ ATermList list;
+ return makeBool(matchList(evalExpr(state, args[0]), list));
}
@@ -617,34 +784,6 @@ static Expr primTail(EvalState & state, const ATermVector & args)
}
-/* Return an environment variable. Use with care. */
-static Expr primGetEnv(EvalState & state, const ATermVector & args)
-{
- string name = evalStringNoCtx(state, args[0]);
- return makeStr(getEnv(name));
-}
-
-
-/* Return the names of the attributes in an attribute set as a sorted
- list of strings. */
-static Expr primAttrNames(EvalState & state, const ATermVector & args)
-{
- ATermMap attrs;
- queryAllAttrs(evalExpr(state, args[0]), attrs);
-
- StringSet names;
- for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i)
- names.insert(aterm2String(i->key));
-
- ATermList list = ATempty;
- for (StringSet::const_reverse_iterator i = names.rbegin();
- i != names.rend(); ++i)
- list = ATinsert(list, makeStr(*i, PathSet()));
-
- return makeList(list);
-}
-
-
/* Apply a function to every element of a list. */
static Expr primMap(EvalState & state, const ATermVector & args)
{
@@ -659,60 +798,9 @@ static Expr primMap(EvalState & state, const ATermVector & args)
}
-/* Return a string constant representing the current platform. Note!
- that differs between platforms, so Nix expressions using
- `__currentSystem' can evaluate to different values on different
- platforms. */
-static Expr primCurrentSystem(EvalState & state, const ATermVector & args)
-{
- return makeStr(thisSystem);
-}
-
-
-static Expr primCurrentTime(EvalState & state, const ATermVector & args)
-{
- return ATmake("Int(<int>)", time(0));
-}
-
-
-/* Dynamic version of the `.' operator. */
-static Expr primGetAttr(EvalState & state, const ATermVector & args)
-{
- string attr = evalStringNoCtx(state, args[0]);
- return evalExpr(state, makeSelect(args[1], toATerm(attr)));
-}
-
-
-/* Dynamic version of the `?' operator. */
-static Expr primHasAttr(EvalState & state, const ATermVector & args)
-{
- string attr = evalStringNoCtx(state, args[0]);
- return evalExpr(state, makeOpHasAttr(args[1], toATerm(attr)));
-}
-
-
-static Expr primRemoveAttrs(EvalState & state, const ATermVector & args)
-{
- ATermMap attrs;
- queryAllAttrs(evalExpr(state, args[0]), attrs, true);
-
- ATermList list = evalList(state, args[1]);
-
- for (ATermIterator i(list); i; ++i)
- /* It's not an error for *i not to exist. */
- attrs.remove(toATerm(evalStringNoCtx(state, *i)));
-
- return makeAttrs(attrs);
-}
-
-
-static Expr primRelativise(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));
-}
+/*************************************************************
+ * Integer arithmetic
+ *************************************************************/
static Expr primAdd(EvalState & state, const ATermVector & args)
@@ -739,54 +827,6 @@ static Expr primLessThan(EvalState & state, const ATermVector & args)
}
-struct FilterFromExpr : PathFilter
-{
- EvalState & state;
- Expr filter;
-
- FilterFromExpr(EvalState & state, Expr filter)
- : state(state), filter(filter)
- {
- }
-
- bool operator () (const Path & path)
- {
- struct stat st;
- if (lstat(path.c_str(), &st))
- throw SysError(format("getting attributes of path `%1%'") % path);
-
- Expr call =
- makeCall(
- makeCall(filter, makeStr(path)),
- makeStr(
- S_ISREG(st.st_mode) ? "regular" :
- S_ISDIR(st.st_mode) ? "directory" :
- S_ISLNK(st.st_mode) ? "symlink" :
- "unknown" /* not supported, will fail! */
- ));
-
- return evalBool(state, call);
- }
-};
-
-
-static Expr primFilterSource(EvalState & state, const ATermVector & args)
-{
- PathSet context;
- Path path = coerceToPath(state, args[1], context);
- if (!context.empty())
- throw EvalError(format("string `%1%' cannot refer to other paths") % path);
-
- FilterFromExpr filter(state, args[0]);
-
- Path dstPath = readOnlyMode
- ? computeStorePathForPath(path, false, false, "", filter).first
- : store->addToStore(path, false, false, "", filter);
-
- return makeStr(dstPath, singleton<PathSet>(dstPath));
-}
-
-
/*************************************************************
* String manipulation
*************************************************************/
@@ -821,41 +861,56 @@ void EvalState::addPrimOps()
{
addPrimOp("builtins", 0, primBuiltins);
+ // Constants
addPrimOp("true", 0, primTrue);
addPrimOp("false", 0, primFalse);
addPrimOp("null", 0, primNull);
addPrimOp("__currentSystem", 0, primCurrentSystem);
addPrimOp("__currentTime", 0, primCurrentTime);
+ // Miscellaneous
addPrimOp("import", 1, primImport);
- addPrimOp("__pathExists", 1, primPathExists);
- addPrimOp("derivation!", 1, primDerivationStrict);
- addPrimOp("derivation", 1, primDerivationLazy);
- addPrimOp("baseNameOf", 1, primBaseNameOf);
- addPrimOp("dirOf", 1, primDirOf);
addPrimOp("toString", 1, primToString);
- addPrimOp("__toPath", 1, primToPath);
- addPrimOp("__toXML", 1, primToXML);
addPrimOp("isNull", 1, primIsNull);
- addPrimOp("__isList", 1, primIsList);
addPrimOp("dependencyClosure", 1, primDependencyClosure);
addPrimOp("abort", 1, primAbort);
- addPrimOp("__head", 1, primHead);
- addPrimOp("__tail", 1, primTail);
addPrimOp("__getEnv", 1, primGetEnv);
- addPrimOp("__attrNames", 1, primAttrNames);
- addPrimOp("map", 2, primMap);
+ addPrimOp("relativise", 2, primRelativise);
+
+ // Derivations
+ addPrimOp("derivation!", 1, primDerivationStrict);
+ addPrimOp("derivation", 1, primDerivationLazy);
+
+ // Paths
+ addPrimOp("__toPath", 1, primToPath);
+ addPrimOp("__pathExists", 1, primPathExists);
+ addPrimOp("baseNameOf", 1, primBaseNameOf);
+ addPrimOp("dirOf", 1, primDirOf);
+
+ // Creating files
+ addPrimOp("__toXML", 1, primToXML);
+ addPrimOp("__toFile", 2, primToFile);
+ addPrimOp("__filterSource", 2, primFilterSource);
+
+ // Attribute sets
+ addPrimOp("__attrNames", 1, primAttrNames);
addPrimOp("__getAttr", 2, primGetAttr);
addPrimOp("__hasAttr", 2, primHasAttr);
addPrimOp("removeAttrs", 2, primRemoveAttrs);
- addPrimOp("relativise", 2, primRelativise);
+
+ // Lists
+ addPrimOp("__isList", 1, primIsList);
+ addPrimOp("__head", 1, primHead);
+ addPrimOp("__tail", 1, primTail);
+ addPrimOp("map", 2, primMap);
+
+ // Integer arithmetic
addPrimOp("__add", 2, primAdd);
addPrimOp("__sub", 2, primSub);
addPrimOp("__lessThan", 2, primLessThan);
- addPrimOp("__toFile", 2, primToFile);
- addPrimOp("__filterSource", 2, primFilterSource);
+ // String manipulation
addPrimOp("__substring", 3, prim_substring);
addPrimOp("__stringLength", 1, prim_stringLength);
}