From ac68840e79ce74f05ee8b31bb1d528c98b9c7f76 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 19 Nov 2003 11:35:41 +0000 Subject: * Refactoring: put the Nix expression evaluator in its own library so that it can be used by multiple programs. --- configure.ac | 2 +- src/Makefile.am | 3 +- src/libexpr/Makefile.am | 22 ++++ src/libexpr/eval.cc | 265 ++++++++++++++++++++++++++++++++++++++++ src/libexpr/eval.hh | 42 +++++++ src/libexpr/fix-expr.cc | 215 ++++++++++++++++++++++++++++++++ src/libexpr/fix-expr.hh | 75 ++++++++++++ src/libexpr/main.cc | 117 ++++++++++++++++++ src/libexpr/nix.sdf | 209 +++++++++++++++++++++++++++++++ src/libexpr/nixexpr.cc | 215 ++++++++++++++++++++++++++++++++ src/libexpr/nixexpr.hh | 75 ++++++++++++ src/libexpr/parser.cc | 164 +++++++++++++++++++++++++ src/libexpr/parser.hh | 10 ++ src/libexpr/primops.cc | 246 +++++++++++++++++++++++++++++++++++++ src/libexpr/primops.hh | 34 ++++++ src/nix-instantiate/Makefile.am | 22 ---- src/nix-instantiate/eval.cc | 265 ---------------------------------------- src/nix-instantiate/eval.hh | 42 ------- src/nix-instantiate/fix-expr.cc | 215 -------------------------------- src/nix-instantiate/fix-expr.hh | 75 ------------ src/nix-instantiate/main.cc | 117 ------------------ src/nix-instantiate/nix.sdf | 209 ------------------------------- src/nix-instantiate/nixexpr.cc | 215 -------------------------------- src/nix-instantiate/nixexpr.hh | 75 ------------ src/nix-instantiate/parser.cc | 164 ------------------------- src/nix-instantiate/parser.hh | 10 -- src/nix-instantiate/primops.cc | 246 ------------------------------------- src/nix-instantiate/primops.hh | 34 ------ 28 files changed, 1692 insertions(+), 1691 deletions(-) create mode 100644 src/libexpr/Makefile.am create mode 100644 src/libexpr/eval.cc create mode 100644 src/libexpr/eval.hh create mode 100644 src/libexpr/fix-expr.cc create mode 100644 src/libexpr/fix-expr.hh create mode 100644 src/libexpr/main.cc create mode 100644 src/libexpr/nix.sdf create mode 100644 src/libexpr/nixexpr.cc create mode 100644 src/libexpr/nixexpr.hh create mode 100644 src/libexpr/parser.cc create mode 100644 src/libexpr/parser.hh create mode 100644 src/libexpr/primops.cc create mode 100644 src/libexpr/primops.hh delete mode 100644 src/nix-instantiate/Makefile.am delete mode 100644 src/nix-instantiate/eval.cc delete mode 100644 src/nix-instantiate/eval.hh delete mode 100644 src/nix-instantiate/fix-expr.cc delete mode 100644 src/nix-instantiate/fix-expr.hh delete mode 100644 src/nix-instantiate/main.cc delete mode 100644 src/nix-instantiate/nix.sdf delete mode 100644 src/nix-instantiate/nixexpr.cc delete mode 100644 src/nix-instantiate/nixexpr.hh delete mode 100644 src/nix-instantiate/parser.cc delete mode 100644 src/nix-instantiate/parser.hh delete mode 100644 src/nix-instantiate/primops.cc delete mode 100644 src/nix-instantiate/primops.hh diff --git a/configure.ac b/configure.ac index 1fa6e1d33f1e..09e292e1b16f 100644 --- a/configure.ac +++ b/configure.ac @@ -34,7 +34,7 @@ AC_CONFIG_FILES([Makefile src/libmain/Makefile src/nix-store/Makefile src/nix-hash/Makefile - src/nix-instantiate/Makefile + src/libexpr/Makefile scripts/Makefile corepkgs/Makefile corepkgs/fetchurl/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 1f2aafcdba6d..f06bb1f1d818 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1 +1,2 @@ -SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash nix-instantiate +SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \ + libexpr #nix-instantiate diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am new file mode 100644 index 000000000000..6fe79850116e --- /dev/null +++ b/src/libexpr/Makefile.am @@ -0,0 +1,22 @@ +bin_PROGRAMS = nix-instantiate + +nix_instantiate_SOURCES = nixexpr.cc parser.cc eval.cc primops.cc main.cc +nix_instantiate_LDADD = ../libmain/libmain.a ../libstore/libstore.a ../libutil/libutil.a \ + ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx \ + -lsglr -lATB -lconversion -lasfix2 -lmept -lATerm + +AM_CXXFLAGS = \ + -I.. -I../../externals/inst/include -I../libutil -I../libstore -I../libmain + + +# Parse table generation. + +parser.o: parse-table.h + +parse-table.h: nix.tbl + ../bin2c/bin2c nixParseTable < $< > $@ || (rm $@ && exit 1) + +%.tbl: %.sdf + ../../externals/inst/bin/sdf2table -s -i $< -o $@ + +CLEANFILES = parse-table.h nix.tbl diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc new file mode 100644 index 000000000000..b110c3a4a41c --- /dev/null +++ b/src/libexpr/eval.cc @@ -0,0 +1,265 @@ +#include "eval.hh" +#include "parser.hh" +#include "primops.hh" + + +EvalState::EvalState() + : normalForms(32768, 75) +{ + blackHole = ATmake("BlackHole()"); + if (!blackHole) throw Error("cannot build black hole"); + nrEvaluated = nrCached = 0; +} + + +/* Substitute an argument set into the body of a function. */ +static Expr substArgs(Expr body, ATermList formals, Expr arg) +{ + ATMatcher m; + ATermMap subs; + Expr undefined = ATmake("Undefined"); + + /* Get the formal arguments. */ + for (ATermIterator i(formals); i; ++i) { + Expr name, def; + if (atMatch(m, *i) >> "NoDefFormal" >> name) + subs.set(name, undefined); + else if (atMatch(m, *i) >> "DefFormal" >> name >> def) + subs.set(name, def); + else abort(); /* can't happen */ + } + + /* Get the actual arguments, and check that they match with the + formals. */ + ATermMap args; + queryAllAttrs(arg, args); + for (ATermIterator i(args.keys()); i; ++i) { + Expr key = *i; + Expr cur = subs.get(key); + if (!cur) + throw badTerm(format("function has no formal argument `%1%'") + % aterm2String(key), arg); + subs.set(key, args.get(key)); + } + + /* Check that all arguments are defined. */ + for (ATermIterator i(subs.keys()); i; ++i) + if (subs.get(*i) == undefined) + throw badTerm(format("formal argument `%1%' missing") + % aterm2String(*i), arg); + + return substitute(subs, body); +} + + +/* Transform a mutually recursive set into a non-recursive set. Each + attribute is transformed into an expression that has all references + to attributes substituted with selection expressions on the + original set. E.g., e = `rec {x = f x y, y = x}' becomes `{x = f + (e.x) (e.y), y = e.x}'. */ +ATerm expandRec(ATerm e, ATermList bnds) +{ + ATMatcher m; + + /* Create the substitution list. */ + ATermMap subs; + for (ATermIterator i(bnds); i; ++i) { + string s; + Expr e2; + if (!(atMatch(m, *i) >> "Bind" >> s >> e2)) + abort(); /* can't happen */ + subs.set(s, ATmake("Select(, )", e, s.c_str())); + } + + /* Create the non-recursive set. */ + ATermMap as; + for (ATermIterator i(bnds); i; ++i) { + string s; + Expr e2; + if (!(atMatch(m, *i) >> "Bind" >> s >> e2)) + abort(); /* can't happen */ + as.set(s, substitute(subs, e2)); + } + + return makeAttrs(as); +} + + +string evalString(EvalState & state, Expr e) +{ + e = evalExpr(state, e); + ATMatcher m; + string s; + if (!(atMatch(m, e) >> "Str" >> s)) + throw badTerm("string expected", e); + return s; +} + + +Path evalPath(EvalState & state, Expr e) +{ + e = evalExpr(state, e); + ATMatcher m; + string s; + if (!(atMatch(m, e) >> "Path" >> s)) + throw badTerm("path expected", e); + return s; +} + + +bool evalBool(EvalState & state, Expr e) +{ + e = evalExpr(state, e); + ATMatcher m; + if (atMatch(m, e) >> "Bool" >> "True") return true; + else if (atMatch(m, e) >> "Bool" >> "False") return false; + else throw badTerm("expecting a boolean", e); +} + + +Expr evalExpr2(EvalState & state, Expr e) +{ + ATMatcher m; + Expr e1, e2, e3, e4; + string s1; + + /* Normal forms. */ + if (atMatch(m, e) >> "Str" || + atMatch(m, e) >> "Path" || + atMatch(m, e) >> "Uri" || + atMatch(m, e) >> "Bool" || + atMatch(m, e) >> "Function" || + atMatch(m, e) >> "Attrs" || + atMatch(m, e) >> "List") + return e; + + /* Any encountered variables must be undeclared or primops. */ + if (atMatch(m, e) >> "Var" >> s1) { + if (s1 == "null") return primNull(state); + return e; + } + + /* Function application. */ + if (atMatch(m, e) >> "Call" >> e1 >> e2) { + + ATermList formals; + + /* Evaluate the left-hand side. */ + e1 = evalExpr(state, e1); + + /* Is it a primop or a function? */ + if (atMatch(m, e1) >> "Var" >> s1) { + if (s1 == "import") return primImport(state, e2); + if (s1 == "derivation") return primDerivation(state, e2); + if (s1 == "toString") return primToString(state, e2); + if (s1 == "baseNameOf") return primBaseNameOf(state, e2); + if (s1 == "isNull") return primIsNull(state, e2); + else throw badTerm("undefined variable/primop", e1); + } + + else if (atMatch(m, e1) >> "Function" >> formals >> e4) + return evalExpr(state, + substArgs(e4, formals, evalExpr(state, e2))); + + else throw badTerm("expecting a function or primop", e1); + } + + /* Attribute selection. */ + if (atMatch(m, e) >> "Select" >> e1 >> s1) { + Expr a = queryAttr(evalExpr(state, e1), s1); + if (!a) throw badTerm(format("missing attribute `%1%'") % s1, e); + return evalExpr(state, a); + } + + /* Mutually recursive sets. */ + ATermList bnds; + if (atMatch(m, e) >> "Rec" >> bnds) + return expandRec(e, bnds); + + /* Let expressions `let {..., body = ...}' are just desugared + into `(rec {..., body = ...}).body'. */ + if (atMatch(m, e) >> "LetRec" >> bnds) + return evalExpr(state, ATmake("Select(Rec(), \"body\")", bnds)); + + /* Conditionals. */ + if (atMatch(m, e) >> "If" >> e1 >> e2 >> e3) { + if (evalBool(state, e1)) + return evalExpr(state, e2); + else + return evalExpr(state, e3); + } + + /* Assertions. */ + if (atMatch(m, e) >> "Assert" >> e1 >> e2) { + if (!evalBool(state, e1)) throw badTerm("guard failed", e); + return evalExpr(state, e2); + } + + /* Generic equality. */ + if (atMatch(m, e) >> "OpEq" >> e1 >> e2) + return makeBool(evalExpr(state, e1) == evalExpr(state, e2)); + + /* Generic inequality. */ + if (atMatch(m, e) >> "OpNEq" >> e1 >> e2) + return makeBool(evalExpr(state, e1) != evalExpr(state, e2)); + + /* Negation. */ + if (atMatch(m, e) >> "OpNot" >> e1) + return makeBool(!evalBool(state, e1)); + + /* Implication. */ + if (atMatch(m, e) >> "OpImpl" >> e1 >> e2) + return makeBool(!evalBool(state, e1) || evalBool(state, e2)); + + /* Conjunction (logical AND). */ + if (atMatch(m, e) >> "OpAnd" >> e1 >> e2) + return makeBool(evalBool(state, e1) && evalBool(state, e2)); + + /* Disjunction (logical OR). */ + if (atMatch(m, e) >> "OpOr" >> e1 >> e2) + return makeBool(evalBool(state, e1) || evalBool(state, e2)); + + /* Barf. */ + throw badTerm("invalid expression", e); +} + + +Expr evalExpr(EvalState & state, Expr e) +{ + startNest(nest, lvlVomit, + format("evaluating expression: %1%") % e); + + state.nrEvaluated++; + + /* Consult the memo table to quickly get the normal form of + previously evaluated expressions. */ + Expr nf = state.normalForms.get(e); + if (nf) { + if (nf == state.blackHole) + throw badTerm("infinite recursion", e); + state.nrCached++; + return nf; + } + + /* Otherwise, evaluate and memoize. */ + state.normalForms.set(e, state.blackHole); + nf = evalExpr2(state, e); + state.normalForms.set(e, nf); + return nf; +} + + +Expr evalFile(EvalState & state, const Path & path) +{ + startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); + Expr e = parseExprFromFile(path); + return evalExpr(state, e); +} + + +void printEvalStats(EvalState & state) +{ + debug(format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency") + % state.nrEvaluated % state.nrCached + % ((float) state.nrCached / (float) state.nrEvaluated * 100)); +} diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh new file mode 100644 index 000000000000..0bc052676deb --- /dev/null +++ b/src/libexpr/eval.hh @@ -0,0 +1,42 @@ +#ifndef __EVAL_H +#define __EVAL_H + +#include + +#include "aterm.hh" +#include "hash.hh" +#include "nixexpr.hh" + + +typedef map DrvPaths; +typedef map DrvHashes; + +struct EvalState +{ + ATermMap normalForms; + DrvPaths drvPaths; + DrvHashes drvHashes; /* normalised derivation hashes */ + Expr blackHole; + + unsigned int nrEvaluated; + unsigned int nrCached; + + EvalState(); +}; + + +/* Evaluate an expression to normal form. */ +Expr evalExpr(EvalState & state, Expr e); + +/* Evaluate an expression read from the given file to normal form. */ +Expr evalFile(EvalState & state, const Path & path); + +/* Specific results. */ +string evalString(EvalState & state, Expr e); +Path evalPath(EvalState & state, Expr e); + +/* Print statistics. */ +void printEvalStats(EvalState & state); + + +#endif /* !__EVAL_H */ diff --git a/src/libexpr/fix-expr.cc b/src/libexpr/fix-expr.cc new file mode 100644 index 000000000000..e9c5a3ba633f --- /dev/null +++ b/src/libexpr/fix-expr.cc @@ -0,0 +1,215 @@ +#include "fix-expr.hh" +#include "expr.hh" + + +ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct) +{ + table = ATtableCreate(initialSize, maxLoadPct); + if (!table) throw Error("cannot create ATerm table"); +} + + +ATermMap::ATermMap(const ATermMap & map) + : table(0) +{ + ATermList keys = map.keys(); + + /* !!! adjust allocation for load pct */ + table = ATtableCreate(ATgetLength(keys), map.maxLoadPct); + if (!table) throw Error("cannot create ATerm table"); + + for (ATermIterator i(keys); i; ++i) + set(*i, map.get(*i)); +} + + +ATermMap::~ATermMap() +{ + if (table) ATtableDestroy(table); +} + + +void ATermMap::set(ATerm key, ATerm value) +{ + return ATtablePut(table, key, value); +} + + +void ATermMap::set(const string & key, ATerm value) +{ + set(string2ATerm(key), value); +} + + +ATerm ATermMap::get(ATerm key) const +{ + return ATtableGet(table, key); +} + + +ATerm ATermMap::get(const string & key) const +{ + return get(string2ATerm(key)); +} + + +void ATermMap::remove(ATerm key) +{ + ATtableRemove(table, key); +} + + +void ATermMap::remove(const string & key) +{ + remove(string2ATerm(key)); +} + + +ATermList ATermMap::keys() const +{ + ATermList keys = ATtableKeys(table); + if (!keys) throw Error("cannot query aterm map keys"); + return keys; +} + + +ATerm string2ATerm(const string & s) +{ + return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue)); +} + + +string aterm2String(ATerm t) +{ + return ATgetName(ATgetAFun(t)); +} + + +ATerm bottomupRewrite(TermFun & f, ATerm e) +{ + if (ATgetType(e) == AT_APPL) { + AFun fun = ATgetAFun(e); + int arity = ATgetArity(fun); + ATermList args = ATempty; + + for (int i = arity - 1; i >= 0; i--) + args = ATinsert(args, bottomupRewrite(f, ATgetArgument(e, i))); + + e = (ATerm) ATmakeApplList(fun, args); + } + + else if (ATgetType(e) == AT_LIST) { + ATermList in = (ATermList) e; + ATermList out = ATempty; + + for (ATermIterator i(in); i; ++i) + out = ATinsert(out, bottomupRewrite(f, *i)); + + e = (ATerm) ATreverse(out); + } + + return f(e); +} + + +void queryAllAttrs(Expr e, ATermMap & attrs) +{ + ATMatcher m; + ATermList bnds; + if (!(atMatch(m, e) >> "Attrs" >> bnds)) + throw badTerm("expected attribute set", e); + + for (ATermIterator i(bnds); i; ++i) { + string s; + Expr e; + if (!(atMatch(m, *i) >> "Bind" >> s >> e)) + abort(); /* can't happen */ + attrs.set(s, e); + } +} + + +Expr queryAttr(Expr e, const string & name) +{ + ATermMap attrs; + queryAllAttrs(e, attrs); + return attrs.get(name); +} + + +Expr makeAttrs(const ATermMap & attrs) +{ + ATermList bnds = ATempty; + for (ATermIterator i(attrs.keys()); i; ++i) + bnds = ATinsert(bnds, + ATmake("Bind(, )", *i, attrs.get(*i))); + return ATmake("Attrs()", ATreverse(bnds)); +} + + +Expr substitute(const ATermMap & subs, Expr e) +{ + ATMatcher m; + string s; + + if (atMatch(m, e) >> "Var" >> s) { + Expr sub = subs.get(s); + return sub ? sub : e; + } + + /* In case of a function, filter out all variables bound by this + function. */ + ATermList formals; + ATerm body; + if (atMatch(m, e) >> "Function" >> formals >> body) { + ATermMap subs2(subs); + for (ATermIterator i(formals); i; ++i) { + Expr def; + if (!(atMatch(m, *i) >> "NoDefFormal" >> s) && + !(atMatch(m, *i) >> "DefFormal" >> s >> def)) + abort(); + subs2.remove(s); + } + return ATmake("Function(, )", formals, + substitute(subs2, body)); + } + + /* Idem for a mutually recursive attribute set. */ + ATermList bindings; + if (atMatch(m, e) >> "Rec" >> bindings) { + ATermMap subs2(subs); + for (ATermIterator i(bindings); i; ++i) { + Expr e; + if (!(atMatch(m, *i) >> "Bind" >> s >> e)) + abort(); /* can't happen */ + subs2.remove(s); + } + return ATmake("Rec()", substitute(subs2, (ATerm) bindings)); + } + + if (ATgetType(e) == AT_APPL) { + AFun fun = ATgetAFun(e); + int arity = ATgetArity(fun); + ATermList args = ATempty; + + for (int i = arity - 1; i >= 0; i--) + args = ATinsert(args, substitute(subs, ATgetArgument(e, i))); + + return (ATerm) ATmakeApplList(fun, args); + } + + if (ATgetType(e) == AT_LIST) { + ATermList out = ATempty; + for (ATermIterator i((ATermList) e); i; ++i) + out = ATinsert(out, substitute(subs, *i)); + return (ATerm) ATreverse(out); + } + + return e; +} + + +Expr makeBool(bool b) +{ + return b ? ATmake("Bool(True)") : ATmake("Bool(False)"); +} diff --git a/src/libexpr/fix-expr.hh b/src/libexpr/fix-expr.hh new file mode 100644 index 000000000000..6c1e51d9ccd6 --- /dev/null +++ b/src/libexpr/fix-expr.hh @@ -0,0 +1,75 @@ +#ifndef __FIXEXPR_H +#define __FIXEXPR_H + +#include + +#include + +#include "util.hh" + + +/* Fix expressions are represented as ATerms. The maximal sharing + property of the ATerm library allows us to implement caching of + normals forms efficiently. */ +typedef ATerm Expr; + + +/* Mappings from ATerms to ATerms. This is just a wrapper around + ATerm tables. */ +class ATermMap +{ +private: + unsigned int maxLoadPct; + ATermTable table; + +public: + ATermMap(unsigned int initialSize = 16, unsigned int maxLoadPct = 75); + ATermMap(const ATermMap & map); + ~ATermMap(); + + void set(ATerm key, ATerm value); + void set(const string & key, ATerm value); + + ATerm get(ATerm key) const; + ATerm get(const string & key) const; + + void remove(ATerm key); + void remove(const string & key); + + ATermList keys() const; +}; + + +/* Convert a string to an ATerm (i.e., a quoted nullary function + applicaton). */ +ATerm string2ATerm(const string & s); +string aterm2String(ATerm t); + +/* Generic bottomup traversal over ATerms. The traversal first + recursively descends into subterms, and then applies the given term + function to the resulting term. */ +struct TermFun +{ + virtual ATerm operator () (ATerm e) = 0; +}; +ATerm bottomupRewrite(TermFun & f, ATerm e); + +/* Query all attributes in an attribute set expression. The + expression must be in normal form. */ +void queryAllAttrs(Expr e, ATermMap & attrs); + +/* Query a specific attribute from an attribute set expression. The + expression must be in normal form. */ +Expr queryAttr(Expr e, const string & name); + +/* Create an attribute set expression from an Attrs value. */ +Expr makeAttrs(const ATermMap & attrs); + +/* Perform a set of substitutions on an expression. */ +Expr substitute(const ATermMap & subs, Expr e); + +/* Create an expression representing a boolean. */ +Expr makeBool(bool b); + + +#endif /* !__FIXEXPR_H */ diff --git a/src/libexpr/main.cc b/src/libexpr/main.cc new file mode 100644 index 000000000000..aa6883ff84b8 --- /dev/null +++ b/src/libexpr/main.cc @@ -0,0 +1,117 @@ +#include +#include + +#include "globals.hh" +#include "normalise.hh" +#include "shared.hh" +#include "eval.hh" + + +#if 0 +static Path searchPath(const Paths & searchDirs, const Path & relPath) +{ + if (string(relPath, 0, 1) == "/") return relPath; + + for (Paths::const_iterator i = searchDirs.begin(); + i != searchDirs.end(); i++) + { + Path path = *i + "/" + relPath; + if (pathExists(path)) return path; + } + + throw Error( + format("path `%1%' not found in any of the search directories") + % relPath); +} +#endif + + +static Expr evalStdin(EvalState & state) +{ + startNest(nest, lvlTalkative, format("evaluating standard input")); + Expr e = ATreadFromFile(stdin); + if (!e) + throw Error(format("unable to read a term from stdin")); + return evalExpr(state, e); +} + + +static void printNixExpr(EvalState & state, Expr e) +{ + ATMatcher m; + ATermList es; + + if (atMatch(m, e) >> "Attrs" >> es) { + Expr a = queryAttr(e, "type"); + if (a && evalString(state, a) == "derivation") { + a = queryAttr(e, "drvPath"); + if (a) { + cout << format("%1%\n") % evalPath(state, a); + return; + } + } + } + + if (ATgetType(e) == AT_LIST) { + for (ATermIterator i((ATermList) e); i; ++i) + printNixExpr(state, evalExpr(state, *i)); + return; + } + + throw badTerm("top level does not evaluate to one or more Nix expressions", e); +} + + +void run(Strings args) +{ + EvalState state; + Strings files; + bool readStdin = false; + +#if 0 + state.searchDirs.push_back("."); + state.searchDirs.push_back(nixDataDir + "/nix"); +#endif + + for (Strings::iterator it = args.begin(); + it != args.end(); ) + { + string arg = *it++; + +#if 0 + if (arg == "--includedir" || arg == "-I") { + if (it == args.end()) + throw UsageError(format("argument required in `%1%'") % arg); + state.searchDirs.push_back(*it++); + } + else +#endif + if (arg == "--verbose" || arg == "-v") + verbosity = (Verbosity) ((int) verbosity + 1); + else if (arg == "-") + readStdin = true; + else if (arg[0] == '-') + throw UsageError(format("unknown flag `%1%`") % arg); + else + files.push_back(arg); + } + + openDB(); + + if (readStdin) { + Expr e = evalStdin(state); + printNixExpr(state, e); + } + + for (Strings::iterator it = files.begin(); + it != files.end(); it++) + { + Expr e = evalFile(state, absPath(*it)); + printNixExpr(state, e); + } + + printEvalStats(state); +} + + +string programId = "nix-instantiate"; diff --git a/src/libexpr/nix.sdf b/src/libexpr/nix.sdf new file mode 100644 index 000000000000..615bdb974775 --- /dev/null +++ b/src/libexpr/nix.sdf @@ -0,0 +1,209 @@ +definition + +module Main +imports Fix + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Top level syntax. + +module Fix +imports Fix-Exprs Fix-Layout + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Expressions. + +module Fix-Exprs +imports Fix-Lexicals URI +exports + sorts Expr Formal Bind Binds BindSemi ExprList + context-free syntax + + Id -> Expr {cons("Var")} + + Int -> Expr {cons("Int")} + + Str -> Expr {cons("Str")} + + Uri -> Expr {cons("Uri")} + + Path -> Expr {cons("Path")} + + "(" Expr ")" -> Expr {bracket} + + Expr Expr -> Expr {cons("Call"), left} + + "{" {Formal ","}* "}" ":" Expr -> Expr {cons("Function")} + Id -> Formal {cons("NoDefFormal")} + Id "?" Expr -> Formal {cons("DefFormal")} + + "assert" Expr ";" Expr -> Expr {cons("Assert")} + + "rec" "{" Binds "}" -> Expr {cons("Rec")} + "let" "{" Binds "}" -> Expr {cons("LetRec")} + "{" Binds "}" -> Expr {cons("Attrs")} + + Id "=" Expr -> Bind {cons("Bind")} + {Bind ";"}* -> Binds + Bind ";" -> BindSemi + BindSemi* -> Binds + + "[" ExprList "]" -> Expr {cons("List")} + "" -> ExprList {cons("ExprNil")} + Expr ExprList -> ExprList {cons("ExprCons")} + + Expr "." Id -> Expr {cons("Select")} + + "if" Expr "then" Expr "else" Expr -> Expr {cons("If")} + + Expr "==" Expr -> Expr {cons("OpEq"), non-assoc} + Expr "!=" Expr -> Expr {cons("OpNEq"), non-assoc} + + "!" Expr -> Expr {cons("OpNot")} + Expr "&&" Expr -> Expr {cons("OpAnd"), right} + Expr "||" Expr -> Expr {cons("OpOr"), right} + Expr "->" Expr -> Expr {cons("OpImpl"), right} + + Bool -> Expr {cons("Bool")} + + context-free priorities + + Expr "." Id -> Expr + > Expr ExprList -> ExprList + > Expr Expr -> Expr + > "!" Expr -> Expr + > Expr "==" Expr -> Expr + > Expr "!=" Expr -> Expr + > Expr "&&" Expr -> Expr + > Expr "||" Expr -> Expr + > Expr "->" Expr -> Expr + > "assert" Expr ";" Expr -> Expr + > "{" {Formal ","}* "}" ":" Expr -> Expr + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Lexical syntax. + +module Fix-Lexicals +exports + sorts Id Int Str Path PathComp Bool + lexical syntax + [a-zA-Z\_][a-zA-Z0-9\_\']* -> Id + "rec" -> Id {reject} + "let" -> Id {reject} + "if" -> Id {reject} + "then" -> Id {reject} + "else" -> Id {reject} + "true" -> Id {reject} + "false" -> Id {reject} + "assert" -> Id {reject} + + [0-9]+ -> Int + + "\"" ~[\n\"]* "\"" -> Str + + PathComp ("/" PathComp)+ -> Path + [a-zA-Z0-9\.\_\-\+]+ -> PathComp + + "true" -> Bool + "false" -> Bool + + lexical restrictions + Id -/- [a-zA-Z0-9\_\'] + Int -/- [0-9] + Path -/- [a-zA-Z0-9\.\_\-\+\/] + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% URIs (RFC 2396, appendix A). + +module URI +exports + sorts Uri Uhierpart Uopaquepart Uuricnoslash Unetpath Uabspath + Urelpath Urelsegment Uscheme Uauthority Uregname Userver + Uuserinfo Uhostport Uhost Uhostname Udomainlabel Utoplabel + UIPv4address Uport Upath Upathsegments Usegment Uparam + Upchar Uquery Ufragment Uuric Ureserved Uunreserved Umark + Uescaped Uhex Ualphanum Ualpha Ulowalpha Uupalpha Udigit + lexical syntax + Uscheme ":" (Uhierpart | Uopaquepart) -> Uri + + (Unetpath | Uabspath) ("?" Uquery)? -> Uhierpart + Uuricnoslash Uuric* -> Uopaquepart + + Uunreserved | Uescaped | [\;\?\:\@\&\=\+\$\,] -> Uuricnoslash + + "//" Uauthority Uabspath? -> Unetpath + "/" Upathsegments -> Uabspath + "//" Uuric* -> Uabspath {reject} + Urelsegment Uabspath? -> Urelpath + + (Uunreserved | Uescaped | [\;\@\&\=\+\$\,])+ -> Urelsegment + + Ualpha (Ualpha | Udigit | [\+\-\.])* -> Uscheme + + Userver | Uregname -> Uauthority + + (Uunreserved | Uescaped | [\$\,\;\:\@\&\=\+])+ -> Uregname + + ((Uuserinfo "@") Uhostport) -> Userver + (Uunreserved | Uescaped | [\;\:\&\=\+\$\,])* -> Uuserinfo + + Uhost (":" Uport)? -> Uhostport + Uhostname | UIPv4address -> Uhost + (Udomainlabel ".")+ Utoplabel "."? -> Uhostname + Ualphanum | Ualphanum (Ualphanum | "-")* Ualphanum -> Udomainlabel + Ualpha | Ualpha (Ualphanum | "-")* Ualphanum -> Utoplabel + Udigit+ "." Udigit+ "." Udigit+ "." Udigit+ -> UIPv4address + Udigit* -> Uport + + Uabspath | Uopaquepart -> Upath + Usegment ("/" Usegment)* -> Upathsegments + Upchar* (";" Uparam)* -> Usegment + Upchar* -> Uparam + Uunreserved | Uescaped | [\:\@\&\=\+\$\,] -> Upchar + + Uuric* -> Uquery + + Uuric* -> Ufragment + + Ureserved | Uunreserved | Uescaped -> Uuric + [\;\/\?\:\@\&\=\+\$\,] -> Ureserved + Ualphanum | Umark -> Uunreserved + [\-\_\.\!\~\*\'\(\)] -> Umark + + "%" Uhex Uhex -> Uescaped + Udigit | [A-Fa-f] -> Uhex + + Ualpha | Udigit -> Ualphanum + Ulowalpha | Uupalpha -> Ualpha + + [a-z] -> Ulowalpha + [A-Z] -> Uupalpha + [0-9] -> Udigit + + lexical restrictions + Uri -/- [a-zA-Z0-9\-\_\.\!\~\*\'\(\)] + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Layout. + +module Fix-Layout +exports + sorts HashComment Asterisk Comment EOF + lexical syntax + [\ \t\n] -> LAYOUT + HashComment -> LAYOUT + Comment -> LAYOUT + "#" ~[\n]* ([\n] | EOF) -> HashComment + "//" ~[\n]* ([\n] | EOF) -> HashComment + "/*" ( ~[\*] | Asterisk )* "*/" -> Comment + [\*] -> Asterisk + "" -> EOF + lexical restrictions + Asterisk -/- [\/] + EOF -/- ~[] + context-free restrictions + LAYOUT? -/- [\ \t\n] | [\#] diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc new file mode 100644 index 000000000000..816b39dc1ae3 --- /dev/null +++ b/src/libexpr/nixexpr.cc @@ -0,0 +1,215 @@ +#include "nixexpr.hh" +#include "storeexpr.hh" + + +ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct) +{ + table = ATtableCreate(initialSize, maxLoadPct); + if (!table) throw Error("cannot create ATerm table"); +} + + +ATermMap::ATermMap(const ATermMap & map) + : table(0) +{ + ATermList keys = map.keys(); + + /* !!! adjust allocation for load pct */ + table = ATtableCreate(ATgetLength(keys), map.maxLoadPct); + if (!table) throw Error("cannot create ATerm table"); + + for (ATermIterator i(keys); i; ++i) + set(*i, map.get(*i)); +} + + +ATermMap::~ATermMap() +{ + if (table) ATtableDestroy(table); +} + + +void ATermMap::set(ATerm key, ATerm value) +{ + return ATtablePut(table, key, value); +} + + +void ATermMap::set(const string & key, ATerm value) +{ + set(string2ATerm(key), value); +} + + +ATerm ATermMap::get(ATerm key) const +{ + return ATtableGet(table, key); +} + + +ATerm ATermMap::get(const string & key) const +{ + return get(string2ATerm(key)); +} + + +void ATermMap::remove(ATerm key) +{ + ATtableRemove(table, key); +} + + +void ATermMap::remove(const string & key) +{ + remove(string2ATerm(key)); +} + + +ATermList ATermMap::keys() const +{ + ATermList keys = ATtableKeys(table); + if (!keys) throw Error("cannot query aterm map keys"); + return keys; +} + + +ATerm string2ATerm(const string & s) +{ + return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue)); +} + + +string aterm2String(ATerm t) +{ + return ATgetName(ATgetAFun(t)); +} + + +ATerm bottomupRewrite(TermFun & f, ATerm e) +{ + if (ATgetType(e) == AT_APPL) { + AFun fun = ATgetAFun(e); + int arity = ATgetArity(fun); + ATermList args = ATempty; + + for (int i = arity - 1; i >= 0; i--) + args = ATinsert(args, bottomupRewrite(f, ATgetArgument(e, i))); + + e = (ATerm) ATmakeApplList(fun, args); + } + + else if (ATgetType(e) == AT_LIST) { + ATermList in = (ATermList) e; + ATermList out = ATempty; + + for (ATermIterator i(in); i; ++i) + out = ATinsert(out, bottomupRewrite(f, *i)); + + e = (ATerm) ATreverse(out); + } + + return f(e); +} + + +void queryAllAttrs(Expr e, ATermMap & attrs) +{ + ATMatcher m; + ATermList bnds; + if (!(atMatch(m, e) >> "Attrs" >> bnds)) + throw badTerm("expected attribute set", e); + + for (ATermIterator i(bnds); i; ++i) { + string s; + Expr e; + if (!(atMatch(m, *i) >> "Bind" >> s >> e)) + abort(); /* can't happen */ + attrs.set(s, e); + } +} + + +Expr queryAttr(Expr e, const string & name) +{ + ATermMap attrs; + queryAllAttrs(e, attrs); + return attrs.get(name); +} + + +Expr makeAttrs(const ATermMap & attrs) +{ + ATermList bnds = ATempty; + for (ATermIterator i(attrs.keys()); i; ++i) + bnds = ATinsert(bnds, + ATmake("Bind(, )", *i, attrs.get(*i))); + return ATmake("Attrs()", ATreverse(bnds)); +} + + +Expr substitute(const ATermMap & subs, Expr e) +{ + ATMatcher m; + string s; + + if (atMatch(m, e) >> "Var" >> s) { + Expr sub = subs.get(s); + return sub ? sub : e; + } + + /* In case of a function, filter out all variables bound by this + function. */ + ATermList formals; + ATerm body; + if (atMatch(m, e) >> "Function" >> formals >> body) { + ATermMap subs2(subs); + for (ATermIterator i(formals); i; ++i) { + Expr def; + if (!(atMatch(m, *i) >> "NoDefFormal" >> s) && + !(atMatch(m, *i) >> "DefFormal" >> s >> def)) + abort(); + subs2.remove(s); + } + return ATmake("Function(, )", formals, + substitute(subs2, body)); + } + + /* Idem for a mutually recursive attribute set. */ + ATermList bindings; + if (atMatch(m, e) >> "Rec" >> bindings) { + ATermMap subs2(subs); + for (ATermIterator i(bindings); i; ++i) { + Expr e; + if (!(atMatch(m, *i) >> "Bind" >> s >> e)) + abort(); /* can't happen */ + subs2.remove(s); + } + return ATmake("Rec()", substitute(subs2, (ATerm) bindings)); + } + + if (ATgetType(e) == AT_APPL) { + AFun fun = ATgetAFun(e); + int arity = ATgetArity(fun); + ATermList args = ATempty; + + for (int i = arity - 1; i >= 0; i--) + args = ATinsert(args, substitute(subs, ATgetArgument(e, i))); + + return (ATerm) ATmakeApplList(fun, args); + } + + if (ATgetType(e) == AT_LIST) { + ATermList out = ATempty; + for (ATermIterator i((ATermList) e); i; ++i) + out = ATinsert(out, substitute(subs, *i)); + return (ATerm) ATreverse(out); + } + + return e; +} + + +Expr makeBool(bool b) +{ + return b ? ATmake("Bool(True)") : ATmake("Bool(False)"); +} diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh new file mode 100644 index 000000000000..011c2900e12a --- /dev/null +++ b/src/libexpr/nixexpr.hh @@ -0,0 +1,75 @@ +#ifndef __NIXEXPR_H +#define __NIXEXPR_H + +#include + +#include + +#include "util.hh" + + +/* Nix expressions are represented as ATerms. The maximal sharing + property of the ATerm library allows us to implement caching of + normals forms efficiently. */ +typedef ATerm Expr; + + +/* Mappings from ATerms to ATerms. This is just a wrapper around + ATerm tables. */ +class ATermMap +{ +private: + unsigned int maxLoadPct; + ATermTable table; + +public: + ATermMap(unsigned int initialSize = 16, unsigned int maxLoadPct = 75); + ATermMap(const ATermMap & map); + ~ATermMap(); + + void set(ATerm key, ATerm value); + void set(const string & key, ATerm value); + + ATerm get(ATerm key) const; + ATerm get(const string & key) const; + + void remove(ATerm key); + void remove(const string & key); + + ATermList keys() const; +}; + + +/* Convert a string to an ATerm (i.e., a quoted nullary function + applicaton). */ +ATerm string2ATerm(const string & s); +string aterm2String(ATerm t); + +/* Generic bottomup traversal over ATerms. The traversal first + recursively descends into subterms, and then applies the given term + function to the resulting term. */ +struct TermFun +{ + virtual ATerm operator () (ATerm e) = 0; +}; +ATerm bottomupRewrite(TermFun & f, ATerm e); + +/* Query all attributes in an attribute set expression. The + expression must be in normal form. */ +void queryAllAttrs(Expr e, ATermMap & attrs); + +/* Query a specific attribute from an attribute set expression. The + expression must be in normal form. */ +Expr queryAttr(Expr e, const string & name); + +/* Create an attribute set expression from an Attrs value. */ +Expr makeAttrs(const ATermMap & attrs); + +/* Perform a set of substitutions on an expression. */ +Expr substitute(const ATermMap & subs, Expr e); + +/* Create an expression representing a boolean. */ +Expr makeBool(bool b); + + +#endif /* !__NIXEXPR_H */ diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc new file mode 100644 index 000000000000..b2c74af33e77 --- /dev/null +++ b/src/libexpr/parser.cc @@ -0,0 +1,164 @@ +#include + +#include +#include +#include +#include + +extern "C" { +#include +#include +} + +#include "aterm.hh" +#include "parser.hh" +#include "shared.hh" +#include "parse-table.h" + + +/* Cleanup cleans up an imploded parse tree into an actual abstract + syntax tree that we can evaluate. It removes quotes around + strings, converts integer literals into actual integers, and + absolutises paths relative to the directory containing the input + file. */ +struct Cleanup : TermFun +{ + string basePath; + + virtual ATerm operator () (ATerm e) + { + ATMatcher m; + string s; + + if (atMatch(m, e) >> "Str" >> s) { + return ATmake("Str()", + string(s, 1, s.size() - 2).c_str()); + } + + if (atMatch(m, e) >> "Path" >> s) { + if (s[0] != '/') + s = basePath + "/" + s; + return ATmake("Path()", canonPath(s).c_str()); + } + + if (atMatch(m, e) >> "Int" >> s) { + istringstream s2(s); + int n; + s2 >> n; + return ATmake("Int()", n); + } + + if (atMatch(m, e) >> "Bool" >> "true") + return ATmake("Bool(True)"); + + if (atMatch(m, e) >> "Bool" >> "false") + return ATmake("Bool(False)"); + + if (atMatch(m, e) >> "ExprNil") + return (ATerm) ATempty; + + ATerm e1; + ATermList e2; + if (atMatch(m, e) >> "ExprCons" >> e1 >> e2) + return (ATerm) ATinsert(e2, e1); + + return e; + } +}; + + +Expr parseExprFromFile(Path path) +{ +#if 0 + /* Perhaps this is already an imploded parse tree? */ + Expr e = ATreadFromNamedFile(path.c_str()); + if (e) return e; +#endif + + /* If `path' refers to a directory, append `/default.nix'. */ + struct stat st; + if (stat(path.c_str(), &st)) + throw SysError(format("getting status of `%1%'") % path); + if (S_ISDIR(st.st_mode)) + path = canonPath(path + "/default.nix"); + + /* Initialise the SDF libraries. */ + static bool initialised = false; + static ATerm parseTable = 0; + static language lang = 0; + + if (!initialised) { + PT_initMEPTApi(); + PT_initAsFix2Api(); + SGinitParser(ATfalse); + + ATprotect(&parseTable); + parseTable = ATreadFromBinaryString( + (char *) nixParseTable, sizeof nixParseTable); + if (!parseTable) + throw Error(format("cannot construct parse table term")); + + ATprotect(&lang); + lang = ATmake("Nix"); + if (!SGopenLanguageFromTerm( + (char *) programId.c_str(), lang, parseTable)) + throw Error(format("cannot open language")); + + SG_STARTSYMBOL_ON(); + SG_OUTPUT_ON(); + SG_ASFIX2ME_ON(); + SG_AMBIGUITY_ERROR_ON(); + SG_FILTER_OFF(); + + initialised = true; + } + + /* Read the input file. We can't use SGparseFile() because it's + broken, so we read the input ourselves and call + SGparseString(). */ + AutoCloseFD fd = open(path.c_str(), O_RDONLY); + if (fd == -1) throw SysError(format("opening `%1%'") % path); + + if (fstat(fd, &st) == -1) + throw SysError(format("statting `%1%'") % path); + + char text[st.st_size + 1]; + readFull(fd, (unsigned char *) text, st.st_size); + text[st.st_size] = 0; + + /* Parse it. */ + ATerm result = SGparseString(lang, "Expr", text); + if (!result) + throw SysError(format("parse failed in `%1%'") % path); + if (SGisParseError(result)) + throw Error(format("parse error in `%1%': %2%") + % path % result); + + /* Implode it. */ + PT_ParseTree tree = PT_makeParseTreeFromTerm(result); + if (!tree) + throw Error(format("cannot create parse tree")); + + ATerm imploded = PT_implodeParseTree(tree, + ATtrue, + ATtrue, + ATtrue, + ATtrue, + ATtrue, + ATtrue, + ATfalse, + ATtrue, + ATtrue, + ATtrue, + ATfalse); + if (!imploded) + throw Error(format("cannot implode parse tree")); + + printMsg(lvlVomit, format("imploded parse tree of `%1%': %2%") + % path % imploded); + + /* Finally, clean it up. */ + Cleanup cleanup; + cleanup.basePath = dirOf(path); + return bottomupRewrite(cleanup, imploded); +} diff --git a/src/libexpr/parser.hh b/src/libexpr/parser.hh new file mode 100644 index 000000000000..5983ec5629e4 --- /dev/null +++ b/src/libexpr/parser.hh @@ -0,0 +1,10 @@ +#ifndef __PARSER_H +#define __PARSER_H + +#include "nixexpr.hh" + + +Expr parseExprFromFile(Path path); + + +#endif /* !__PARSER_H */ diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc new file mode 100644 index 000000000000..097933115342 --- /dev/null +++ b/src/libexpr/primops.cc @@ -0,0 +1,246 @@ +#include "primops.hh" +#include "normalise.hh" +#include "globals.hh" + + +Expr primImport(EvalState & state, Expr arg) +{ + ATMatcher m; + string path; + if (!(atMatch(m, arg) >> "Path" >> path)) + throw badTerm("path expected", arg); + return evalFile(state, path); +} + + +static PathSet storeExprRootsCached(EvalState & state, const Path & nePath) +{ + DrvPaths::iterator i = state.drvPaths.find(nePath); + if (i != state.drvPaths.end()) + return i->second; + else { + PathSet paths = storeExprRoots(nePath); + state.drvPaths[nePath] = paths; + return paths; + } +} + + +static Hash hashDerivation(EvalState & state, StoreExpr ne) +{ + if (ne.type == StoreExpr::neDerivation) { + PathSet inputs2; + for (PathSet::iterator i = ne.derivation.inputs.begin(); + i != ne.derivation.inputs.end(); i++) + { + DrvHashes::iterator j = state.drvHashes.find(*i); + if (j == state.drvHashes.end()) + throw Error(format("don't know expression `%1%'") % (string) *i); + inputs2.insert(j->second); + } + ne.derivation.inputs = inputs2; + } + return hashTerm(unparseStoreExpr(ne)); +} + + +static Path copyAtom(EvalState & state, const Path & srcPath) +{ + /* !!! should be cached */ + Path dstPath(addToStore(srcPath)); + + ClosureElem elem; + StoreExpr ne; + ne.type = StoreExpr::neClosure; + ne.closure.roots.insert(dstPath); + ne.closure.elems[dstPath] = elem; + + Hash drvHash = hashDerivation(state, ne); + Path drvPath = writeTerm(unparseStoreExpr(ne), ""); + state.drvHashes[drvPath] = drvHash; + + printMsg(lvlChatty, format("copied `%1%' -> closure `%2%'") + % srcPath % drvPath); + return drvPath; +} + + +static string addInput(EvalState & state, + Path & nePath, StoreExpr & ne) +{ + PathSet paths = storeExprRootsCached(state, nePath); + if (paths.size() != 1) abort(); + Path path = *(paths.begin()); + ne.derivation.inputs.insert(nePath); + return path; +} + + +static string processBinding(EvalState & state, Expr e, StoreExpr & ne) +{ + e = evalExpr(state, e); + + ATMatcher m; + string s; + ATermList es; + + if (atMatch(m, e) >> "Str" >> s) return s; + if (atMatch(m, e) >> "Uri" >> s) return s; + if (atMatch(m, e) >> "Bool" >> "True") return "1"; + if (atMatch(m, e) >> "Bool" >> "False") return ""; + + if (atMatch(m, e) >> "Attrs" >> es) { + Expr a = queryAttr(e, "type"); + if (a && evalString(state, a) == "derivation") { + a = queryAttr(e, "drvPath"); + if (a) { + Path drvPath = evalPath(state, a); + return addInput(state, drvPath, ne); + } + } + } + + if (atMatch(m, e) >> "Path" >> s) { + Path drvPath = copyAtom(state, s); + return addInput(state, drvPath, ne); + } + + if (atMatch(m, e) >> "List" >> es) { + string s; + bool first = true; + for (ATermIterator i(es); i; ++i) { + startNest(nest, lvlVomit, format("processing list element")); + if (!first) s = s + " "; else first = false; + s += processBinding(state, evalExpr(state, *i), ne); + } + return s; + } + + if (atMatch(m, e) >> "Null") return ""; + + throw badTerm("invalid derivation binding", e); +} + + +Expr primDerivation(EvalState & state, Expr args) +{ + startNest(nest, lvlVomit, "evaluating derivation"); + + ATermMap attrs; + args = evalExpr(state, args); + queryAllAttrs(args, attrs); + + /* Build the derivation expression by processing the attributes. */ + StoreExpr ne; + ne.type = StoreExpr::neDerivation; + + string drvName; + Path outPath; + Hash outHash; + bool outHashGiven = false; + + for (ATermIterator i(attrs.keys()); i; ++i) { + string key = aterm2String(*i); + Expr value = attrs.get(key); + startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); + + /* The `args' attribute is special: it supplies the + command-line arguments to the builder. */ + if (key == "args") { + throw Error("args not implemented"); +#if 0 + ATermList args; + if (!(ATmatch(value, "[]", &args)) + throw badTerm("list expected", value); + while (!ATisEmpty(args)) { + Expr arg = evalExpr(state, ATgetFirst(args)); + ne.derivation.args.push_back(processBinding(state, arg, ne)); + args = ATgetNext(args); + } +#endif + } + + /* All other attributes are passed to the builder through the + environment. */ + else { + string s = processBinding(state, value, ne); + ne.derivation.env[key] = s; + if (key == "builder") ne.derivation.builder = s; + else if (key == "system") ne.derivation.platform = s; + else if (key == "name") drvName = s; + else if (key == "outPath") outPath = s; + else if (key == "id") { + outHash = parseHash(s); + outHashGiven = true; + } + } + } + + /* Do we have all required attributes? */ + if (ne.derivation.builder == "") + throw badTerm("required attribute `builder' missing", args); + if (ne.derivation.platform == "") + throw badTerm("required attribute `system' missing", args); + if (drvName == "") + throw badTerm("required attribute `name' missing", args); + + /* Determine the output path. */ + if (!outHashGiven) outHash = hashDerivation(state, ne); + if (outPath == "") + /* Hash the Nix expression with no outputs to produce a + unique but deterministic path name for this derivation. */ + outPath = canonPath(nixStore + "/" + + ((string) outHash).c_str() + "-" + drvName); + ne.derivation.env["out"] = outPath; + ne.derivation.outputs.insert(outPath); + + /* Write the resulting term into the Nix store directory. */ + Hash drvHash = outHashGiven + ? hashString((string) outHash + outPath) + : hashDerivation(state, ne); + Path drvPath = writeTerm(unparseStoreExpr(ne), "-d-" + drvName); + state.drvHashes[drvPath] = drvHash; + + printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'") + % drvName % drvPath); + + attrs.set("outPath", ATmake("Path()", outPath.c_str())); + attrs.set("drvPath", ATmake("Path()", drvPath.c_str())); + attrs.set("type", ATmake("Str(\"derivation\")")); + + return makeAttrs(attrs); +} + + +Expr primBaseNameOf(EvalState & state, Expr arg) +{ + string s = evalString(state, arg); + return ATmake("Str()", baseNameOf(s).c_str()); +} + + +Expr primToString(EvalState & state, Expr arg) +{ + arg = evalExpr(state, arg); + ATMatcher m; + string s; + if (atMatch(m, arg) >> "Str" >> s || + atMatch(m, arg) >> "Path" >> s || + atMatch(m, arg) >> "Uri" >> s) + return ATmake("Str()", s.c_str()); + else throw badTerm("cannot coerce to string", arg); +} + + +Expr primNull(EvalState & state) +{ + return ATmake("Null"); +} + + +Expr primIsNull(EvalState & state, Expr arg) +{ + arg = evalExpr(state, arg); + ATMatcher m; + return makeBool(atMatch(m, arg) >> "Null"); +} diff --git a/src/libexpr/primops.hh b/src/libexpr/primops.hh new file mode 100644 index 000000000000..76d587afdb1e --- /dev/null +++ b/src/libexpr/primops.hh @@ -0,0 +1,34 @@ +#ifndef __PRIMOPS_H +#define __PRIMOPS_H + +#include "eval.hh" + + +/* Load and evaluate an expression from path specified by the + argument. */ +Expr primImport(EvalState & state, Expr arg); + +/* Construct (as a unobservable) side effect) a Nix derivation + expression that performs the derivation described by the argument + set. Returns the original set extended with the following + attributes: `outPath' containing the primary output path of the + derivation; `drvPath' containing the path of the Nix expression; + and `type' set to `derivation' to indicate that this is a + derivation. */ +Expr primDerivation(EvalState & state, Expr args); + +/* Return the base name of the given string, i.e., everything + following the last slash. */ +Expr primBaseNameOf(EvalState & state, Expr arg); + +/* Convert the argument (which can be a path or a uri) to a string. */ +Expr primToString(EvalState & state, Expr arg); + +/* Return the null value. */ +Expr primNull(EvalState & state); + +/* Determine whether the argument is the null value. */ +Expr primIsNull(EvalState & state, Expr arg); + + +#endif /* !__PRIMOPS_H */ diff --git a/src/nix-instantiate/Makefile.am b/src/nix-instantiate/Makefile.am deleted file mode 100644 index 6fe79850116e..000000000000 --- a/src/nix-instantiate/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -bin_PROGRAMS = nix-instantiate - -nix_instantiate_SOURCES = nixexpr.cc parser.cc eval.cc primops.cc main.cc -nix_instantiate_LDADD = ../libmain/libmain.a ../libstore/libstore.a ../libutil/libutil.a \ - ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx \ - -lsglr -lATB -lconversion -lasfix2 -lmept -lATerm - -AM_CXXFLAGS = \ - -I.. -I../../externals/inst/include -I../libutil -I../libstore -I../libmain - - -# Parse table generation. - -parser.o: parse-table.h - -parse-table.h: nix.tbl - ../bin2c/bin2c nixParseTable < $< > $@ || (rm $@ && exit 1) - -%.tbl: %.sdf - ../../externals/inst/bin/sdf2table -s -i $< -o $@ - -CLEANFILES = parse-table.h nix.tbl diff --git a/src/nix-instantiate/eval.cc b/src/nix-instantiate/eval.cc deleted file mode 100644 index b110c3a4a41c..000000000000 --- a/src/nix-instantiate/eval.cc +++ /dev/null @@ -1,265 +0,0 @@ -#include "eval.hh" -#include "parser.hh" -#include "primops.hh" - - -EvalState::EvalState() - : normalForms(32768, 75) -{ - blackHole = ATmake("BlackHole()"); - if (!blackHole) throw Error("cannot build black hole"); - nrEvaluated = nrCached = 0; -} - - -/* Substitute an argument set into the body of a function. */ -static Expr substArgs(Expr body, ATermList formals, Expr arg) -{ - ATMatcher m; - ATermMap subs; - Expr undefined = ATmake("Undefined"); - - /* Get the formal arguments. */ - for (ATermIterator i(formals); i; ++i) { - Expr name, def; - if (atMatch(m, *i) >> "NoDefFormal" >> name) - subs.set(name, undefined); - else if (atMatch(m, *i) >> "DefFormal" >> name >> def) - subs.set(name, def); - else abort(); /* can't happen */ - } - - /* Get the actual arguments, and check that they match with the - formals. */ - ATermMap args; - queryAllAttrs(arg, args); - for (ATermIterator i(args.keys()); i; ++i) { - Expr key = *i; - Expr cur = subs.get(key); - if (!cur) - throw badTerm(format("function has no formal argument `%1%'") - % aterm2String(key), arg); - subs.set(key, args.get(key)); - } - - /* Check that all arguments are defined. */ - for (ATermIterator i(subs.keys()); i; ++i) - if (subs.get(*i) == undefined) - throw badTerm(format("formal argument `%1%' missing") - % aterm2String(*i), arg); - - return substitute(subs, body); -} - - -/* Transform a mutually recursive set into a non-recursive set. Each - attribute is transformed into an expression that has all references - to attributes substituted with selection expressions on the - original set. E.g., e = `rec {x = f x y, y = x}' becomes `{x = f - (e.x) (e.y), y = e.x}'. */ -ATerm expandRec(ATerm e, ATermList bnds) -{ - ATMatcher m; - - /* Create the substitution list. */ - ATermMap subs; - for (ATermIterator i(bnds); i; ++i) { - string s; - Expr e2; - if (!(atMatch(m, *i) >> "Bind" >> s >> e2)) - abort(); /* can't happen */ - subs.set(s, ATmake("Select(, )", e, s.c_str())); - } - - /* Create the non-recursive set. */ - ATermMap as; - for (ATermIterator i(bnds); i; ++i) { - string s; - Expr e2; - if (!(atMatch(m, *i) >> "Bind" >> s >> e2)) - abort(); /* can't happen */ - as.set(s, substitute(subs, e2)); - } - - return makeAttrs(as); -} - - -string evalString(EvalState & state, Expr e) -{ - e = evalExpr(state, e); - ATMatcher m; - string s; - if (!(atMatch(m, e) >> "Str" >> s)) - throw badTerm("string expected", e); - return s; -} - - -Path evalPath(EvalState & state, Expr e) -{ - e = evalExpr(state, e); - ATMatcher m; - string s; - if (!(atMatch(m, e) >> "Path" >> s)) - throw badTerm("path expected", e); - return s; -} - - -bool evalBool(EvalState & state, Expr e) -{ - e = evalExpr(state, e); - ATMatcher m; - if (atMatch(m, e) >> "Bool" >> "True") return true; - else if (atMatch(m, e) >> "Bool" >> "False") return false; - else throw badTerm("expecting a boolean", e); -} - - -Expr evalExpr2(EvalState & state, Expr e) -{ - ATMatcher m; - Expr e1, e2, e3, e4; - string s1; - - /* Normal forms. */ - if (atMatch(m, e) >> "Str" || - atMatch(m, e) >> "Path" || - atMatch(m, e) >> "Uri" || - atMatch(m, e) >> "Bool" || - atMatch(m, e) >> "Function" || - atMatch(m, e) >> "Attrs" || - atMatch(m, e) >> "List") - return e; - - /* Any encountered variables must be undeclared or primops. */ - if (atMatch(m, e) >> "Var" >> s1) { - if (s1 == "null") return primNull(state); - return e; - } - - /* Function application. */ - if (atMatch(m, e) >> "Call" >> e1 >> e2) { - - ATermList formals; - - /* Evaluate the left-hand side. */ - e1 = evalExpr(state, e1); - - /* Is it a primop or a function? */ - if (atMatch(m, e1) >> "Var" >> s1) { - if (s1 == "import") return primImport(state, e2); - if (s1 == "derivation") return primDerivation(state, e2); - if (s1 == "toString") return primToString(state, e2); - if (s1 == "baseNameOf") return primBaseNameOf(state, e2); - if (s1 == "isNull") return primIsNull(state, e2); - else throw badTerm("undefined variable/primop", e1); - } - - else if (atMatch(m, e1) >> "Function" >> formals >> e4) - return evalExpr(state, - substArgs(e4, formals, evalExpr(state, e2))); - - else throw badTerm("expecting a function or primop", e1); - } - - /* Attribute selection. */ - if (atMatch(m, e) >> "Select" >> e1 >> s1) { - Expr a = queryAttr(evalExpr(state, e1), s1); - if (!a) throw badTerm(format("missing attribute `%1%'") % s1, e); - return evalExpr(state, a); - } - - /* Mutually recursive sets. */ - ATermList bnds; - if (atMatch(m, e) >> "Rec" >> bnds) - return expandRec(e, bnds); - - /* Let expressions `let {..., body = ...}' are just desugared - into `(rec {..., body = ...}).body'. */ - if (atMatch(m, e) >> "LetRec" >> bnds) - return evalExpr(state, ATmake("Select(Rec(), \"body\")", bnds)); - - /* Conditionals. */ - if (atMatch(m, e) >> "If" >> e1 >> e2 >> e3) { - if (evalBool(state, e1)) - return evalExpr(state, e2); - else - return evalExpr(state, e3); - } - - /* Assertions. */ - if (atMatch(m, e) >> "Assert" >> e1 >> e2) { - if (!evalBool(state, e1)) throw badTerm("guard failed", e); - return evalExpr(state, e2); - } - - /* Generic equality. */ - if (atMatch(m, e) >> "OpEq" >> e1 >> e2) - return makeBool(evalExpr(state, e1) == evalExpr(state, e2)); - - /* Generic inequality. */ - if (atMatch(m, e) >> "OpNEq" >> e1 >> e2) - return makeBool(evalExpr(state, e1) != evalExpr(state, e2)); - - /* Negation. */ - if (atMatch(m, e) >> "OpNot" >> e1) - return makeBool(!evalBool(state, e1)); - - /* Implication. */ - if (atMatch(m, e) >> "OpImpl" >> e1 >> e2) - return makeBool(!evalBool(state, e1) || evalBool(state, e2)); - - /* Conjunction (logical AND). */ - if (atMatch(m, e) >> "OpAnd" >> e1 >> e2) - return makeBool(evalBool(state, e1) && evalBool(state, e2)); - - /* Disjunction (logical OR). */ - if (atMatch(m, e) >> "OpOr" >> e1 >> e2) - return makeBool(evalBool(state, e1) || evalBool(state, e2)); - - /* Barf. */ - throw badTerm("invalid expression", e); -} - - -Expr evalExpr(EvalState & state, Expr e) -{ - startNest(nest, lvlVomit, - format("evaluating expression: %1%") % e); - - state.nrEvaluated++; - - /* Consult the memo table to quickly get the normal form of - previously evaluated expressions. */ - Expr nf = state.normalForms.get(e); - if (nf) { - if (nf == state.blackHole) - throw badTerm("infinite recursion", e); - state.nrCached++; - return nf; - } - - /* Otherwise, evaluate and memoize. */ - state.normalForms.set(e, state.blackHole); - nf = evalExpr2(state, e); - state.normalForms.set(e, nf); - return nf; -} - - -Expr evalFile(EvalState & state, const Path & path) -{ - startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); - Expr e = parseExprFromFile(path); - return evalExpr(state, e); -} - - -void printEvalStats(EvalState & state) -{ - debug(format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency") - % state.nrEvaluated % state.nrCached - % ((float) state.nrCached / (float) state.nrEvaluated * 100)); -} diff --git a/src/nix-instantiate/eval.hh b/src/nix-instantiate/eval.hh deleted file mode 100644 index 0bc052676deb..000000000000 --- a/src/nix-instantiate/eval.hh +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __EVAL_H -#define __EVAL_H - -#include - -#include "aterm.hh" -#include "hash.hh" -#include "nixexpr.hh" - - -typedef map DrvPaths; -typedef map DrvHashes; - -struct EvalState -{ - ATermMap normalForms; - DrvPaths drvPaths; - DrvHashes drvHashes; /* normalised derivation hashes */ - Expr blackHole; - - unsigned int nrEvaluated; - unsigned int nrCached; - - EvalState(); -}; - - -/* Evaluate an expression to normal form. */ -Expr evalExpr(EvalState & state, Expr e); - -/* Evaluate an expression read from the given file to normal form. */ -Expr evalFile(EvalState & state, const Path & path); - -/* Specific results. */ -string evalString(EvalState & state, Expr e); -Path evalPath(EvalState & state, Expr e); - -/* Print statistics. */ -void printEvalStats(EvalState & state); - - -#endif /* !__EVAL_H */ diff --git a/src/nix-instantiate/fix-expr.cc b/src/nix-instantiate/fix-expr.cc deleted file mode 100644 index e9c5a3ba633f..000000000000 --- a/src/nix-instantiate/fix-expr.cc +++ /dev/null @@ -1,215 +0,0 @@ -#include "fix-expr.hh" -#include "expr.hh" - - -ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct) -{ - table = ATtableCreate(initialSize, maxLoadPct); - if (!table) throw Error("cannot create ATerm table"); -} - - -ATermMap::ATermMap(const ATermMap & map) - : table(0) -{ - ATermList keys = map.keys(); - - /* !!! adjust allocation for load pct */ - table = ATtableCreate(ATgetLength(keys), map.maxLoadPct); - if (!table) throw Error("cannot create ATerm table"); - - for (ATermIterator i(keys); i; ++i) - set(*i, map.get(*i)); -} - - -ATermMap::~ATermMap() -{ - if (table) ATtableDestroy(table); -} - - -void ATermMap::set(ATerm key, ATerm value) -{ - return ATtablePut(table, key, value); -} - - -void ATermMap::set(const string & key, ATerm value) -{ - set(string2ATerm(key), value); -} - - -ATerm ATermMap::get(ATerm key) const -{ - return ATtableGet(table, key); -} - - -ATerm ATermMap::get(const string & key) const -{ - return get(string2ATerm(key)); -} - - -void ATermMap::remove(ATerm key) -{ - ATtableRemove(table, key); -} - - -void ATermMap::remove(const string & key) -{ - remove(string2ATerm(key)); -} - - -ATermList ATermMap::keys() const -{ - ATermList keys = ATtableKeys(table); - if (!keys) throw Error("cannot query aterm map keys"); - return keys; -} - - -ATerm string2ATerm(const string & s) -{ - return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue)); -} - - -string aterm2String(ATerm t) -{ - return ATgetName(ATgetAFun(t)); -} - - -ATerm bottomupRewrite(TermFun & f, ATerm e) -{ - if (ATgetType(e) == AT_APPL) { - AFun fun = ATgetAFun(e); - int arity = ATgetArity(fun); - ATermList args = ATempty; - - for (int i = arity - 1; i >= 0; i--) - args = ATinsert(args, bottomupRewrite(f, ATgetArgument(e, i))); - - e = (ATerm) ATmakeApplList(fun, args); - } - - else if (ATgetType(e) == AT_LIST) { - ATermList in = (ATermList) e; - ATermList out = ATempty; - - for (ATermIterator i(in); i; ++i) - out = ATinsert(out, bottomupRewrite(f, *i)); - - e = (ATerm) ATreverse(out); - } - - return f(e); -} - - -void queryAllAttrs(Expr e, ATermMap & attrs) -{ - ATMatcher m; - ATermList bnds; - if (!(atMatch(m, e) >> "Attrs" >> bnds)) - throw badTerm("expected attribute set", e); - - for (ATermIterator i(bnds); i; ++i) { - string s; - Expr e; - if (!(atMatch(m, *i) >> "Bind" >> s >> e)) - abort(); /* can't happen */ - attrs.set(s, e); - } -} - - -Expr queryAttr(Expr e, const string & name) -{ - ATermMap attrs; - queryAllAttrs(e, attrs); - return attrs.get(name); -} - - -Expr makeAttrs(const ATermMap & attrs) -{ - ATermList bnds = ATempty; - for (ATermIterator i(attrs.keys()); i; ++i) - bnds = ATinsert(bnds, - ATmake("Bind(, )", *i, attrs.get(*i))); - return ATmake("Attrs()", ATreverse(bnds)); -} - - -Expr substitute(const ATermMap & subs, Expr e) -{ - ATMatcher m; - string s; - - if (atMatch(m, e) >> "Var" >> s) { - Expr sub = subs.get(s); - return sub ? sub : e; - } - - /* In case of a function, filter out all variables bound by this - function. */ - ATermList formals; - ATerm body; - if (atMatch(m, e) >> "Function" >> formals >> body) { - ATermMap subs2(subs); - for (ATermIterator i(formals); i; ++i) { - Expr def; - if (!(atMatch(m, *i) >> "NoDefFormal" >> s) && - !(atMatch(m, *i) >> "DefFormal" >> s >> def)) - abort(); - subs2.remove(s); - } - return ATmake("Function(, )", formals, - substitute(subs2, body)); - } - - /* Idem for a mutually recursive attribute set. */ - ATermList bindings; - if (atMatch(m, e) >> "Rec" >> bindings) { - ATermMap subs2(subs); - for (ATermIterator i(bindings); i; ++i) { - Expr e; - if (!(atMatch(m, *i) >> "Bind" >> s >> e)) - abort(); /* can't happen */ - subs2.remove(s); - } - return ATmake("Rec()", substitute(subs2, (ATerm) bindings)); - } - - if (ATgetType(e) == AT_APPL) { - AFun fun = ATgetAFun(e); - int arity = ATgetArity(fun); - ATermList args = ATempty; - - for (int i = arity - 1; i >= 0; i--) - args = ATinsert(args, substitute(subs, ATgetArgument(e, i))); - - return (ATerm) ATmakeApplList(fun, args); - } - - if (ATgetType(e) == AT_LIST) { - ATermList out = ATempty; - for (ATermIterator i((ATermList) e); i; ++i) - out = ATinsert(out, substitute(subs, *i)); - return (ATerm) ATreverse(out); - } - - return e; -} - - -Expr makeBool(bool b) -{ - return b ? ATmake("Bool(True)") : ATmake("Bool(False)"); -} diff --git a/src/nix-instantiate/fix-expr.hh b/src/nix-instantiate/fix-expr.hh deleted file mode 100644 index 6c1e51d9ccd6..000000000000 --- a/src/nix-instantiate/fix-expr.hh +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __FIXEXPR_H -#define __FIXEXPR_H - -#include - -#include - -#include "util.hh" - - -/* Fix expressions are represented as ATerms. The maximal sharing - property of the ATerm library allows us to implement caching of - normals forms efficiently. */ -typedef ATerm Expr; - - -/* Mappings from ATerms to ATerms. This is just a wrapper around - ATerm tables. */ -class ATermMap -{ -private: - unsigned int maxLoadPct; - ATermTable table; - -public: - ATermMap(unsigned int initialSize = 16, unsigned int maxLoadPct = 75); - ATermMap(const ATermMap & map); - ~ATermMap(); - - void set(ATerm key, ATerm value); - void set(const string & key, ATerm value); - - ATerm get(ATerm key) const; - ATerm get(const string & key) const; - - void remove(ATerm key); - void remove(const string & key); - - ATermList keys() const; -}; - - -/* Convert a string to an ATerm (i.e., a quoted nullary function - applicaton). */ -ATerm string2ATerm(const string & s); -string aterm2String(ATerm t); - -/* Generic bottomup traversal over ATerms. The traversal first - recursively descends into subterms, and then applies the given term - function to the resulting term. */ -struct TermFun -{ - virtual ATerm operator () (ATerm e) = 0; -}; -ATerm bottomupRewrite(TermFun & f, ATerm e); - -/* Query all attributes in an attribute set expression. The - expression must be in normal form. */ -void queryAllAttrs(Expr e, ATermMap & attrs); - -/* Query a specific attribute from an attribute set expression. The - expression must be in normal form. */ -Expr queryAttr(Expr e, const string & name); - -/* Create an attribute set expression from an Attrs value. */ -Expr makeAttrs(const ATermMap & attrs); - -/* Perform a set of substitutions on an expression. */ -Expr substitute(const ATermMap & subs, Expr e); - -/* Create an expression representing a boolean. */ -Expr makeBool(bool b); - - -#endif /* !__FIXEXPR_H */ diff --git a/src/nix-instantiate/main.cc b/src/nix-instantiate/main.cc deleted file mode 100644 index aa6883ff84b8..000000000000 --- a/src/nix-instantiate/main.cc +++ /dev/null @@ -1,117 +0,0 @@ -#include -#include - -#include "globals.hh" -#include "normalise.hh" -#include "shared.hh" -#include "eval.hh" - - -#if 0 -static Path searchPath(const Paths & searchDirs, const Path & relPath) -{ - if (string(relPath, 0, 1) == "/") return relPath; - - for (Paths::const_iterator i = searchDirs.begin(); - i != searchDirs.end(); i++) - { - Path path = *i + "/" + relPath; - if (pathExists(path)) return path; - } - - throw Error( - format("path `%1%' not found in any of the search directories") - % relPath); -} -#endif - - -static Expr evalStdin(EvalState & state) -{ - startNest(nest, lvlTalkative, format("evaluating standard input")); - Expr e = ATreadFromFile(stdin); - if (!e) - throw Error(format("unable to read a term from stdin")); - return evalExpr(state, e); -} - - -static void printNixExpr(EvalState & state, Expr e) -{ - ATMatcher m; - ATermList es; - - if (atMatch(m, e) >> "Attrs" >> es) { - Expr a = queryAttr(e, "type"); - if (a && evalString(state, a) == "derivation") { - a = queryAttr(e, "drvPath"); - if (a) { - cout << format("%1%\n") % evalPath(state, a); - return; - } - } - } - - if (ATgetType(e) == AT_LIST) { - for (ATermIterator i((ATermList) e); i; ++i) - printNixExpr(state, evalExpr(state, *i)); - return; - } - - throw badTerm("top level does not evaluate to one or more Nix expressions", e); -} - - -void run(Strings args) -{ - EvalState state; - Strings files; - bool readStdin = false; - -#if 0 - state.searchDirs.push_back("."); - state.searchDirs.push_back(nixDataDir + "/nix"); -#endif - - for (Strings::iterator it = args.begin(); - it != args.end(); ) - { - string arg = *it++; - -#if 0 - if (arg == "--includedir" || arg == "-I") { - if (it == args.end()) - throw UsageError(format("argument required in `%1%'") % arg); - state.searchDirs.push_back(*it++); - } - else -#endif - if (arg == "--verbose" || arg == "-v") - verbosity = (Verbosity) ((int) verbosity + 1); - else if (arg == "-") - readStdin = true; - else if (arg[0] == '-') - throw UsageError(format("unknown flag `%1%`") % arg); - else - files.push_back(arg); - } - - openDB(); - - if (readStdin) { - Expr e = evalStdin(state); - printNixExpr(state, e); - } - - for (Strings::iterator it = files.begin(); - it != files.end(); it++) - { - Expr e = evalFile(state, absPath(*it)); - printNixExpr(state, e); - } - - printEvalStats(state); -} - - -string programId = "nix-instantiate"; diff --git a/src/nix-instantiate/nix.sdf b/src/nix-instantiate/nix.sdf deleted file mode 100644 index 615bdb974775..000000000000 --- a/src/nix-instantiate/nix.sdf +++ /dev/null @@ -1,209 +0,0 @@ -definition - -module Main -imports Fix - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Top level syntax. - -module Fix -imports Fix-Exprs Fix-Layout - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Expressions. - -module Fix-Exprs -imports Fix-Lexicals URI -exports - sorts Expr Formal Bind Binds BindSemi ExprList - context-free syntax - - Id -> Expr {cons("Var")} - - Int -> Expr {cons("Int")} - - Str -> Expr {cons("Str")} - - Uri -> Expr {cons("Uri")} - - Path -> Expr {cons("Path")} - - "(" Expr ")" -> Expr {bracket} - - Expr Expr -> Expr {cons("Call"), left} - - "{" {Formal ","}* "}" ":" Expr -> Expr {cons("Function")} - Id -> Formal {cons("NoDefFormal")} - Id "?" Expr -> Formal {cons("DefFormal")} - - "assert" Expr ";" Expr -> Expr {cons("Assert")} - - "rec" "{" Binds "}" -> Expr {cons("Rec")} - "let" "{" Binds "}" -> Expr {cons("LetRec")} - "{" Binds "}" -> Expr {cons("Attrs")} - - Id "=" Expr -> Bind {cons("Bind")} - {Bind ";"}* -> Binds - Bind ";" -> BindSemi - BindSemi* -> Binds - - "[" ExprList "]" -> Expr {cons("List")} - "" -> ExprList {cons("ExprNil")} - Expr ExprList -> ExprList {cons("ExprCons")} - - Expr "." Id -> Expr {cons("Select")} - - "if" Expr "then" Expr "else" Expr -> Expr {cons("If")} - - Expr "==" Expr -> Expr {cons("OpEq"), non-assoc} - Expr "!=" Expr -> Expr {cons("OpNEq"), non-assoc} - - "!" Expr -> Expr {cons("OpNot")} - Expr "&&" Expr -> Expr {cons("OpAnd"), right} - Expr "||" Expr -> Expr {cons("OpOr"), right} - Expr "->" Expr -> Expr {cons("OpImpl"), right} - - Bool -> Expr {cons("Bool")} - - context-free priorities - - Expr "." Id -> Expr - > Expr ExprList -> ExprList - > Expr Expr -> Expr - > "!" Expr -> Expr - > Expr "==" Expr -> Expr - > Expr "!=" Expr -> Expr - > Expr "&&" Expr -> Expr - > Expr "||" Expr -> Expr - > Expr "->" Expr -> Expr - > "assert" Expr ";" Expr -> Expr - > "{" {Formal ","}* "}" ":" Expr -> Expr - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Lexical syntax. - -module Fix-Lexicals -exports - sorts Id Int Str Path PathComp Bool - lexical syntax - [a-zA-Z\_][a-zA-Z0-9\_\']* -> Id - "rec" -> Id {reject} - "let" -> Id {reject} - "if" -> Id {reject} - "then" -> Id {reject} - "else" -> Id {reject} - "true" -> Id {reject} - "false" -> Id {reject} - "assert" -> Id {reject} - - [0-9]+ -> Int - - "\"" ~[\n\"]* "\"" -> Str - - PathComp ("/" PathComp)+ -> Path - [a-zA-Z0-9\.\_\-\+]+ -> PathComp - - "true" -> Bool - "false" -> Bool - - lexical restrictions - Id -/- [a-zA-Z0-9\_\'] - Int -/- [0-9] - Path -/- [a-zA-Z0-9\.\_\-\+\/] - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% URIs (RFC 2396, appendix A). - -module URI -exports - sorts Uri Uhierpart Uopaquepart Uuricnoslash Unetpath Uabspath - Urelpath Urelsegment Uscheme Uauthority Uregname Userver - Uuserinfo Uhostport Uhost Uhostname Udomainlabel Utoplabel - UIPv4address Uport Upath Upathsegments Usegment Uparam - Upchar Uquery Ufragment Uuric Ureserved Uunreserved Umark - Uescaped Uhex Ualphanum Ualpha Ulowalpha Uupalpha Udigit - lexical syntax - Uscheme ":" (Uhierpart | Uopaquepart) -> Uri - - (Unetpath | Uabspath) ("?" Uquery)? -> Uhierpart - Uuricnoslash Uuric* -> Uopaquepart - - Uunreserved | Uescaped | [\;\?\:\@\&\=\+\$\,] -> Uuricnoslash - - "//" Uauthority Uabspath? -> Unetpath - "/" Upathsegments -> Uabspath - "//" Uuric* -> Uabspath {reject} - Urelsegment Uabspath? -> Urelpath - - (Uunreserved | Uescaped | [\;\@\&\=\+\$\,])+ -> Urelsegment - - Ualpha (Ualpha | Udigit | [\+\-\.])* -> Uscheme - - Userver | Uregname -> Uauthority - - (Uunreserved | Uescaped | [\$\,\;\:\@\&\=\+])+ -> Uregname - - ((Uuserinfo "@") Uhostport) -> Userver - (Uunreserved | Uescaped | [\;\:\&\=\+\$\,])* -> Uuserinfo - - Uhost (":" Uport)? -> Uhostport - Uhostname | UIPv4address -> Uhost - (Udomainlabel ".")+ Utoplabel "."? -> Uhostname - Ualphanum | Ualphanum (Ualphanum | "-")* Ualphanum -> Udomainlabel - Ualpha | Ualpha (Ualphanum | "-")* Ualphanum -> Utoplabel - Udigit+ "." Udigit+ "." Udigit+ "." Udigit+ -> UIPv4address - Udigit* -> Uport - - Uabspath | Uopaquepart -> Upath - Usegment ("/" Usegment)* -> Upathsegments - Upchar* (";" Uparam)* -> Usegment - Upchar* -> Uparam - Uunreserved | Uescaped | [\:\@\&\=\+\$\,] -> Upchar - - Uuric* -> Uquery - - Uuric* -> Ufragment - - Ureserved | Uunreserved | Uescaped -> Uuric - [\;\/\?\:\@\&\=\+\$\,] -> Ureserved - Ualphanum | Umark -> Uunreserved - [\-\_\.\!\~\*\'\(\)] -> Umark - - "%" Uhex Uhex -> Uescaped - Udigit | [A-Fa-f] -> Uhex - - Ualpha | Udigit -> Ualphanum - Ulowalpha | Uupalpha -> Ualpha - - [a-z] -> Ulowalpha - [A-Z] -> Uupalpha - [0-9] -> Udigit - - lexical restrictions - Uri -/- [a-zA-Z0-9\-\_\.\!\~\*\'\(\)] - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Layout. - -module Fix-Layout -exports - sorts HashComment Asterisk Comment EOF - lexical syntax - [\ \t\n] -> LAYOUT - HashComment -> LAYOUT - Comment -> LAYOUT - "#" ~[\n]* ([\n] | EOF) -> HashComment - "//" ~[\n]* ([\n] | EOF) -> HashComment - "/*" ( ~[\*] | Asterisk )* "*/" -> Comment - [\*] -> Asterisk - "" -> EOF - lexical restrictions - Asterisk -/- [\/] - EOF -/- ~[] - context-free restrictions - LAYOUT? -/- [\ \t\n] | [\#] diff --git a/src/nix-instantiate/nixexpr.cc b/src/nix-instantiate/nixexpr.cc deleted file mode 100644 index 816b39dc1ae3..000000000000 --- a/src/nix-instantiate/nixexpr.cc +++ /dev/null @@ -1,215 +0,0 @@ -#include "nixexpr.hh" -#include "storeexpr.hh" - - -ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct) -{ - table = ATtableCreate(initialSize, maxLoadPct); - if (!table) throw Error("cannot create ATerm table"); -} - - -ATermMap::ATermMap(const ATermMap & map) - : table(0) -{ - ATermList keys = map.keys(); - - /* !!! adjust allocation for load pct */ - table = ATtableCreate(ATgetLength(keys), map.maxLoadPct); - if (!table) throw Error("cannot create ATerm table"); - - for (ATermIterator i(keys); i; ++i) - set(*i, map.get(*i)); -} - - -ATermMap::~ATermMap() -{ - if (table) ATtableDestroy(table); -} - - -void ATermMap::set(ATerm key, ATerm value) -{ - return ATtablePut(table, key, value); -} - - -void ATermMap::set(const string & key, ATerm value) -{ - set(string2ATerm(key), value); -} - - -ATerm ATermMap::get(ATerm key) const -{ - return ATtableGet(table, key); -} - - -ATerm ATermMap::get(const string & key) const -{ - return get(string2ATerm(key)); -} - - -void ATermMap::remove(ATerm key) -{ - ATtableRemove(table, key); -} - - -void ATermMap::remove(const string & key) -{ - remove(string2ATerm(key)); -} - - -ATermList ATermMap::keys() const -{ - ATermList keys = ATtableKeys(table); - if (!keys) throw Error("cannot query aterm map keys"); - return keys; -} - - -ATerm string2ATerm(const string & s) -{ - return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue)); -} - - -string aterm2String(ATerm t) -{ - return ATgetName(ATgetAFun(t)); -} - - -ATerm bottomupRewrite(TermFun & f, ATerm e) -{ - if (ATgetType(e) == AT_APPL) { - AFun fun = ATgetAFun(e); - int arity = ATgetArity(fun); - ATermList args = ATempty; - - for (int i = arity - 1; i >= 0; i--) - args = ATinsert(args, bottomupRewrite(f, ATgetArgument(e, i))); - - e = (ATerm) ATmakeApplList(fun, args); - } - - else if (ATgetType(e) == AT_LIST) { - ATermList in = (ATermList) e; - ATermList out = ATempty; - - for (ATermIterator i(in); i; ++i) - out = ATinsert(out, bottomupRewrite(f, *i)); - - e = (ATerm) ATreverse(out); - } - - return f(e); -} - - -void queryAllAttrs(Expr e, ATermMap & attrs) -{ - ATMatcher m; - ATermList bnds; - if (!(atMatch(m, e) >> "Attrs" >> bnds)) - throw badTerm("expected attribute set", e); - - for (ATermIterator i(bnds); i; ++i) { - string s; - Expr e; - if (!(atMatch(m, *i) >> "Bind" >> s >> e)) - abort(); /* can't happen */ - attrs.set(s, e); - } -} - - -Expr queryAttr(Expr e, const string & name) -{ - ATermMap attrs; - queryAllAttrs(e, attrs); - return attrs.get(name); -} - - -Expr makeAttrs(const ATermMap & attrs) -{ - ATermList bnds = ATempty; - for (ATermIterator i(attrs.keys()); i; ++i) - bnds = ATinsert(bnds, - ATmake("Bind(, )", *i, attrs.get(*i))); - return ATmake("Attrs()", ATreverse(bnds)); -} - - -Expr substitute(const ATermMap & subs, Expr e) -{ - ATMatcher m; - string s; - - if (atMatch(m, e) >> "Var" >> s) { - Expr sub = subs.get(s); - return sub ? sub : e; - } - - /* In case of a function, filter out all variables bound by this - function. */ - ATermList formals; - ATerm body; - if (atMatch(m, e) >> "Function" >> formals >> body) { - ATermMap subs2(subs); - for (ATermIterator i(formals); i; ++i) { - Expr def; - if (!(atMatch(m, *i) >> "NoDefFormal" >> s) && - !(atMatch(m, *i) >> "DefFormal" >> s >> def)) - abort(); - subs2.remove(s); - } - return ATmake("Function(, )", formals, - substitute(subs2, body)); - } - - /* Idem for a mutually recursive attribute set. */ - ATermList bindings; - if (atMatch(m, e) >> "Rec" >> bindings) { - ATermMap subs2(subs); - for (ATermIterator i(bindings); i; ++i) { - Expr e; - if (!(atMatch(m, *i) >> "Bind" >> s >> e)) - abort(); /* can't happen */ - subs2.remove(s); - } - return ATmake("Rec()", substitute(subs2, (ATerm) bindings)); - } - - if (ATgetType(e) == AT_APPL) { - AFun fun = ATgetAFun(e); - int arity = ATgetArity(fun); - ATermList args = ATempty; - - for (int i = arity - 1; i >= 0; i--) - args = ATinsert(args, substitute(subs, ATgetArgument(e, i))); - - return (ATerm) ATmakeApplList(fun, args); - } - - if (ATgetType(e) == AT_LIST) { - ATermList out = ATempty; - for (ATermIterator i((ATermList) e); i; ++i) - out = ATinsert(out, substitute(subs, *i)); - return (ATerm) ATreverse(out); - } - - return e; -} - - -Expr makeBool(bool b) -{ - return b ? ATmake("Bool(True)") : ATmake("Bool(False)"); -} diff --git a/src/nix-instantiate/nixexpr.hh b/src/nix-instantiate/nixexpr.hh deleted file mode 100644 index 011c2900e12a..000000000000 --- a/src/nix-instantiate/nixexpr.hh +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __NIXEXPR_H -#define __NIXEXPR_H - -#include - -#include - -#include "util.hh" - - -/* Nix expressions are represented as ATerms. The maximal sharing - property of the ATerm library allows us to implement caching of - normals forms efficiently. */ -typedef ATerm Expr; - - -/* Mappings from ATerms to ATerms. This is just a wrapper around - ATerm tables. */ -class ATermMap -{ -private: - unsigned int maxLoadPct; - ATermTable table; - -public: - ATermMap(unsigned int initialSize = 16, unsigned int maxLoadPct = 75); - ATermMap(const ATermMap & map); - ~ATermMap(); - - void set(ATerm key, ATerm value); - void set(const string & key, ATerm value); - - ATerm get(ATerm key) const; - ATerm get(const string & key) const; - - void remove(ATerm key); - void remove(const string & key); - - ATermList keys() const; -}; - - -/* Convert a string to an ATerm (i.e., a quoted nullary function - applicaton). */ -ATerm string2ATerm(const string & s); -string aterm2String(ATerm t); - -/* Generic bottomup traversal over ATerms. The traversal first - recursively descends into subterms, and then applies the given term - function to the resulting term. */ -struct TermFun -{ - virtual ATerm operator () (ATerm e) = 0; -}; -ATerm bottomupRewrite(TermFun & f, ATerm e); - -/* Query all attributes in an attribute set expression. The - expression must be in normal form. */ -void queryAllAttrs(Expr e, ATermMap & attrs); - -/* Query a specific attribute from an attribute set expression. The - expression must be in normal form. */ -Expr queryAttr(Expr e, const string & name); - -/* Create an attribute set expression from an Attrs value. */ -Expr makeAttrs(const ATermMap & attrs); - -/* Perform a set of substitutions on an expression. */ -Expr substitute(const ATermMap & subs, Expr e); - -/* Create an expression representing a boolean. */ -Expr makeBool(bool b); - - -#endif /* !__NIXEXPR_H */ diff --git a/src/nix-instantiate/parser.cc b/src/nix-instantiate/parser.cc deleted file mode 100644 index b2c74af33e77..000000000000 --- a/src/nix-instantiate/parser.cc +++ /dev/null @@ -1,164 +0,0 @@ -#include - -#include -#include -#include -#include - -extern "C" { -#include -#include -} - -#include "aterm.hh" -#include "parser.hh" -#include "shared.hh" -#include "parse-table.h" - - -/* Cleanup cleans up an imploded parse tree into an actual abstract - syntax tree that we can evaluate. It removes quotes around - strings, converts integer literals into actual integers, and - absolutises paths relative to the directory containing the input - file. */ -struct Cleanup : TermFun -{ - string basePath; - - virtual ATerm operator () (ATerm e) - { - ATMatcher m; - string s; - - if (atMatch(m, e) >> "Str" >> s) { - return ATmake("Str()", - string(s, 1, s.size() - 2).c_str()); - } - - if (atMatch(m, e) >> "Path" >> s) { - if (s[0] != '/') - s = basePath + "/" + s; - return ATmake("Path()", canonPath(s).c_str()); - } - - if (atMatch(m, e) >> "Int" >> s) { - istringstream s2(s); - int n; - s2 >> n; - return ATmake("Int()", n); - } - - if (atMatch(m, e) >> "Bool" >> "true") - return ATmake("Bool(True)"); - - if (atMatch(m, e) >> "Bool" >> "false") - return ATmake("Bool(False)"); - - if (atMatch(m, e) >> "ExprNil") - return (ATerm) ATempty; - - ATerm e1; - ATermList e2; - if (atMatch(m, e) >> "ExprCons" >> e1 >> e2) - return (ATerm) ATinsert(e2, e1); - - return e; - } -}; - - -Expr parseExprFromFile(Path path) -{ -#if 0 - /* Perhaps this is already an imploded parse tree? */ - Expr e = ATreadFromNamedFile(path.c_str()); - if (e) return e; -#endif - - /* If `path' refers to a directory, append `/default.nix'. */ - struct stat st; - if (stat(path.c_str(), &st)) - throw SysError(format("getting status of `%1%'") % path); - if (S_ISDIR(st.st_mode)) - path = canonPath(path + "/default.nix"); - - /* Initialise the SDF libraries. */ - static bool initialised = false; - static ATerm parseTable = 0; - static language lang = 0; - - if (!initialised) { - PT_initMEPTApi(); - PT_initAsFix2Api(); - SGinitParser(ATfalse); - - ATprotect(&parseTable); - parseTable = ATreadFromBinaryString( - (char *) nixParseTable, sizeof nixParseTable); - if (!parseTable) - throw Error(format("cannot construct parse table term")); - - ATprotect(&lang); - lang = ATmake("Nix"); - if (!SGopenLanguageFromTerm( - (char *) programId.c_str(), lang, parseTable)) - throw Error(format("cannot open language")); - - SG_STARTSYMBOL_ON(); - SG_OUTPUT_ON(); - SG_ASFIX2ME_ON(); - SG_AMBIGUITY_ERROR_ON(); - SG_FILTER_OFF(); - - initialised = true; - } - - /* Read the input file. We can't use SGparseFile() because it's - broken, so we read the input ourselves and call - SGparseString(). */ - AutoCloseFD fd = open(path.c_str(), O_RDONLY); - if (fd == -1) throw SysError(format("opening `%1%'") % path); - - if (fstat(fd, &st) == -1) - throw SysError(format("statting `%1%'") % path); - - char text[st.st_size + 1]; - readFull(fd, (unsigned char *) text, st.st_size); - text[st.st_size] = 0; - - /* Parse it. */ - ATerm result = SGparseString(lang, "Expr", text); - if (!result) - throw SysError(format("parse failed in `%1%'") % path); - if (SGisParseError(result)) - throw Error(format("parse error in `%1%': %2%") - % path % result); - - /* Implode it. */ - PT_ParseTree tree = PT_makeParseTreeFromTerm(result); - if (!tree) - throw Error(format("cannot create parse tree")); - - ATerm imploded = PT_implodeParseTree(tree, - ATtrue, - ATtrue, - ATtrue, - ATtrue, - ATtrue, - ATtrue, - ATfalse, - ATtrue, - ATtrue, - ATtrue, - ATfalse); - if (!imploded) - throw Error(format("cannot implode parse tree")); - - printMsg(lvlVomit, format("imploded parse tree of `%1%': %2%") - % path % imploded); - - /* Finally, clean it up. */ - Cleanup cleanup; - cleanup.basePath = dirOf(path); - return bottomupRewrite(cleanup, imploded); -} diff --git a/src/nix-instantiate/parser.hh b/src/nix-instantiate/parser.hh deleted file mode 100644 index 5983ec5629e4..000000000000 --- a/src/nix-instantiate/parser.hh +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __PARSER_H -#define __PARSER_H - -#include "nixexpr.hh" - - -Expr parseExprFromFile(Path path); - - -#endif /* !__PARSER_H */ diff --git a/src/nix-instantiate/primops.cc b/src/nix-instantiate/primops.cc deleted file mode 100644 index 097933115342..000000000000 --- a/src/nix-instantiate/primops.cc +++ /dev/null @@ -1,246 +0,0 @@ -#include "primops.hh" -#include "normalise.hh" -#include "globals.hh" - - -Expr primImport(EvalState & state, Expr arg) -{ - ATMatcher m; - string path; - if (!(atMatch(m, arg) >> "Path" >> path)) - throw badTerm("path expected", arg); - return evalFile(state, path); -} - - -static PathSet storeExprRootsCached(EvalState & state, const Path & nePath) -{ - DrvPaths::iterator i = state.drvPaths.find(nePath); - if (i != state.drvPaths.end()) - return i->second; - else { - PathSet paths = storeExprRoots(nePath); - state.drvPaths[nePath] = paths; - return paths; - } -} - - -static Hash hashDerivation(EvalState & state, StoreExpr ne) -{ - if (ne.type == StoreExpr::neDerivation) { - PathSet inputs2; - for (PathSet::iterator i = ne.derivation.inputs.begin(); - i != ne.derivation.inputs.end(); i++) - { - DrvHashes::iterator j = state.drvHashes.find(*i); - if (j == state.drvHashes.end()) - throw Error(format("don't know expression `%1%'") % (string) *i); - inputs2.insert(j->second); - } - ne.derivation.inputs = inputs2; - } - return hashTerm(unparseStoreExpr(ne)); -} - - -static Path copyAtom(EvalState & state, const Path & srcPath) -{ - /* !!! should be cached */ - Path dstPath(addToStore(srcPath)); - - ClosureElem elem; - StoreExpr ne; - ne.type = StoreExpr::neClosure; - ne.closure.roots.insert(dstPath); - ne.closure.elems[dstPath] = elem; - - Hash drvHash = hashDerivation(state, ne); - Path drvPath = writeTerm(unparseStoreExpr(ne), ""); - state.drvHashes[drvPath] = drvHash; - - printMsg(lvlChatty, format("copied `%1%' -> closure `%2%'") - % srcPath % drvPath); - return drvPath; -} - - -static string addInput(EvalState & state, - Path & nePath, StoreExpr & ne) -{ - PathSet paths = storeExprRootsCached(state, nePath); - if (paths.size() != 1) abort(); - Path path = *(paths.begin()); - ne.derivation.inputs.insert(nePath); - return path; -} - - -static string processBinding(EvalState & state, Expr e, StoreExpr & ne) -{ - e = evalExpr(state, e); - - ATMatcher m; - string s; - ATermList es; - - if (atMatch(m, e) >> "Str" >> s) return s; - if (atMatch(m, e) >> "Uri" >> s) return s; - if (atMatch(m, e) >> "Bool" >> "True") return "1"; - if (atMatch(m, e) >> "Bool" >> "False") return ""; - - if (atMatch(m, e) >> "Attrs" >> es) { - Expr a = queryAttr(e, "type"); - if (a && evalString(state, a) == "derivation") { - a = queryAttr(e, "drvPath"); - if (a) { - Path drvPath = evalPath(state, a); - return addInput(state, drvPath, ne); - } - } - } - - if (atMatch(m, e) >> "Path" >> s) { - Path drvPath = copyAtom(state, s); - return addInput(state, drvPath, ne); - } - - if (atMatch(m, e) >> "List" >> es) { - string s; - bool first = true; - for (ATermIterator i(es); i; ++i) { - startNest(nest, lvlVomit, format("processing list element")); - if (!first) s = s + " "; else first = false; - s += processBinding(state, evalExpr(state, *i), ne); - } - return s; - } - - if (atMatch(m, e) >> "Null") return ""; - - throw badTerm("invalid derivation binding", e); -} - - -Expr primDerivation(EvalState & state, Expr args) -{ - startNest(nest, lvlVomit, "evaluating derivation"); - - ATermMap attrs; - args = evalExpr(state, args); - queryAllAttrs(args, attrs); - - /* Build the derivation expression by processing the attributes. */ - StoreExpr ne; - ne.type = StoreExpr::neDerivation; - - string drvName; - Path outPath; - Hash outHash; - bool outHashGiven = false; - - for (ATermIterator i(attrs.keys()); i; ++i) { - string key = aterm2String(*i); - Expr value = attrs.get(key); - startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); - - /* The `args' attribute is special: it supplies the - command-line arguments to the builder. */ - if (key == "args") { - throw Error("args not implemented"); -#if 0 - ATermList args; - if (!(ATmatch(value, "[]", &args)) - throw badTerm("list expected", value); - while (!ATisEmpty(args)) { - Expr arg = evalExpr(state, ATgetFirst(args)); - ne.derivation.args.push_back(processBinding(state, arg, ne)); - args = ATgetNext(args); - } -#endif - } - - /* All other attributes are passed to the builder through the - environment. */ - else { - string s = processBinding(state, value, ne); - ne.derivation.env[key] = s; - if (key == "builder") ne.derivation.builder = s; - else if (key == "system") ne.derivation.platform = s; - else if (key == "name") drvName = s; - else if (key == "outPath") outPath = s; - else if (key == "id") { - outHash = parseHash(s); - outHashGiven = true; - } - } - } - - /* Do we have all required attributes? */ - if (ne.derivation.builder == "") - throw badTerm("required attribute `builder' missing", args); - if (ne.derivation.platform == "") - throw badTerm("required attribute `system' missing", args); - if (drvName == "") - throw badTerm("required attribute `name' missing", args); - - /* Determine the output path. */ - if (!outHashGiven) outHash = hashDerivation(state, ne); - if (outPath == "") - /* Hash the Nix expression with no outputs to produce a - unique but deterministic path name for this derivation. */ - outPath = canonPath(nixStore + "/" + - ((string) outHash).c_str() + "-" + drvName); - ne.derivation.env["out"] = outPath; - ne.derivation.outputs.insert(outPath); - - /* Write the resulting term into the Nix store directory. */ - Hash drvHash = outHashGiven - ? hashString((string) outHash + outPath) - : hashDerivation(state, ne); - Path drvPath = writeTerm(unparseStoreExpr(ne), "-d-" + drvName); - state.drvHashes[drvPath] = drvHash; - - printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'") - % drvName % drvPath); - - attrs.set("outPath", ATmake("Path()", outPath.c_str())); - attrs.set("drvPath", ATmake("Path()", drvPath.c_str())); - attrs.set("type", ATmake("Str(\"derivation\")")); - - return makeAttrs(attrs); -} - - -Expr primBaseNameOf(EvalState & state, Expr arg) -{ - string s = evalString(state, arg); - return ATmake("Str()", baseNameOf(s).c_str()); -} - - -Expr primToString(EvalState & state, Expr arg) -{ - arg = evalExpr(state, arg); - ATMatcher m; - string s; - if (atMatch(m, arg) >> "Str" >> s || - atMatch(m, arg) >> "Path" >> s || - atMatch(m, arg) >> "Uri" >> s) - return ATmake("Str()", s.c_str()); - else throw badTerm("cannot coerce to string", arg); -} - - -Expr primNull(EvalState & state) -{ - return ATmake("Null"); -} - - -Expr primIsNull(EvalState & state, Expr arg) -{ - arg = evalExpr(state, arg); - ATMatcher m; - return makeBool(atMatch(m, arg) >> "Null"); -} diff --git a/src/nix-instantiate/primops.hh b/src/nix-instantiate/primops.hh deleted file mode 100644 index 76d587afdb1e..000000000000 --- a/src/nix-instantiate/primops.hh +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __PRIMOPS_H -#define __PRIMOPS_H - -#include "eval.hh" - - -/* Load and evaluate an expression from path specified by the - argument. */ -Expr primImport(EvalState & state, Expr arg); - -/* Construct (as a unobservable) side effect) a Nix derivation - expression that performs the derivation described by the argument - set. Returns the original set extended with the following - attributes: `outPath' containing the primary output path of the - derivation; `drvPath' containing the path of the Nix expression; - and `type' set to `derivation' to indicate that this is a - derivation. */ -Expr primDerivation(EvalState & state, Expr args); - -/* Return the base name of the given string, i.e., everything - following the last slash. */ -Expr primBaseNameOf(EvalState & state, Expr arg); - -/* Convert the argument (which can be a path or a uri) to a string. */ -Expr primToString(EvalState & state, Expr arg); - -/* Return the null value. */ -Expr primNull(EvalState & state); - -/* Determine whether the argument is the null value. */ -Expr primIsNull(EvalState & state, Expr arg); - - -#endif /* !__PRIMOPS_H */ -- cgit 1.4.1