diff --git a/src/Makefile.am b/src/Makefile.am index 563738217..089f53220 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,8 @@ SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \ libexpr nix-instantiate nix-env log2xml +EXTRA_DIST = aterm-helper.pl + SETUID_PROGS = nix-store nix-instantiate nix-env install-exec-hook: if SETUID_HACK diff --git a/src/libexpr/aterm-helper.pl b/src/aterm-helper.pl similarity index 68% rename from src/libexpr/aterm-helper.pl rename to src/aterm-helper.pl index 9a1a931a9..917b50852 100755 --- a/src/libexpr/aterm-helper.pl +++ b/src/aterm-helper.pl @@ -1,9 +1,41 @@ #! /usr/bin/perl -w +# This program generates C/C++ code for efficiently manipulating +# ATerms. It generates functions to build and match ATerms according +# to a set of constructor definitions defined in a file read from +# standard input. A constructor is defined by a line with the +# following format: +# +# SYM | ARGS | TYPE | FUN? +# +# where SYM is the name of the constructor, ARGS is a +# whitespace-separated list of argument types, TYPE is the type of the +# resulting ATerm (which should be `ATerm' or a type synonym for +# `ATerm'), and the optional FUN is used to construct the names of the +# build and match functions (it defaults to SYM; overriding it is +# useful if there are overloaded constructors, e.g., with different +# arities). Note that SYM may be empty. +# +# A line of the form +# +# VAR = EXPR +# +# causes a ATerm variable to be generated that is initialised to the +# value EXPR. +# +# Finally, a line of the form +# +# init NAME +# +# causes the initialisation function to be called `NAME'. This +# function must be called before any of the build/match functions or +# the generated variables are used. + die if scalar @ARGV != 2; my $syms = ""; my $init = ""; +my $initFun = "init"; open HEADER, ">$ARGV[0]"; open IMPL, ">$ARGV[1]"; @@ -11,7 +43,7 @@ open IMPL, ">$ARGV[1]"; while () { next if (/^\s*$/); - if (/^\s*(\w+)\s*\|([^\|]*)\|\s*(\w+)\s*\|\s*(\w+)?/) { + if (/^\s*(\w*)\s*\|([^\|]*)\|\s*(\w+)\s*\|\s*(\w+)?/) { my $const = $1; my @types = split ' ', $2; my $result = $3; @@ -30,6 +62,8 @@ while () { # $type = "const char *"; $type = "ATerm"; $args .= "e$n"; + # !!! in the matcher, we should check that the + # argument is a string (i.e., a nullary application). } elsif ($type eq "int") { $args .= "(ATerm) ATmakeInt(e$n)"; } elsif ($type eq "ATermList" || $type eq "ATermBlob") { @@ -42,6 +76,7 @@ while () { $formals2 .= ", "; $formals2 .= "$type & e$n"; my $m = $n - 1; + # !!! more checks here if ($type eq "int") { $unpack .= " e$n = ATgetInt((ATermInt) ATgetArgument(e, $m));\n"; } elsif ($type eq "ATermList") { @@ -84,12 +119,16 @@ while () { $init .= " $name = $value;\n"; } + elsif (/^\s*init\s+(\w+)\s*$/) { + $initFun = $1; + } + else { die "bad line: `$_'"; } } -print HEADER "void initSyms();\n\n"; +print HEADER "void $initFun();\n\n"; print HEADER "static inline ATerm string2ATerm(const char * s) {\n"; print HEADER " return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s, 0, ATtrue));\n"; @@ -100,7 +139,7 @@ print HEADER " return (const char *) ATgetName(ATgetAFun(t));\n"; print HEADER "}\n\n"; print IMPL "\n"; -print IMPL "void initSyms() {\n"; +print IMPL "void $initFun() {\n"; print IMPL "$init"; print IMPL "}\n"; diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am index a52b4710d..d7de30855 100644 --- a/src/libexpr/Makefile.am +++ b/src/libexpr/Makefile.am @@ -3,10 +3,9 @@ noinst_LIBRARIES = libexpr.a libexpr_a_SOURCES = nixexpr.cc nixexpr.hh parser.cc parser.hh \ eval.cc eval.hh primops.cc \ lexer-tab.c lexer-tab.h parser-tab.c parser-tab.h \ - constructors.hh + nixexpr-ast.hh -EXTRA_DIST = lexer.l parser.y constructors.def constructors.cc \ - aterm-helper.pl +EXTRA_DIST = lexer.l parser.y nixexpr-ast.def nixexpr-ast.cc AM_CXXFLAGS = \ -I.. ${bdb_include} ${aterm_include} -I../libutil -I../libstore @@ -27,10 +26,10 @@ lexer-tab.c lexer-tab.h: lexer.l # ATerm helper function generation. -constructors.cc constructors.hh: aterm-helper.pl constructors.def - $(perl) aterm-helper.pl constructors.hh constructors.cc < constructors.def +nixexpr-ast.cc nixexpr-ast.hh: ../aterm-helper.pl nixexpr-ast.def + $(perl) ../aterm-helper.pl nixexpr-ast.hh nixexpr-ast.cc < nixexpr-ast.def -nixexpr.hh: constructors.hh +nixexpr.hh: nixexpr-ast.hh CLEANFILES = diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 88362333c..cef346002 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1,6 +1,6 @@ #include "eval.hh" #include "parser.hh" -#include "constructors.hh" +#include "nixexpr-ast.hh" EvalState::EvalState() @@ -10,7 +10,7 @@ EvalState::EvalState() nrEvaluated = nrCached = 0; - initSyms(); + initNixExprHelpers(); addPrimOps(); } diff --git a/src/libexpr/constructors.def b/src/libexpr/nixexpr-ast.def similarity index 98% rename from src/libexpr/constructors.def rename to src/libexpr/nixexpr-ast.def index 497cd33c3..19601847c 100644 --- a/src/libexpr/constructors.def +++ b/src/libexpr/nixexpr-ast.def @@ -1,3 +1,5 @@ +init initNixExprHelpers + Pos | string int int | Pos | NoPos | | Pos | diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index cbfb5576b..56e053fd7 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -2,8 +2,8 @@ #include "storeexpr.hh" -#include "constructors.hh" -#include "constructors.cc" +#include "nixexpr-ast.hh" +#include "nixexpr-ast.cc" ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct) diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc index a0a6c01df..8a199c002 100644 --- a/src/libexpr/parser.cc +++ b/src/libexpr/parser.cc @@ -7,7 +7,7 @@ #include "aterm.hh" #include "parser.hh" -#include "constructors.hh" +#include "nixexpr-ast.hh" struct ParseData diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 2864b1600..8573697b6 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -18,7 +18,7 @@ typedef ATerm Expr; typedef ATerm Pos; -#include "constructors.hh" +#include "nixexpr-ast.hh" void setParseResult(void * data, ATerm t); void parseError(void * data, char * error, int line, int column); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index e230d35ce..830a2c095 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1,7 +1,7 @@ #include "normalise.hh" #include "eval.hh" #include "globals.hh" -#include "constructors.hh" +#include "nixexpr-ast.hh" /* Load and evaluate an expression from path specified by the diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 73388c96e..f608afd84 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -55,6 +55,9 @@ void checkStoreNotSymlink(Path path) } +void initStoreExprHelpers(); + + /* Initialize and reorder arguments, then call the actual argument processor. */ static void initAndRun(int argc, char * * argv) @@ -101,6 +104,9 @@ static void initAndRun(int argc, char * * argv) string lt = getEnv("NIX_LOG_TYPE"); if (lt != "") setLogType(lt); + /* ATerm stuff. !!! find a better place to put this */ + initStoreExprHelpers(); + /* Put the arguments in a vector. */ Strings args, remaining; while (argc--) args.push_back(*argv++); diff --git a/src/libstore/Makefile.am b/src/libstore/Makefile.am index 31735e893..7e0f32d1f 100644 --- a/src/libstore/Makefile.am +++ b/src/libstore/Makefile.am @@ -5,7 +5,14 @@ libstore_a_SOURCES = \ normalise.cc misc.cc normalise.hh \ globals.cc globals.hh db.cc db.hh \ references.cc references.hh pathlocks.cc pathlocks.hh \ - gc.cc gc.hh + gc.cc gc.hh storeexpr-ast.hh + +EXTRA_DIST = storeexpr-ast.def storeexpr-ast.cc AM_CXXFLAGS = -Wall \ -I.. ${bdb_include} ${aterm_include} -I../libutil + +storeexpr-ast.cc storeexpr-ast.hh: ../aterm-helper.pl storeexpr-ast.def + $(perl) ../aterm-helper.pl storeexpr-ast.hh storeexpr-ast.cc < storeexpr-ast.def + +storeexpr.cc: storeexpr-ast.hh \ No newline at end of file diff --git a/src/libstore/storeexpr-ast.def b/src/libstore/storeexpr-ast.def new file mode 100644 index 000000000..9d2433dbe --- /dev/null +++ b/src/libstore/storeexpr-ast.def @@ -0,0 +1,7 @@ +init initStoreExprHelpers + +Closure | ATermList ATermList | ATerm | +Derive | ATermList ATermList string string ATermList ATermList | ATerm | + +| string string | ATerm | EnvBinding | +| string ATermList | ATerm | ClosureElem | diff --git a/src/libstore/storeexpr.cc b/src/libstore/storeexpr.cc index 29f271de8..0b92be0e7 100644 --- a/src/libstore/storeexpr.cc +++ b/src/libstore/storeexpr.cc @@ -2,6 +2,9 @@ #include "globals.hh" #include "store.hh" +#include "storeexpr-ast.hh" +#include "storeexpr-ast.cc" + Hash hashTerm(ATerm t) { @@ -29,10 +32,11 @@ Path writeTerm(ATerm t, const string & suffix) static void parsePaths(ATermList paths, PathSet & out) { - ATMatcher m; for (ATermIterator i(paths); i; ++i) { - string s; - if (!(atMatch(m, *i) >> s)) + if (ATgetType(*i) != AT_APPL) + throw badTerm("not a path", *i); + string s = aterm2String(*i); + if (s.size() == 0 || s[0] != '/') throw badTerm("not a path", *i); out.insert(s); } @@ -69,21 +73,20 @@ static void checkClosure(const Closure & closure) static bool parseClosure(ATerm t, Closure & closure) { ATermList roots, elems; - ATMatcher m; - if (!(atMatch(m, t) >> "Closure" >> roots >> elems)) + if (!matchClosure(t, roots, elems)) return false; parsePaths(roots, closure.roots); for (ATermIterator i(elems); i; ++i) { - string path; + ATerm path; ATermList refs; - if (!(atMatch(m, *i) >> "" >> path >> refs)) + if (!matchClosureElem(*i, path, refs)) throw badTerm("not a closure element", *i); ClosureElem elem; parsePaths(refs, elem.refs); - closure.elems[path] = elem; + closure.elems[aterm2String(path)] = elem; } checkClosure(closure); @@ -93,32 +96,29 @@ static bool parseClosure(ATerm t, Closure & closure) static bool parseDerivation(ATerm t, Derivation & derivation) { - ATMatcher m; ATermList outs, ins, args, bnds; - string builder, platform; + ATerm builder, platform; - if (!(atMatch(m, t) >> "Derive" >> outs >> ins >> platform - >> builder >> args >> bnds)) + if (!matchDerive(t, outs, ins, platform, builder, args, bnds)) return false; parsePaths(outs, derivation.outputs); parsePaths(ins, derivation.inputs); - derivation.builder = builder; - derivation.platform = platform; + derivation.builder = aterm2String(builder); + derivation.platform = aterm2String(platform); for (ATermIterator i(args); i; ++i) { - string s; - if (!(atMatch(m, *i) >> s)) + if (ATgetType(*i) != AT_APPL) throw badTerm("string expected", *i); - derivation.args.push_back(s); + derivation.args.push_back(aterm2String(*i)); } for (ATermIterator i(bnds); i; ++i) { - string s1, s2; - if (!(atMatch(m, *i) >> "" >> s1 >> s2)) + ATerm s1, s2; + if (!matchEnvBinding(*i, s1, s2)) throw badTerm("tuple of strings expected", *i); - derivation.env[s1] = s2; + derivation.env[aterm2String(s1)] = aterm2String(s2); } return true; @@ -142,7 +142,7 @@ static ATermList unparsePaths(const PathSet & paths) ATermList l = ATempty; for (PathSet::const_iterator i = paths.begin(); i != paths.end(); i++) - l = ATinsert(l, ATmake("", i->c_str())); + l = ATinsert(l, string2ATerm(i->c_str())); return ATreverse(l); } @@ -155,11 +155,11 @@ static ATerm unparseClosure(const Closure & closure) for (ClosureElems::const_iterator i = closure.elems.begin(); i != closure.elems.end(); i++) elems = ATinsert(elems, - ATmake("(, )", - i->first.c_str(), + makeClosureElem( + string2ATerm(i->first.c_str()), unparsePaths(i->second.refs))); - return ATmake("Closure(, )", roots, elems); + return makeClosure(roots, elems); } @@ -168,20 +168,21 @@ static ATerm unparseDerivation(const Derivation & derivation) ATermList args = ATempty; for (Strings::const_iterator i = derivation.args.begin(); i != derivation.args.end(); i++) - args = ATinsert(args, ATmake("", i->c_str())); + args = ATinsert(args, string2ATerm(i->c_str())); ATermList env = ATempty; for (StringPairs::const_iterator i = derivation.env.begin(); i != derivation.env.end(); i++) env = ATinsert(env, - ATmake("(, )", - i->first.c_str(), i->second.c_str())); + makeEnvBinding( + string2ATerm(i->first.c_str()), + string2ATerm(i->second.c_str()))); - return ATmake("Derive(, , , , , )", + return makeDerive( unparsePaths(derivation.outputs), unparsePaths(derivation.inputs), - derivation.platform.c_str(), - derivation.builder.c_str(), + string2ATerm(derivation.platform.c_str()), + string2ATerm(derivation.builder.c_str()), ATreverse(args), ATreverse(env)); } diff --git a/src/libutil/Makefile.am b/src/libutil/Makefile.am index bd19bfa83..a7ff1b6e0 100644 --- a/src/libutil/Makefile.am +++ b/src/libutil/Makefile.am @@ -4,10 +4,3 @@ libutil_a_SOURCES = util.cc util.hh hash.cc hash.hh \ archive.cc archive.hh md5.c md5.h aterm.cc aterm.hh AM_CXXFLAGS = -Wall -I.. ${aterm_include} - -check_PROGRAMS = test-aterm - -test_aterm_SOURCES = test-aterm.cc -test_aterm_LDADD = ./libutil.a ../boost/format/libformat.a \ - ${aterm_lib} - diff --git a/src/libutil/aterm.cc b/src/libutil/aterm.cc index fb734b3a0..77bf8dab4 100644 --- a/src/libutil/aterm.cc +++ b/src/libutil/aterm.cc @@ -16,95 +16,6 @@ ostream & operator << (ostream & stream, ATerm e) } -ATMatcher & atMatch(ATMatcher & pos, ATerm t) -{ - pos.t = t; - pos.pos = ATMatcher::funPos; - return pos; -} - - -static inline bool failed(const ATMatcher & pos) -{ - return pos.pos == ATMatcher::failPos; -} - - -static inline ATMatcher & fail(ATMatcher & pos) -{ - pos.pos = ATMatcher::failPos; - return pos; -} - - -ATMatcher & operator >> (ATMatcher & pos, ATerm & out) -{ - out = 0; - if (failed(pos)) return pos; - if (pos.pos == ATMatcher::funPos || - ATgetType(pos.t) != AT_APPL || - pos.pos >= (int) ATgetArity(ATgetAFun(pos.t))) - return fail(pos); - out = ATgetArgument(pos.t, pos.pos); - pos.pos++; - return pos; -} - - -ATMatcher & operator >> (ATMatcher & pos, string & out) -{ - out = ""; - if (pos.pos == ATMatcher::funPos) { - if (ATgetType(pos.t) != AT_APPL) return fail(pos); - out = ATgetName(ATgetAFun(pos.t)); - pos.pos = 0; - } else { - ATerm t; - pos = pos >> t; - if (failed(pos)) return pos; - if (ATgetType(t) != AT_APPL || - ATgetArity(ATgetAFun(t)) != 0) - return fail(pos); - out = ATgetName(ATgetAFun(t)); - } - return pos; -} - - -ATMatcher & operator >> (ATMatcher & pos, const string & s) -{ - string s2; - pos = pos >> s2; - if (failed(pos)) return pos; - if (s != s2) return fail(pos); - return pos; -} - - -ATMatcher & operator >> (ATMatcher & pos, int & n) -{ - n = 0; - ATerm t; - pos = pos >> t; - if (failed(pos)) return pos; - if (ATgetType(t) != AT_INT) return fail(pos); - n = ATgetInt((ATermInt) t); - return pos; -} - - -ATMatcher & operator >> (ATMatcher & pos, ATermList & out) -{ - out = 0; - ATerm t; - pos = pos >> t; - if (failed(pos)) return pos; - if (ATgetType(t) != AT_LIST) return fail(pos); - out = (ATermList) t; - return pos; -} - - Error badTerm(const format & f, ATerm t) { char * s = ATwriteToString(t); diff --git a/src/libutil/aterm.hh b/src/libutil/aterm.hh index 577b784be..883d20c63 100644 --- a/src/libutil/aterm.hh +++ b/src/libutil/aterm.hh @@ -36,48 +36,6 @@ public: }; -/* Type-safe matching. */ - -struct ATMatcher -{ - ATerm t; - int pos; - const static int failPos = -2; - const static int funPos = -1; - - ATMatcher() : t(0), pos(failPos) - { - } - - operator bool() const - { - return pos != failPos; - } -}; - -/* Initiate matching of a term. */ -ATMatcher & atMatch(ATMatcher & pos, ATerm t); - -/* Get the next argument of an application. */ -ATMatcher & operator >> (ATMatcher & pos, ATerm & out); - -/* Get the name of the function symbol of an application, or the next - argument of an application as a string. */ -ATMatcher & operator >> (ATMatcher & pos, string & out); - -/* Like the previous, but check that the string is equal to the given - string. */ -ATMatcher & operator >> (ATMatcher & pos, const string & s); - -/* Get the next argument of an application, and verify that it is a - integer. */ -ATMatcher & operator >> (ATMatcher & pos, int & n); - -/* Get the next argument of an application, and verify that it is a - list. */ -ATMatcher & operator >> (ATMatcher & pos, ATermList & out); - - /* Throw an exception with an error message containing the given aterm. */ Error badTerm(const format & f, ATerm t); diff --git a/src/libutil/test-aterm.cc b/src/libutil/test-aterm.cc deleted file mode 100644 index 325639ca4..000000000 --- a/src/libutil/test-aterm.cc +++ /dev/null @@ -1,66 +0,0 @@ -#include "aterm.hh" -#include - - -void runTests() -{ - verbosity = lvlDebug; - - ATMatcher pos; - - ATerm t = ATmake("Call(Foo, Bar, \"xyz\")"); - - debug(format("term: %1%") % t); - - string fun, arg3; - ATerm lhs, rhs; - - if (!(atMatch(pos, t) >> "Call" >> lhs >> rhs >> arg3)) - throw Error("should succeed"); - if (arg3 != "xyz") throw Error("bad 1"); - - if (!(atMatch(pos, t) >> fun >> lhs >> rhs >> arg3)) - throw Error("should succeed"); - if (fun != "Call") throw Error("bad 2"); - if (arg3 != "xyz") throw Error("bad 3"); - - if (!(atMatch(pos, t) >> fun >> lhs >> rhs >> "xyz")) - throw Error("should succeed"); - - if (atMatch(pos, t) >> fun >> lhs >> rhs >> "abc") - throw Error("should fail"); - - if (atMatch(pos, t) >> "Call" >> lhs >> rhs >> "abc") - throw Error("should fail"); - - t = ATmake("X([A, B, C], \"abc\")"); - - ATerm t1, t2, t3; - if (atMatch(pos, t) >> "X" >> t1 >> t2 >> t3) - throw Error("should fail"); - if (!(atMatch(pos, t) >> "X" >> t1 >> t2)) - throw Error("should succeed"); - ATermList ts; - if (!(atMatch(pos, t) >> "X" >> ts >> t2)) - throw Error("should succeed"); - if (ATgetLength(ts) != 3) - throw Error("bad"); - if (atMatch(pos, t) >> "X" >> t1 >> ts) - throw Error("should fail"); -} - - -int main(int argc, char * * argv) -{ - ATerm bottomOfStack; - ATinit(argc, argv, &bottomOfStack); - - try { - runTests(); - } catch (Error & e) { - printMsg(lvlError, format("error: %1%") % e.msg()); - return 1; - } - - return 0; -} diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc index c25cdb60c..527dafbf7 100644 --- a/src/nix-env/main.cc +++ b/src/nix-env/main.cc @@ -6,7 +6,7 @@ #include "parser.hh" #include "eval.hh" #include "help.txt.hh" -#include "constructors.hh" +#include "nixexpr-ast.hh" #include #include @@ -481,20 +481,22 @@ typedef list Table; void printTable(Table & table) { - int nrColumns = table.size() > 0 ? table.front().size() : 0; + unsigned int nrColumns = table.size() > 0 ? table.front().size() : 0; - vector widths; + vector widths; widths.resize(nrColumns); for (Table::iterator i = table.begin(); i != table.end(); ++i) { assert(i->size() == nrColumns); - Strings::iterator j; int column; + Strings::iterator j; + unsigned int column; for (j = i->begin(), column = 0; j != i->end(); ++j, ++column) if (j->size() > widths[column]) widths[column] = j->size(); } for (Table::iterator i = table.begin(); i != table.end(); ++i) { - Strings::iterator j; int column; + Strings::iterator j; + unsigned int column; for (j = i->begin(), column = 0; j != i->end(); ++j, ++column) { cout << *j; diff --git a/src/nix-instantiate/main.cc b/src/nix-instantiate/main.cc index 907f7257a..7decc2259 100644 --- a/src/nix-instantiate/main.cc +++ b/src/nix-instantiate/main.cc @@ -6,7 +6,7 @@ #include "shared.hh" #include "eval.hh" #include "parser.hh" -#include "constructors.hh" +#include "nixexpr-ast.hh" #include "help.txt.hh" @@ -28,7 +28,6 @@ static Expr evalStdin(EvalState & state, bool parseOnly) static void printDrvPaths(EvalState & state, Expr e) { - ATMatcher m; ATermList es; /* !!! duplication w.r.t. parseDerivations in nix-env */