diff options
Diffstat (limited to 'src/libnix')
-rw-r--r-- | src/libnix/Makefile.am | 9 | ||||
-rw-r--r-- | src/libnix/aterm.cc | 93 | ||||
-rw-r--r-- | src/libnix/aterm.hh | 55 | ||||
-rw-r--r-- | src/libnix/expr.cc | 52 | ||||
-rw-r--r-- | src/libnix/expr.hh | 8 | ||||
-rw-r--r-- | src/libnix/normalise.cc | 2 | ||||
-rw-r--r-- | src/libnix/references.hh | 6 | ||||
-rw-r--r-- | src/libnix/test-aterm.cc | 66 |
8 files changed, 247 insertions, 44 deletions
diff --git a/src/libnix/Makefile.am b/src/libnix/Makefile.am index b890ba8c0548..7671b1613d19 100644 --- a/src/libnix/Makefile.am +++ b/src/libnix/Makefile.am @@ -2,8 +2,15 @@ noinst_LIBRARIES = libnix.a libnix_a_SOURCES = util.cc hash.cc archive.cc md5.c \ store.cc expr.cc normalise.cc exec.cc \ - globals.cc db.cc references.cc pathlocks.cc + globals.cc db.cc references.cc pathlocks.cc aterm.cc AM_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall -I.. -I../../externals/inst/include EXTRA_DIST = *.hh *.h test-builder-*.sh + +check_PROGRAMS = test-aterm + +test_aterm_SOURCES = test-aterm.cc +test_aterm_LDADD = libnix.a $(LDADD) ../boost/format/libformat.a \ + -L../../externals/inst/lib -ldb_cxx -lATerm + diff --git a/src/libnix/aterm.cc b/src/libnix/aterm.cc new file mode 100644 index 000000000000..de7c359521a7 --- /dev/null +++ b/src/libnix/aterm.cc @@ -0,0 +1,93 @@ +#include "aterm.hh" + + +string atPrint(ATerm t) +{ + if (!t) throw Error("attempt to print null aterm"); + char * s = ATwriteToString(t); + if (!s) throw Error("cannot print term"); + return s; +} + + +ostream & operator << (ostream & stream, ATerm e) +{ + return stream << atPrint(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, 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; +} diff --git a/src/libnix/aterm.hh b/src/libnix/aterm.hh new file mode 100644 index 000000000000..1e4ee80eeab5 --- /dev/null +++ b/src/libnix/aterm.hh @@ -0,0 +1,55 @@ +#ifndef __ATERM_H +#define __ATERM_H + +extern "C" { +#include <aterm2.h> +} + +#include "util.hh" + + +/* Print an ATerm. */ +string atPrint(ATerm t); + +/* Write an ATerm to an output stream. */ +ostream & operator << (ostream & stream, ATerm e); + +/* 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 applicatin, 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 + list. */ +ATMatcher & operator >> (ATMatcher & pos, ATermList & out); + + +#endif /* !__ATERM_H */ diff --git a/src/libnix/expr.cc b/src/libnix/expr.cc index 9bbe80ab4c88..67fa69f72fab 100644 --- a/src/libnix/expr.cc +++ b/src/libnix/expr.cc @@ -3,14 +3,6 @@ #include "store.hh" -string printTerm(ATerm t) -{ - char * s = ATwriteToString(t); - if (!s) throw Error("cannot print term"); - return s; -} - - Error badTerm(const format & f, ATerm t) { char * s = ATwriteToString(t); @@ -26,7 +18,7 @@ Error badTerm(const format & f, ATerm t) Hash hashTerm(ATerm t) { - return hashString(printTerm(t)); + return hashString(atPrint(t)); } @@ -50,10 +42,11 @@ Path writeTerm(ATerm t, const string & suffix) static void parsePaths(ATermList paths, PathSet & out) { + ATMatcher m; while (!ATisEmpty(paths)) { - char * s; + string s; ATerm t = ATgetFirst(paths); - if (!ATmatch(t, "<str>", &s)) + if (!(atMatch(m, t) >> s)) throw badTerm("not a path", t); out.insert(s); paths = ATgetNext(paths); @@ -91,21 +84,22 @@ static void checkClosure(const Closure & closure) static bool parseClosure(ATerm t, Closure & closure) { ATermList roots, elems; - - if (!ATmatch(t, "Closure([<list>], [<list>])", &roots, &elems)) + ATMatcher m; + + if (!(atMatch(m, t) >> "Closure" >> roots >> elems)) return false; parsePaths(roots, closure.roots); while (!ATisEmpty(elems)) { - char * s1; + string path; ATermList refs; ATerm t = ATgetFirst(elems); - if (!ATmatch(t, "(<str>, [<list>])", &s1, &refs)) + if (!(atMatch(m, t) >> "" >> path >> refs)) throw badTerm("not a closure element", t); ClosureElem elem; parsePaths(refs, elem.refs); - closure.elems[s1] = elem; + closure.elems[path] = elem; elems = ATgetNext(elems); } @@ -116,19 +110,13 @@ static bool parseClosure(ATerm t, Closure & closure) static bool parseDerivation(ATerm t, Derivation & derivation) { + ATMatcher m; ATermList outs, ins, args, bnds; - char * builder; - char * platform; - - if (!ATmatch(t, "Derive([<list>], [<list>], <str>, <str>, [<list>], [<list>])", - &outs, &ins, &platform, &builder, &args, &bnds)) - { - /* !!! compatibility -> remove eventually */ - if (!ATmatch(t, "Derive([<list>], [<list>], <str>, <str>, [<list>])", - &outs, &ins, &builder, &platform, &bnds)) - return false; - args = ATempty; - } + string builder, platform; + + if (!(atMatch(m, t) >> "Derive" >> outs >> ins >> platform + >> builder >> args >> bnds)) + return false; parsePaths(outs, derivation.outputs); parsePaths(ins, derivation.inputs); @@ -137,18 +125,18 @@ static bool parseDerivation(ATerm t, Derivation & derivation) derivation.platform = platform; while (!ATisEmpty(args)) { - char * s; + string s; ATerm arg = ATgetFirst(args); - if (!ATmatch(arg, "<str>", &s)) + if (!(atMatch(m, arg) >> s)) throw badTerm("string expected", arg); derivation.args.push_back(s); args = ATgetNext(args); } while (!ATisEmpty(bnds)) { - char * s1, * s2; + string s1, s2; ATerm bnd = ATgetFirst(bnds); - if (!ATmatch(bnd, "(<str>, <str>)", &s1, &s2)) + if (!(atMatch(m, bnd) >> "" >> s1 >> s2)) throw badTerm("tuple of strings expected", bnd); derivation.env[s1] = s2; bnds = ATgetNext(bnds); diff --git a/src/libnix/expr.hh b/src/libnix/expr.hh index 7d0420935f9d..f5abf9af0d3a 100644 --- a/src/libnix/expr.hh +++ b/src/libnix/expr.hh @@ -1,10 +1,7 @@ #ifndef __FSTATE_H #define __FSTATE_H -extern "C" { -#include <aterm2.h> -} - +#include "aterm.hh" #include "store.hh" @@ -43,9 +40,6 @@ struct NixExpr }; -/* Return a canonical textual representation of an expression. */ -string printTerm(ATerm t); - /* Throw an exception with an error message containing the given aterm. */ Error badTerm(const format & f, ATerm t); diff --git a/src/libnix/normalise.cc b/src/libnix/normalise.cc index 49f86cc6fe18..cb2bf4f5b183 100644 --- a/src/libnix/normalise.cc +++ b/src/libnix/normalise.cc @@ -239,7 +239,7 @@ Path normaliseNixExpr(const Path & _nePath, PathSet pending) /* Write the normal form. This does not have to occur in the transaction below because writing terms is idem-potent. */ ATerm nfTerm = unparseNixExpr(nf); - printMsg(lvlVomit, format("normal form: %1%") % printTerm(nfTerm)); + printMsg(lvlVomit, format("normal form: %1%") % atPrint(nfTerm)); Path nfPath = writeTerm(nfTerm, "-s"); /* Register each outpat path, and register the normal form. This diff --git a/src/libnix/references.hh b/src/libnix/references.hh index d009453d6a00..ada23a883302 100644 --- a/src/libnix/references.hh +++ b/src/libnix/references.hh @@ -1,5 +1,5 @@ -#ifndef __VALUES_H -#define __VALUES_H +#ifndef __REFERENCES_H +#define __REFERENCES_H #include "util.hh" @@ -7,4 +7,4 @@ Strings filterReferences(const Path & path, const Strings & refs); -#endif /* !__VALUES_H */ +#endif /* !__REFERENCES_H */ diff --git a/src/libnix/test-aterm.cc b/src/libnix/test-aterm.cc new file mode 100644 index 000000000000..325639ca4f30 --- /dev/null +++ b/src/libnix/test-aterm.cc @@ -0,0 +1,66 @@ +#include "aterm.hh" +#include <iostream> + + +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; +} |