* Drop ATmake / ATMatcher also in handling store expressions.

This commit is contained in:
Eelco Dolstra 2004-10-29 11:22:49 +00:00
parent ed09821859
commit a69534fc21
19 changed files with 118 additions and 258 deletions

View File

@ -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

View File

@ -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 (<STDIN>) {
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 (<STDIN>) {
# $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 (<STDIN>) {
$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 (<STDIN>) {
$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";

View File

@ -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 =

View File

@ -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();
}

View File

@ -1,3 +1,5 @@
init initNixExprHelpers
Pos | string int int | Pos |
NoPos | | Pos |

View File

@ -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)

View File

@ -7,7 +7,7 @@
#include "aterm.hh"
#include "parser.hh"
#include "constructors.hh"
#include "nixexpr-ast.hh"
struct ParseData

View File

@ -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);

View File

@ -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

View File

@ -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++);

View File

@ -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

View File

@ -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 |

View File

@ -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("<str>", 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("(<str>, <term>)",
i->first.c_str(),
makeClosureElem(
string2ATerm(i->first.c_str()),
unparsePaths(i->second.refs)));
return ATmake("Closure(<term>, <term>)", 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("<str>", 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("(<str>, <str>)",
i->first.c_str(), i->second.c_str()));
makeEnvBinding(
string2ATerm(i->first.c_str()),
string2ATerm(i->second.c_str())));
return ATmake("Derive(<term>, <term>, <str>, <str>, <term>, <term>)",
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));
}

View File

@ -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}

View File

@ -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);

View File

@ -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);

View File

@ -1,66 +0,0 @@
#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;
}

View File

@ -6,7 +6,7 @@
#include "parser.hh"
#include "eval.hh"
#include "help.txt.hh"
#include "constructors.hh"
#include "nixexpr-ast.hh"
#include <cerrno>
#include <ctime>
@ -481,20 +481,22 @@ typedef list<Strings> 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<int> widths;
vector<unsigned int> 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;

View File

@ -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 */