* Don't use ATmake / ATmatch anymore, nor the ATMatcher class.

Instead we generate data bindings (build and match functions) for
  the constructors specified in `constructors.def'.  In particular
  this removes the conversions between AFuns and strings, and Nix
  expression evaluation now seems 3 to 4 times faster.
This commit is contained in:
Eelco Dolstra 2004-10-26 22:54:26 +00:00
parent eb8284ddaa
commit 5fe9222b36
11 changed files with 410 additions and 304 deletions

View file

@ -2,9 +2,10 @@ noinst_LIBRARIES = libexpr.a
libexpr_a_SOURCES = nixexpr.cc nixexpr.hh parser.cc parser.hh \ libexpr_a_SOURCES = nixexpr.cc nixexpr.hh parser.cc parser.hh \
eval.cc eval.hh primops.cc \ eval.cc eval.hh primops.cc \
lexer-tab.c lexer-tab.h parser-tab.c parser-tab.h lexer-tab.c lexer-tab.h parser-tab.c parser-tab.h \
constructors.hh
EXTRA_DIST = lexer.l parser.y EXTRA_DIST = lexer.l parser.y constructors.cc
AM_CXXFLAGS = \ AM_CXXFLAGS = \
-I.. ${bdb_include} ${aterm_include} -I../libutil -I../libstore -I.. ${bdb_include} ${aterm_include} -I../libutil -I../libstore
@ -23,4 +24,12 @@ lexer-tab.c lexer-tab.h: lexer.l
$(flex) --outfile lexer-tab.c --header-file=lexer-tab.h lexer.l $(flex) --outfile lexer-tab.c --header-file=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.hh: constructors.hh
CLEANFILES = CLEANFILES =

108
src/libexpr/aterm-helper.pl Executable file
View file

@ -0,0 +1,108 @@
#! /usr/bin/perl -w
die if scalar @ARGV != 2;
my $syms = "";
my $init = "";
open HEADER, ">$ARGV[0]";
open IMPL, ">$ARGV[1]";
while (<STDIN>) {
next if (/^\s*$/);
if (/^\s*(\w+)\s*\|([^\|]*)\|\s*(\w+)\s*\|\s*(\w+)?/) {
my $const = $1;
my @types = split ' ', $2;
my $result = $3;
my $funname = $4;
$funname = $const unless defined $funname;
my $formals = "";
my $formals2 = "";
my $args = "";
my $unpack = "";
my $n = 1;
foreach my $type (@types) {
$args .= ", ";
if ($type eq "string") {
# $args .= "(ATerm) ATmakeAppl0(ATmakeAFun((char *) e$n, 0, ATtrue))";
# $type = "const char *";
$type = "ATerm";
$args .= "e$n";
} elsif ($type eq "int") {
$args .= "(ATerm) ATmakeInt(e$n)";
} elsif ($type eq "ATermList" || $type eq "ATermBlob") {
$args .= "(ATerm) e$n";
} else {
$args .= "e$n";
}
$formals .= ", " if $formals ne "";
$formals .= "$type e$n";
$formals2 .= ", ";
$formals2 .= "$type & e$n";
my $m = $n - 1;
if ($type eq "int") {
$unpack .= " e$n = ATgetInt((ATermInt) ATgetArgument(e, $m));\n";
} elsif ($type eq "ATermList") {
$unpack .= " e$n = (ATermList) ATgetArgument(e, $m);\n";
} elsif ($type eq "ATermBlob") {
$unpack .= " e$n = (ATermBlob) ATgetArgument(e, $m);\n";
} else {
$unpack .= " e$n = ATgetArgument(e, $m);\n";
}
$n++;
}
my $arity = scalar @types;
print HEADER "extern AFun sym$funname;\n\n";
print IMPL "AFun sym$funname = 0;\n";
print HEADER "static inline $result make$funname($formals) {\n";
print HEADER " return (ATerm) ATmakeAppl$arity(sym$funname$args);\n";
print HEADER "}\n\n";
print HEADER "#ifdef __cplusplus\n";
print HEADER "static inline bool match$funname(ATerm e$formals2) {\n";
print HEADER " if (ATgetAFun(e) != sym$funname) return false;\n";
print HEADER "$unpack";
print HEADER " return true;\n";
print HEADER "}\n";
print HEADER "#endif\n\n\n";
$init .= " sym$funname = ATmakeAFun(\"$const\", $arity, ATfalse);\n";
$init .= " ATprotectAFun(sym$funname);\n";
}
elsif (/^\s*(\w+)\s*=\s*(.*)$/) {
my $name = $1;
my $value = $2;
print HEADER "extern ATerm $name;\n";
print IMPL "ATerm $name = 0;\n";
$init .= " $name = $value;\n";
}
else {
die "bad line: `$_'";
}
}
print HEADER "void initSyms();\n\n";
print HEADER "static inline ATerm string2ATerm(const char * s) {\n";
print HEADER " return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s, 0, ATtrue));\n";
print HEADER "}\n\n";
print HEADER "static inline const char * aterm2String(ATerm t) {\n";
print HEADER " return (const char *) ATgetName(ATgetAFun(t));\n";
print HEADER "}\n\n";
print IMPL "\n";
print IMPL "void initSyms() {\n";
print IMPL "$init";
print IMPL "}\n";
close HEADER;
close IMPL;

View file

@ -0,0 +1,53 @@
Pos | string int int | Pos |
NoPos | | Pos |
Function | ATermList Expr Pos | Expr |
Function1 | string Expr Pos | Expr |
Assert | Expr Expr Pos | Expr |
With | Expr Expr Pos | Expr |
If | Expr Expr Expr | Expr |
OpNot | Expr | Expr |
OpEq | Expr Expr | Expr |
OpNEq | Expr Expr | Expr |
OpAnd | Expr Expr | Expr |
OpOr | Expr Expr | Expr |
OpImpl | Expr Expr | Expr |
OpUpdate | Expr Expr | Expr |
SubPath | Expr Expr | Expr |
OpHasAttr | Expr string | Expr |
OpPlus | Expr Expr | Expr |
Call | Expr Expr | Expr |
Select | Expr string | Expr |
Var | string | Expr |
Int | int | Expr |
Str | string | Expr |
Path | string | Expr |
Uri | string | Expr |
List | ATermList | Expr |
BlackHole | | Expr |
Undefined | | Expr |
PrimOp | int ATermBlob ATermList | Expr |
Attrs | ATermList | Expr |
Closed | Expr | Expr |
Rec | ATermList ATermList | Expr |
Bool | ATerm | Expr |
Null | | Expr |
Bind | string Expr Pos | ATerm |
Bind | string Expr | ATerm | Bind2
Inherit | Expr ATermList Pos | ATerm |
Scope | | Expr |
NoDefFormal | string | ATerm |
DefFormal | string Expr | ATerm |
True | | ATerm |
False | | ATerm |
PrimOpDef | int ATermBlob | ATerm |
AttrRHS | Expr Pos | ATerm |
eTrue = makeBool(makeTrue())
eFalse = makeBool(makeFalse())

View file

@ -1,15 +1,17 @@
#include "eval.hh" #include "eval.hh"
#include "parser.hh" #include "parser.hh"
#include "constructors.hh"
EvalState::EvalState() EvalState::EvalState()
: normalForms(32768, 50) : normalForms(32768, 50)
{ {
blackHole = ATmake("BlackHole()"); blackHole = makeBlackHole();
if (!blackHole) throw Error("cannot build black hole");
nrEvaluated = nrCached = 0; nrEvaluated = nrCached = 0;
initSyms();
addPrimOps(); addPrimOps();
} }
@ -17,24 +19,22 @@ EvalState::EvalState()
void EvalState::addPrimOp(const string & name, void EvalState::addPrimOp(const string & name,
unsigned int arity, PrimOp primOp) unsigned int arity, PrimOp primOp)
{ {
primOps.set(name, ATmake("(<int>, <term>)", primOps.set(name, makePrimOpDef(arity, ATmakeBlob(0, (void *) primOp)));
arity, ATmakeBlob(0, (void *) primOp)));
} }
/* Substitute an argument set into the body of a function. */ /* Substitute an argument set into the body of a function. */
static Expr substArgs(Expr body, ATermList formals, Expr arg) static Expr substArgs(Expr body, ATermList formals, Expr arg)
{ {
ATMatcher m;
ATermMap subs; ATermMap subs;
Expr undefined = ATmake("Undefined"); Expr undefined = makeUndefined();
/* Get the formal arguments. */ /* Get the formal arguments. */
for (ATermIterator i(formals); i; ++i) { for (ATermIterator i(formals); i; ++i) {
Expr name, def; Expr name, def;
if (atMatch(m, *i) >> "NoDefFormal" >> name) if (matchNoDefFormal(*i, name))
subs.set(name, undefined); subs.set(name, undefined);
else if (atMatch(m, *i) >> "DefFormal" >> name >> def) else if (matchDefFormal(*i, name, def))
subs.set(name, def); subs.set(name, def);
else abort(); /* can't happen */ else abort(); /* can't happen */
} }
@ -69,38 +69,32 @@ static Expr substArgs(Expr body, ATermList formals, Expr arg)
(e.x) (e.y); y = e.x;}'. */ (e.x) (e.y); y = e.x;}'. */
ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds) ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)
{ {
ATMatcher m;
ATerm name; ATerm name;
Expr e2; Expr e2;
Pos pos;
/* Create the substitution list. */ /* Create the substitution list. */
ATermMap subs; ATermMap subs;
for (ATermIterator i(rbnds); i; ++i) { for (ATermIterator i(rbnds); i; ++i) {
if (!(atMatch(m, *i) >> "Bind" >> name >> e2)) if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
abort(); /* can't happen */ subs.set(name, makeSelect(e, name));
subs.set(name, ATmake("Select(<term>, <term>)", e, name));
} }
for (ATermIterator i(nrbnds); i; ++i) { for (ATermIterator i(nrbnds); i; ++i) {
if (!(atMatch(m, *i) >> "Bind" >> name >> e2)) if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
abort(); /* can't happen */
subs.set(name, e2); subs.set(name, e2);
} }
/* Create the non-recursive set. */ /* Create the non-recursive set. */
ATermMap as; ATermMap as;
for (ATermIterator i(rbnds); i; ++i) { for (ATermIterator i(rbnds); i; ++i) {
ATerm pos; if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos)) as.set(name, makeAttrRHS(substitute(subs, e2), pos));
abort(); /* can't happen */
as.set(name, ATmake("(<term>, <term>)", substitute(subs, e2), pos));
} }
/* Copy the non-recursive bindings. !!! inefficient */ /* Copy the non-recursive bindings. !!! inefficient */
for (ATermIterator i(nrbnds); i; ++i) { for (ATermIterator i(nrbnds); i; ++i) {
ATerm pos; if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos)) as.set(name, makeAttrRHS(e2, pos));
abort(); /* can't happen */
as.set(name, ATmake("(<term>, <term>)", e2, pos));
} }
return makeAttrs(as); return makeAttrs(as);
@ -122,82 +116,73 @@ static Expr updateAttrs(Expr e1, Expr e2)
string evalString(EvalState & state, Expr e) string evalString(EvalState & state, Expr e)
{ {
e = evalExpr(state, e); e = evalExpr(state, e);
ATMatcher m; ATerm s;
string s; if (!matchStr(e, s)) throw Error("string expected");
if (!(atMatch(m, e) >> "Str" >> s)) return aterm2String(s);
throw Error("string expected");
return s;
} }
Path evalPath(EvalState & state, Expr e) Path evalPath(EvalState & state, Expr e)
{ {
e = evalExpr(state, e); e = evalExpr(state, e);
ATMatcher m; ATerm s;
string s; if (!matchPath(e, s)) throw Error("path expected");
if (!(atMatch(m, e) >> "Path" >> s)) return aterm2String(s);
throw Error("path expected");
return s;
} }
bool evalBool(EvalState & state, Expr e) bool evalBool(EvalState & state, Expr e)
{ {
e = evalExpr(state, e); e = evalExpr(state, e);
ATMatcher m; if (e == eTrue) return true;
if (atMatch(m, e) >> "Bool" >> "True") return true; else if (e == eFalse) return false;
else if (atMatch(m, e) >> "Bool" >> "False") return false;
else throw Error("boolean expected"); else throw Error("boolean expected");
} }
Expr evalExpr2(EvalState & state, Expr e) Expr evalExpr2(EvalState & state, Expr e)
{ {
ATMatcher m;
Expr e1, e2, e3, e4; Expr e1, e2, e3, e4;
ATerm name, pos; ATerm name, pos;
AFun sym = ATgetAFun(e);
/* Normal forms. */ /* Normal forms. */
string cons; if (sym == symStr ||
if (atMatch(m, e) >> cons && sym == symPath ||
(cons == "Str" || sym == symSubPath ||
cons == "Path" || sym == symUri ||
cons == "SubPath" || sym == symNull ||
cons == "Uri" || sym == symInt ||
cons == "Null" || sym == symBool ||
cons == "Int" || sym == symFunction ||
cons == "Bool" || sym == symFunction1 ||
cons == "Function" || sym == symAttrs ||
cons == "Function1" || sym == symList ||
cons == "Attrs" || sym == symPrimOp)
cons == "List" ||
cons == "PrimOp"))
return e; return e;
/* The `Closed' constructor is just a way to prevent substitutions /* The `Closed' constructor is just a way to prevent substitutions
into expressions not containing free variables. */ into expressions not containing free variables. */
if (atMatch(m, e) >> "Closed" >> e1) if (matchClosed(e, e1))
return evalExpr(state, e1); return evalExpr(state, e1);
/* Any encountered variables must be primops (since undefined /* Any encountered variables must be primops (since undefined
variables are detected after parsing). */ variables are detected after parsing). */
if (atMatch(m, e) >> "Var" >> name) { if (matchVar(e, name)) {
ATerm primOp = state.primOps.get(name); ATerm primOp = state.primOps.get(name);
if (!primOp) if (!primOp)
throw Error(format("impossible: undefined variable `%1%'") % name); throw Error(format("impossible: undefined variable `%1%'") % name);
int arity; int arity;
ATerm fun; ATermBlob fun;
if (!(atMatch(m, primOp) >> "" >> arity >> fun)) abort(); if (!matchPrimOpDef(primOp, arity, fun)) abort();
if (arity == 0) if (arity == 0)
return ((PrimOp) ATgetBlobData((ATermBlob) fun)) return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector());
(state, ATermVector());
else else
return ATmake("PrimOp(<int>, <term>, <term>)", return makePrimOp(arity, fun, ATempty);
arity, fun, ATempty);
} }
/* Function application. */ /* Function application. */
if (atMatch(m, e) >> "Call" >> e1 >> e2) { if (matchCall(e, e1, e2)) {
ATermList formals; ATermList formals;
ATerm pos; ATerm pos;
@ -207,9 +192,9 @@ Expr evalExpr2(EvalState & state, Expr e)
/* Is it a primop or a function? */ /* Is it a primop or a function? */
int arity; int arity;
ATerm fun; ATermBlob fun;
ATermList args; ATermList args;
if (atMatch(m, e1) >> "PrimOp" >> arity >> fun >> args) { if (matchPrimOp(e1, arity, fun, args)) {
args = ATinsert(args, e2); args = ATinsert(args, e2);
if (ATgetLength(args) == arity) { if (ATgetLength(args) == arity) {
/* Put the arguments in a vector in reverse (i.e., /* Put the arguments in a vector in reverse (i.e.,
@ -221,11 +206,10 @@ Expr evalExpr2(EvalState & state, Expr e)
(state, args2); (state, args2);
} else } else
/* Need more arguments, so propagate the primop. */ /* Need more arguments, so propagate the primop. */
return ATmake("PrimOp(<int>, <term>, <term>)", return makePrimOp(arity, fun, args);
arity, fun, args);
} }
else if (atMatch(m, e1) >> "Function" >> formals >> e4 >> pos) { else if (matchFunction(e1, formals, e4, pos)) {
e2 = evalExpr(state, e2); e2 = evalExpr(state, e2);
try { try {
return evalExpr(state, substArgs(e4, formals, e2)); return evalExpr(state, substArgs(e4, formals, e2));
@ -235,7 +219,7 @@ Expr evalExpr2(EvalState & state, Expr e)
} }
} }
else if (atMatch(m, e1) >> "Function1" >> name >> e4 >> pos) { else if (matchFunction1(e1, name, e4, pos)) {
try { try {
ATermMap subs; ATermMap subs;
subs.set(name, e2); subs.set(name, e2);
@ -250,9 +234,9 @@ Expr evalExpr2(EvalState & state, Expr e)
} }
/* Attribute selection. */ /* Attribute selection. */
string s1; if (matchSelect(e, e1, name)) {
if (atMatch(m, e) >> "Select" >> e1 >> s1) {
ATerm pos; ATerm pos;
string s1 = aterm2String(name);
Expr a = queryAttr(evalExpr(state, e1), s1, pos); Expr a = queryAttr(evalExpr(state, e1), s1, pos);
if (!a) throw Error(format("attribute `%1%' missing") % s1); if (!a) throw Error(format("attribute `%1%' missing") % s1);
try { try {
@ -265,11 +249,11 @@ Expr evalExpr2(EvalState & state, Expr e)
/* Mutually recursive sets. */ /* Mutually recursive sets. */
ATermList rbnds, nrbnds; ATermList rbnds, nrbnds;
if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) if (matchRec(e, rbnds, nrbnds))
return expandRec(e, rbnds, nrbnds); return expandRec(e, rbnds, nrbnds);
/* Conditionals. */ /* Conditionals. */
if (atMatch(m, e) >> "If" >> e1 >> e2 >> e3) { if (matchIf(e, e1, e2, e3)) {
if (evalBool(state, e1)) if (evalBool(state, e1))
return evalExpr(state, e2); return evalExpr(state, e2);
else else
@ -277,14 +261,14 @@ Expr evalExpr2(EvalState & state, Expr e)
} }
/* Assertions. */ /* Assertions. */
if (atMatch(m, e) >> "Assert" >> e1 >> e2 >> pos) { if (matchAssert(e, e1, e2, pos)) {
if (!evalBool(state, e1)) if (!evalBool(state, e1))
throw Error(format("assertion failed at %1%") % showPos(pos)); throw Error(format("assertion failed at %1%") % showPos(pos));
return evalExpr(state, e2); return evalExpr(state, e2);
} }
/* Withs. */ /* Withs. */
if (atMatch(m, e) >> "With" >> e1 >> e2 >> pos) { if (matchWith(e, e1, e2, pos)) {
ATermMap attrs; ATermMap attrs;
try { try {
e1 = evalExpr(state, e1); e1 = evalExpr(state, e1);
@ -304,51 +288,51 @@ Expr evalExpr2(EvalState & state, Expr e)
} }
/* Generic equality. */ /* Generic equality. */
if (atMatch(m, e) >> "OpEq" >> e1 >> e2) if (matchOpEq(e, e1, e2))
return makeBool(evalExpr(state, e1) == evalExpr(state, e2)); return makeBool(evalExpr(state, e1) == evalExpr(state, e2));
/* Generic inequality. */ /* Generic inequality. */
if (atMatch(m, e) >> "OpNEq" >> e1 >> e2) if (matchOpNEq(e, e1, e2))
return makeBool(evalExpr(state, e1) != evalExpr(state, e2)); return makeBool(evalExpr(state, e1) != evalExpr(state, e2));
/* Negation. */ /* Negation. */
if (atMatch(m, e) >> "OpNot" >> e1) if (matchOpNot(e, e1))
return makeBool(!evalBool(state, e1)); return makeBool(!evalBool(state, e1));
/* Implication. */ /* Implication. */
if (atMatch(m, e) >> "OpImpl" >> e1 >> e2) if (matchOpImpl(e, e1, e2))
return makeBool(!evalBool(state, e1) || evalBool(state, e2)); return makeBool(!evalBool(state, e1) || evalBool(state, e2));
/* Conjunction (logical AND). */ /* Conjunction (logical AND). */
if (atMatch(m, e) >> "OpAnd" >> e1 >> e2) if (matchOpAnd(e, e1, e2))
return makeBool(evalBool(state, e1) && evalBool(state, e2)); return makeBool(evalBool(state, e1) && evalBool(state, e2));
/* Disjunction (logical OR). */ /* Disjunction (logical OR). */
if (atMatch(m, e) >> "OpOr" >> e1 >> e2) if (matchOpOr(e, e1, e2))
return makeBool(evalBool(state, e1) || evalBool(state, e2)); return makeBool(evalBool(state, e1) || evalBool(state, e2));
/* Attribute set update (//). */ /* Attribute set update (//). */
if (atMatch(m, e) >> "OpUpdate" >> e1 >> e2) if (matchOpUpdate(e, e1, e2))
return updateAttrs(evalExpr(state, e1), evalExpr(state, e2)); return updateAttrs(evalExpr(state, e1), evalExpr(state, e2));
/* Attribute existence test (?). */ /* Attribute existence test (?). */
if (atMatch(m, e) >> "OpHasAttr" >> e1 >> name) { if (matchOpHasAttr(e, e1, name)) {
ATermMap attrs; ATermMap attrs;
queryAllAttrs(evalExpr(state, e1), attrs); queryAllAttrs(evalExpr(state, e1), attrs);
return makeBool(attrs.get(name) != 0); return makeBool(attrs.get(name) != 0);
} }
/* String or path concatenation. */ /* String or path concatenation. */
if (atMatch(m, e) >> "OpPlus" >> e1 >> e2) { if (matchOpPlus(e, e1, e2)) {
e1 = evalExpr(state, e1); e1 = evalExpr(state, e1);
e2 = evalExpr(state, e2); e2 = evalExpr(state, e2);
string s1, s2; ATerm s1, s2;
if (atMatch(m, e1) >> "Str" >> s1 && if (matchStr(e1, s1) && matchStr(e2, s2))
atMatch(m, e2) >> "Str" >> s2) return makeStr(string2ATerm((
return makeString(s1 + s2); (string) aterm2String(s1) + (string) aterm2String(s2)).c_str()));
else if (atMatch(m, e1) >> "Path" >> s1 && else if (matchPath(e1, s1) && matchPath(e2, s2))
atMatch(m, e2) >> "Path" >> s2) return makePath(string2ATerm(canonPath(
return makePath(canonPath(s1 + "/" + s2)); (string) aterm2String(s1) + "/" + (string) aterm2String(s2)).c_str()));
else throw Error("wrong argument types in `+' operator"); else throw Error("wrong argument types in `+' operator");
} }

View file

@ -2,6 +2,10 @@
#include "storeexpr.hh" #include "storeexpr.hh"
#include "constructors.hh"
#include "constructors.cc"
ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct) ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct)
{ {
this->maxLoadPct = maxLoadPct; this->maxLoadPct = maxLoadPct;
@ -38,7 +42,7 @@ void ATermMap::set(ATerm key, ATerm value)
void ATermMap::set(const string & key, ATerm value) void ATermMap::set(const string & key, ATerm value)
{ {
set(string2ATerm(key), value); set(string2ATerm(key.c_str()), value);
} }
@ -50,7 +54,7 @@ ATerm ATermMap::get(ATerm key) const
ATerm ATermMap::get(const string & key) const ATerm ATermMap::get(const string & key) const
{ {
return get(string2ATerm(key)); return get(string2ATerm(key.c_str()));
} }
@ -62,7 +66,7 @@ void ATermMap::remove(ATerm key)
void ATermMap::remove(const string & key) void ATermMap::remove(const string & key)
{ {
remove(string2ATerm(key)); remove(string2ATerm(key.c_str()));
} }
@ -94,28 +98,14 @@ void ATermMap::reset()
} }
ATerm string2ATerm(const string & s)
{
return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue));
}
string aterm2String(ATerm t)
{
return ATgetName(ATgetAFun(t));
}
string showPos(ATerm pos) string showPos(ATerm pos)
{ {
ATMatcher m; ATerm path;
Path path;
int line, column; int line, column;
if (atMatch(m, pos) >> "NoPos") if (matchNoPos(pos)) return "undefined position";
return "undefined position"; if (!matchPos(pos, path, line, column))
if (!(atMatch(m, pos) >> "Pos" >> path >> line >> column))
throw badTerm("position expected", pos); throw badTerm("position expected", pos);
return (format("`%1%', line %2%") % path % line).str(); return (format("`%1%', line %2%") % aterm2String(path) % line).str();
} }
@ -150,18 +140,16 @@ ATerm bottomupRewrite(TermFun & f, ATerm e)
void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos) void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos)
{ {
ATMatcher m;
ATermList bnds; ATermList bnds;
if (!(atMatch(m, e) >> "Attrs" >> bnds)) if (!matchAttrs(e, bnds))
throw Error("attribute set expected"); throw Error("attribute set expected");
for (ATermIterator i(bnds); i; ++i) { for (ATermIterator i(bnds); i; ++i) {
string s; ATerm name;
Expr e; Expr e;
ATerm pos; ATerm pos;
if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos)) if (!matchBind(*i, name, e, pos)) abort(); /* can't happen */
abort(); /* can't happen */ attrs.set(name, withPos ? makeAttrRHS(e, pos) : e);
attrs.set(s, withPos ? ATmake("(<term>, <term>)", e, pos) : e);
} }
} }
@ -175,18 +163,16 @@ Expr queryAttr(Expr e, const string & name)
Expr queryAttr(Expr e, const string & name, ATerm & pos) Expr queryAttr(Expr e, const string & name, ATerm & pos)
{ {
ATMatcher m;
ATermList bnds; ATermList bnds;
if (!(atMatch(m, e) >> "Attrs" >> bnds)) if (!matchAttrs(e, bnds))
throw Error("attribute set expected"); throw Error("attribute set expected");
for (ATermIterator i(bnds); i; ++i) { for (ATermIterator i(bnds); i; ++i) {
string s; ATerm name2, pos2;
Expr e; Expr e;
ATerm pos2; if (!matchBind(*i, name2, e, pos2))
if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos2))
abort(); /* can't happen */ abort(); /* can't happen */
if (s == name) { if (aterm2String(name2) == name) {
pos = pos2; pos = pos2;
return e; return e;
} }
@ -198,17 +184,15 @@ Expr queryAttr(Expr e, const string & name, ATerm & pos)
Expr makeAttrs(const ATermMap & attrs) Expr makeAttrs(const ATermMap & attrs)
{ {
ATMatcher m;
ATermList bnds = ATempty; ATermList bnds = ATempty;
for (ATermIterator i(attrs.keys()); i; ++i) { for (ATermIterator i(attrs.keys()); i; ++i) {
Expr e; Expr e;
ATerm pos; ATerm pos;
if (!(atMatch(m, attrs.get(*i)) >> "" >> e >> pos)) if (!matchAttrRHS(attrs.get(*i), e, pos))
abort(); /* can't happen */ abort(); /* can't happen */
bnds = ATinsert(bnds, bnds = ATinsert(bnds, makeBind(*i, e, pos));
ATmake("Bind(<term>, <term>, <term>)", *i, e, pos));
} }
return ATmake("Attrs(<term>)", ATreverse(bnds)); return makeAttrs(ATreverse(bnds));
} }
@ -216,57 +200,53 @@ Expr substitute(const ATermMap & subs, Expr e)
{ {
checkInterrupt(); checkInterrupt();
ATMatcher m; ATerm name, pos, e2;
ATerm name, pos;
/* As an optimisation, don't substitute in subterms known to be /* As an optimisation, don't substitute in subterms known to be
closed. */ closed. */
if (atMatch(m, e) >> "Closed") return e; if (matchClosed(e, e2)) return e;
if (atMatch(m, e) >> "Var" >> name) { if (matchVar(e, name)) {
Expr sub = subs.get(name); Expr sub = subs.get(name);
return sub ? ATmake("Closed(<term>)", sub) : e; return sub ? makeClosed(sub) : e;
} }
/* In case of a function, filter out all variables bound by this /* In case of a function, filter out all variables bound by this
function. */ function. */
ATermList formals; ATermList formals;
ATerm body; ATerm body, def;
if (atMatch(m, e) >> "Function" >> formals >> body >> pos) { if (matchFunction(e, formals, body, pos)) {
ATermMap subs2(subs); ATermMap subs2(subs);
for (ATermIterator i(formals); i; ++i) { for (ATermIterator i(formals); i; ++i) {
if (!(atMatch(m, *i) >> "NoDefFormal" >> name) && if (!matchNoDefFormal(*i, name) &&
!(atMatch(m, *i) >> "DefFormal" >> name)) !matchDefFormal(*i, name, def))
abort(); abort();
subs2.remove(name); subs2.remove(name);
} }
return ATmake("Function(<term>, <term>, <term>)", return makeFunction(
substitute(subs, (ATerm) formals), (ATermList) substitute(subs, (ATerm) formals),
substitute(subs2, body), pos); substitute(subs2, body), pos);
} }
if (atMatch(m, e) >> "Function1" >> name >> body >> pos) { if (matchFunction1(e, name, body, pos)) {
ATermMap subs2(subs); ATermMap subs2(subs);
subs2.remove(name); subs2.remove(name);
return ATmake("Function1(<term>, <term>, <term>)", name, return makeFunction1(name, substitute(subs2, body), pos);
substitute(subs2, body), pos);
} }
/* Idem for a mutually recursive attribute set. */ /* Idem for a mutually recursive attribute set. */
ATermList rbnds, nrbnds; ATermList rbnds, nrbnds;
if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) { if (matchRec(e, rbnds, nrbnds)) {
ATermMap subs2(subs); ATermMap subs2(subs);
for (ATermIterator i(rbnds); i; ++i) for (ATermIterator i(rbnds); i; ++i)
if (atMatch(m, *i) >> "Bind" >> name) if (matchBind(*i, name, e2, pos)) subs2.remove(name);
subs2.remove(name);
else abort(); /* can't happen */ else abort(); /* can't happen */
for (ATermIterator i(nrbnds); i; ++i) for (ATermIterator i(nrbnds); i; ++i)
if (atMatch(m, *i) >> "Bind" >> name) if (matchBind(*i, name, e2, pos)) subs2.remove(name);
subs2.remove(name);
else abort(); /* can't happen */ else abort(); /* can't happen */
return ATmake("Rec(<term>, <term>)", return makeRec(
substitute(subs2, (ATerm) rbnds), (ATermList) substitute(subs2, (ATerm) rbnds),
substitute(subs, (ATerm) nrbnds)); (ATermList) substitute(subs, (ATerm) nrbnds));
} }
if (ATgetType(e) == AT_APPL) { if (ATgetType(e) == AT_APPL) {
@ -293,24 +273,23 @@ Expr substitute(const ATermMap & subs, Expr e)
void checkVarDefs(const ATermMap & defs, Expr e) void checkVarDefs(const ATermMap & defs, Expr e)
{ {
ATMatcher m; ATerm name, pos, value;
ATerm name;
ATermList formals; ATermList formals;
ATerm with, body; ATerm with, body;
ATermList rbnds, nrbnds; ATermList rbnds, nrbnds;
if (atMatch(m, e) >> "Var" >> name) { if (matchVar(e, name)) {
if (!defs.get(name)) if (!defs.get(name))
throw Error(format("undefined variable `%1%'") throw Error(format("undefined variable `%1%'")
% aterm2String(name)); % aterm2String(name));
} }
else if (atMatch(m, e) >> "Function" >> formals >> body) { else if (matchFunction(e, formals, body, pos)) {
ATermMap defs2(defs); ATermMap defs2(defs);
for (ATermIterator i(formals); i; ++i) { for (ATermIterator i(formals); i; ++i) {
Expr deflt; Expr deflt;
if (!(atMatch(m, *i) >> "NoDefFormal" >> name)) if (!matchNoDefFormal(*i, name))
if (atMatch(m, *i) >> "DefFormal" >> name >> deflt) if (matchDefFormal(*i, name, deflt))
checkVarDefs(defs, deflt); checkVarDefs(defs, deflt);
else else
abort(); abort();
@ -319,29 +298,27 @@ void checkVarDefs(const ATermMap & defs, Expr e)
checkVarDefs(defs2, body); checkVarDefs(defs2, body);
} }
else if (atMatch(m, e) >> "Function1" >> name >> body) { else if (matchFunction1(e, name, body, pos)) {
ATermMap defs2(defs); ATermMap defs2(defs);
defs2.set(name, (ATerm) ATempty); defs2.set(name, (ATerm) ATempty);
checkVarDefs(defs2, body); checkVarDefs(defs2, body);
} }
else if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) { else if (matchRec(e, rbnds, nrbnds)) {
checkVarDefs(defs, (ATerm) nrbnds); checkVarDefs(defs, (ATerm) nrbnds);
ATermMap defs2(defs); ATermMap defs2(defs);
for (ATermIterator i(rbnds); i; ++i) { for (ATermIterator i(rbnds); i; ++i) {
if (!(atMatch(m, *i) >> "Bind" >> name)) if (!matchBind(*i, name, value, pos)) abort(); /* can't happen */
abort(); /* can't happen */
defs2.set(name, (ATerm) ATempty); defs2.set(name, (ATerm) ATempty);
} }
for (ATermIterator i(nrbnds); i; ++i) { for (ATermIterator i(nrbnds); i; ++i) {
if (!(atMatch(m, *i) >> "Bind" >> name)) if (!matchBind(*i, name, value, pos)) abort(); /* can't happen */
abort(); /* can't happen */
defs2.set(name, (ATerm) ATempty); defs2.set(name, (ATerm) ATempty);
} }
checkVarDefs(defs2, (ATerm) rbnds); checkVarDefs(defs2, (ATerm) rbnds);
} }
else if (atMatch(m, e) >> "With" >> with >> body) { else if (matchWith(e, with, body, pos)) {
/* We can't check the body without evaluating the definitions /* We can't check the body without evaluating the definitions
(which is an arbitrary expression), so we don't do that (which is an arbitrary expression), so we don't do that
here but only when actually evaluating the `with'. */ here but only when actually evaluating the `with'. */
@ -362,17 +339,5 @@ void checkVarDefs(const ATermMap & defs, Expr e)
Expr makeBool(bool b) Expr makeBool(bool b)
{ {
return b ? ATmake("Bool(True)") : ATmake("Bool(False)"); return b ? eTrue : eFalse;
}
Expr makeString(const string & s)
{
return ATmake("Str(<str>)", s.c_str());
}
Expr makePath(const Path & path)
{
return ATmake("Path(<str>)", path.c_str());
} }

View file

@ -13,6 +13,8 @@
normals forms efficiently. */ normals forms efficiently. */
typedef ATerm Expr; typedef ATerm Expr;
typedef ATerm Pos;
/* Mappings from ATerms to ATerms. This is just a wrapper around /* Mappings from ATerms to ATerms. This is just a wrapper around
ATerm tables. */ ATerm tables. */
@ -53,11 +55,6 @@ private:
typedef vector<ATerm> ATermVector; typedef vector<ATerm> ATermVector;
/* Convert a string to an ATerm (i.e., a quoted nullary function
applicaton). */
ATerm string2ATerm(const string & s);
string aterm2String(ATerm t);
/* Show a position. */ /* Show a position. */
string showPos(ATerm pos); string showPos(ATerm pos);

View file

@ -7,6 +7,7 @@
#include "aterm.hh" #include "aterm.hh"
#include "parser.hh" #include "parser.hh"
#include "constructors.hh"
struct ParseData struct ParseData
@ -45,28 +46,24 @@ void parseError(ParseData * data, char * error, int line, int column)
ATerm fixAttrs(int recursive, ATermList as) ATerm fixAttrs(int recursive, ATermList as)
{ {
ATMatcher m;
ATermList bs = ATempty, cs = ATempty; ATermList bs = ATempty, cs = ATempty;
ATermList * is = recursive ? &cs : &bs; ATermList * is = recursive ? &cs : &bs;
for (ATermIterator i(as); i; ++i) { for (ATermIterator i(as); i; ++i) {
ATermList names; ATermList names;
Expr src; Expr src;
ATerm pos; ATerm pos;
if (atMatch(m, *i) >> "Inherit" >> src >> names >> pos) { if (matchInherit(*i, src, names, pos)) {
bool fromScope = atMatch(m, src) >> "Scope"; bool fromScope = matchScope(src);
for (ATermIterator j(names); j; ++j) { for (ATermIterator j(names); j; ++j) {
Expr rhs = fromScope Expr rhs = fromScope ? makeVar(*j) : makeSelect(src, *j);
? ATmake("Var(<term>)", *j) *is = ATinsert(*is, makeBind(*j, rhs, pos));
: ATmake("Select(<term>, <term>)", src, *j);
*is = ATinsert(*is, ATmake("Bind(<term>, <term>, <term>)",
*j, rhs, pos));
} }
} else bs = ATinsert(bs, *i); } else bs = ATinsert(bs, *i);
} }
if (recursive) if (recursive)
return ATmake("Rec(<term>, <term>)", bs, cs); return makeRec(bs, cs);
else else
return ATmake("Attrs(<term>)", bs); return makeAttrs(bs);
} }
const char * getPath(ParseData * data) const char * getPath(ParseData * data)

View file

@ -15,6 +15,11 @@
#include "parser-tab.h" #include "parser-tab.h"
#include "lexer-tab.h" #include "lexer-tab.h"
typedef ATerm Expr;
typedef ATerm Pos;
#include "constructors.hh"
void setParseResult(void * data, ATerm t); void setParseResult(void * data, ATerm t);
void parseError(void * data, char * error, int line, int column); void parseError(void * data, char * error, int line, int column);
ATerm absParsedPath(void * data, ATerm t); ATerm absParsedPath(void * data, ATerm t);
@ -26,13 +31,13 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, void * data, char * s)
parseError(data, s, loc->first_line, loc->first_column); parseError(data, s, loc->first_line, loc->first_column);
} }
ATerm makePos(YYLTYPE * loc, void * data) static Pos makeCurPos(YYLTYPE * loc, void * data)
{ {
return ATmake("Pos(<str>, <int>, <int>)", return makePos(string2ATerm(getPath(data)),
getPath(data), loc->first_line, loc->first_column); loc->first_line, loc->first_column);
} }
#define CUR_POS makePos(yylocp, data) #define CUR_POS makeCurPos(yylocp, data)
%} %}
@ -65,64 +70,64 @@ expr: expr_function;
expr_function expr_function
: '{' formals '}' ':' expr_function : '{' formals '}' ':' expr_function
{ $$ = ATmake("Function(<term>, <term>, <term>)", $2, $5, CUR_POS); } { $$ = makeFunction($2, $5, CUR_POS); }
| ID ':' expr_function | ID ':' expr_function
{ $$ = ATmake("Function1(<term>, <term>, <term>)", $1, $3, CUR_POS); } { $$ = makeFunction1($1, $3, CUR_POS); }
| ASSERT expr ';' expr_function | ASSERT expr ';' expr_function
{ $$ = ATmake("Assert(<term>, <term>, <term>)", $2, $4, CUR_POS); } { $$ = makeAssert($2, $4, CUR_POS); }
| WITH expr ';' expr_function | WITH expr ';' expr_function
{ $$ = ATmake("With(<term>, <term>, <term>)", $2, $4, CUR_POS); } { $$ = makeWith($2, $4, CUR_POS); }
| expr_if | expr_if
; ;
expr_if expr_if
: IF expr THEN expr ELSE expr : IF expr THEN expr ELSE expr
{ $$ = ATmake("If(<term>, <term>, <term>)", $2, $4, $6); } { $$ = makeIf($2, $4, $6); }
| expr_op | expr_op
; ;
expr_op expr_op
: '!' expr_op %prec NEG { $$ = ATmake("OpNot(<term>)", $2); } : '!' expr_op %prec NEG { $$ = makeOpNot($2); }
| expr_op EQ expr_op { $$ = ATmake("OpEq(<term>, <term>)", $1, $3); } | expr_op EQ expr_op { $$ = makeOpEq($1, $3); }
| expr_op NEQ expr_op { $$ = ATmake("OpNEq(<term>, <term>)", $1, $3); } | expr_op NEQ expr_op { $$ = makeOpNEq($1, $3); }
| expr_op AND expr_op { $$ = ATmake("OpAnd(<term>, <term>)", $1, $3); } | expr_op AND expr_op { $$ = makeOpAnd($1, $3); }
| expr_op OR expr_op { $$ = ATmake("OpOr(<term>, <term>)", $1, $3); } | expr_op OR expr_op { $$ = makeOpOr($1, $3); }
| expr_op IMPL expr_op { $$ = ATmake("OpImpl(<term>, <term>)", $1, $3); } | expr_op IMPL expr_op { $$ = makeOpImpl($1, $3); }
| expr_op UPDATE expr_op { $$ = ATmake("OpUpdate(<term>, <term>)", $1, $3); } | expr_op UPDATE expr_op { $$ = makeOpUpdate($1, $3); }
| expr_op '~' expr_op { $$ = ATmake("SubPath(<term>, <term>)", $1, $3); } | expr_op '~' expr_op { $$ = makeSubPath($1, $3); }
| expr_op '?' ID { $$ = ATmake("OpHasAttr(<term>, <term>)", $1, $3); } | expr_op '?' ID { $$ = makeOpHasAttr($1, $3); }
| expr_op '+' expr_op { $$ = ATmake("OpPlus(<term>, <term>)", $1, $3); } | expr_op '+' expr_op { $$ = makeOpPlus($1, $3); }
| expr_app | expr_app
; ;
expr_app expr_app
: expr_app expr_select : expr_app expr_select
{ $$ = ATmake("Call(<term>, <term>)", $1, $2); } { $$ = makeCall($1, $2); }
| expr_select { $$ = $1; } | expr_select { $$ = $1; }
; ;
expr_select expr_select
: expr_select '.' ID : expr_select '.' ID
{ $$ = ATmake("Select(<term>, <term>)", $1, $3); } { $$ = makeSelect($1, $3); }
| expr_simple { $$ = $1; } | expr_simple { $$ = $1; }
; ;
expr_simple expr_simple
: ID { $$ = ATmake("Var(<term>)", $1); } : ID { $$ = makeVar($1); }
| INT { $$ = ATmake("Int(<term>)", $1); } | INT { $$ = makeInt(ATgetInt((ATermInt) $1)); }
| STR { $$ = ATmake("Str(<term>)", $1); } | STR { $$ = makeStr($1); }
| PATH { $$ = ATmake("Path(<term>)", absParsedPath(data, $1)); } | PATH { $$ = makePath(absParsedPath(data, $1)); }
| URI { $$ = ATmake("Uri(<term>)", $1); } | URI { $$ = makeUri($1); }
| '(' expr ')' { $$ = $2; } | '(' expr ')' { $$ = $2; }
/* Let expressions `let {..., body = ...}' are just desugared /* Let expressions `let {..., body = ...}' are just desugared
into `(rec {..., body = ...}).body'. */ into `(rec {..., body = ...}).body'. */
| LET '{' binds '}' | LET '{' binds '}'
{ $$ = ATmake("Select(<term>, \"body\")", fixAttrs(1, $3)); } { $$ = makeSelect(fixAttrs(1, $3), string2ATerm("body")); }
| REC '{' binds '}' | REC '{' binds '}'
{ $$ = fixAttrs(1, $3); } { $$ = fixAttrs(1, $3); }
| '{' binds '}' | '{' binds '}'
{ $$ = fixAttrs(0, $2); } { $$ = fixAttrs(0, $2); }
| '[' expr_list ']' { $$ = ATmake("List(<term>)", $2); } | '[' expr_list ']' { $$ = makeList($2); }
; ;
binds binds
@ -132,14 +137,14 @@ binds
bind bind
: ID '=' expr ';' : ID '=' expr ';'
{ $$ = ATmake("Bind(<term>, <term>, <term>)", $1, $3, CUR_POS); } { $$ = makeBind($1, $3, CUR_POS); }
| INHERIT inheritsrc ids ';' | INHERIT inheritsrc ids ';'
{ $$ = ATmake("Inherit(<term>, <term>, <term>)", $2, $3, CUR_POS); } { $$ = makeInherit($2, $3, CUR_POS); }
; ;
inheritsrc inheritsrc
: '(' expr ')' { $$ = $2; } : '(' expr ')' { $$ = $2; }
| { $$ = ATmake("Scope"); } | { $$ = makeScope(); }
; ;
ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; }; ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; };
@ -158,8 +163,8 @@ formals
; ;
formal formal
: ID { $$ = ATmake("NoDefFormal(<term>)", $1); } : ID { $$ = makeNoDefFormal($1); }
| ID '?' expr { $$ = ATmake("DefFormal(<term>, <term>)", $1, $3); } | ID '?' expr { $$ = makeDefFormal($1, $3); }
; ;
%% %%

View file

@ -1,18 +1,18 @@
#include "normalise.hh" #include "normalise.hh"
#include "eval.hh" #include "eval.hh"
#include "globals.hh" #include "globals.hh"
#include "constructors.hh"
/* Load and evaluate an expression from path specified by the /* Load and evaluate an expression from path specified by the
argument. */ argument. */
static Expr primImport(EvalState & state, const ATermVector & args) static Expr primImport(EvalState & state, const ATermVector & args)
{ {
ATMatcher m; ATerm path;
string path;
Expr fn = evalExpr(state, args[0]); Expr fn = evalExpr(state, args[0]);
if (!(atMatch(m, fn) >> "Path" >> path)) if (!matchPath(fn, path))
throw Error("path expected"); throw Error("path expected");
return evalFile(state, path); return evalFile(state, aterm2String(path));
} }
@ -86,24 +86,23 @@ static void processBinding(EvalState & state, Expr e, StoreExpr & ne,
{ {
e = evalExpr(state, e); e = evalExpr(state, e);
ATMatcher m; ATerm s;
string s;
ATermList es; ATermList es;
int n; int n;
Expr e1, e2; Expr e1, e2;
if (atMatch(m, e) >> "Str" >> s) ss.push_back(s); if (matchStr(e, s)) ss.push_back(aterm2String(s));
else if (atMatch(m, e) >> "Uri" >> s) ss.push_back(s); else if (matchUri(e, s)) ss.push_back(aterm2String(s));
else if (atMatch(m, e) >> "Bool" >> "True") ss.push_back("1"); else if (e == eTrue) ss.push_back("1");
else if (atMatch(m, e) >> "Bool" >> "False") ss.push_back(""); else if (e == eFalse) ss.push_back("");
else if (atMatch(m, e) >> "Int" >> n) { else if (matchInt(e, n)) {
ostringstream st; ostringstream st;
st << n; st << n;
ss.push_back(st.str()); ss.push_back(st.str());
} }
else if (atMatch(m, e) >> "Attrs") { else if (matchAttrs(e, es)) {
Expr a = queryAttr(e, "type"); Expr a = queryAttr(e, "type");
if (a && evalString(state, a) == "derivation") { if (a && evalString(state, a) == "derivation") {
a = queryAttr(e, "drvPath"); a = queryAttr(e, "drvPath");
@ -127,30 +126,29 @@ static void processBinding(EvalState & state, Expr e, StoreExpr & ne,
throw Error("invalid derivation attribute"); throw Error("invalid derivation attribute");
} }
else if (atMatch(m, e) >> "Path" >> s) { else if (matchPath(e, s)) {
Path drvPath = copyAtom(state, s); Path drvPath = copyAtom(state, aterm2String(s));
ss.push_back(addInput(state, drvPath, ne)); ss.push_back(addInput(state, drvPath, ne));
} }
else if (atMatch(m, e) >> "List" >> es) { else if (matchList(e, es)) {
for (ATermIterator i(es); i; ++i) { for (ATermIterator i(es); i; ++i) {
startNest(nest, lvlVomit, format("processing list element")); startNest(nest, lvlVomit, format("processing list element"));
processBinding(state, evalExpr(state, *i), ne, ss); processBinding(state, evalExpr(state, *i), ne, ss);
} }
} }
else if (atMatch(m, e) >> "Null") ss.push_back(""); else if (matchNull(e)) ss.push_back("");
else if (atMatch(m, e) >> "SubPath" >> e1 >> e2) { else if (matchSubPath(e, e1, e2)) {
Strings ss2; Strings ss2;
processBinding(state, evalExpr(state, e1), ne, ss2); processBinding(state, evalExpr(state, e1), ne, ss2);
if (ss2.size() != 1) if (ss2.size() != 1)
throw Error("left-hand side of `~' operator cannot be a list"); throw Error("left-hand side of `~' operator cannot be a list");
e2 = evalExpr(state, e2); e2 = evalExpr(state, e2);
if (!(atMatch(m, e2) >> "Str" >> s || if (!(matchStr(e2, s) || matchPath(e2, s)))
(atMatch(m, e2) >> "Path" >> s)))
throw Error("right-hand side of `~' operator must be a path or string"); throw Error("right-hand side of `~' operator must be a path or string");
ss.push_back(canonPath(ss2.front() + "/" + s)); ss.push_back(canonPath(ss2.front() + "/" + aterm2String(s)));
} }
else throw Error("invalid derivation attribute"); else throw Error("invalid derivation attribute");
@ -198,8 +196,7 @@ static Expr primDerivation(EvalState & state, const ATermVector & _args)
ATerm value; ATerm value;
Expr pos; Expr pos;
ATerm rhs = attrs.get(key); ATerm rhs = attrs.get(key);
ATMatcher m; if (!matchAttrRHS(rhs, value, pos)) abort();
if (!(atMatch(m, rhs) >> "" >> value >> pos)) abort();
startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
Strings ss; Strings ss;
@ -272,10 +269,11 @@ static Expr primDerivation(EvalState & state, const ATermVector & _args)
printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'") printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'")
% drvName % drvPath); % drvName % drvPath);
attrs.set("outPath", ATmake("(Path(<str>), NoPos)", outPath.c_str())); attrs.set("outPath", makeAttrRHS(makePath(string2ATerm(outPath.c_str())), makeNoPos()));
attrs.set("drvPath", ATmake("(Path(<str>), NoPos)", drvPath.c_str())); attrs.set("drvPath", makeAttrRHS(makePath(string2ATerm(drvPath.c_str())), makeNoPos()));
attrs.set("drvHash", ATmake("(<term>, NoPos)", makeString(drvHash))); attrs.set("drvHash",
attrs.set("type", ATmake("(<term>, NoPos)", makeString("derivation"))); makeAttrRHS(makeStr(string2ATerm(((string) drvHash).c_str())), makeNoPos()));
attrs.set("type", makeAttrRHS(makeStr(string2ATerm("derivation")), makeNoPos()));
return makeAttrs(attrs); return makeAttrs(attrs);
} }
@ -285,7 +283,7 @@ static Expr primDerivation(EvalState & state, const ATermVector & _args)
following the last slash. */ following the last slash. */
static Expr primBaseNameOf(EvalState & state, const ATermVector & args) static Expr primBaseNameOf(EvalState & state, const ATermVector & args)
{ {
return makeString(baseNameOf(evalString(state, args[0]))); return makeStr(string2ATerm(baseNameOf(evalString(state, args[0])).c_str()));
} }
@ -293,12 +291,9 @@ static Expr primBaseNameOf(EvalState & state, const ATermVector & args)
static Expr primToString(EvalState & state, const ATermVector & args) static Expr primToString(EvalState & state, const ATermVector & args)
{ {
Expr arg = evalExpr(state, args[0]); Expr arg = evalExpr(state, args[0]);
ATMatcher m; ATerm s;
string s; if (matchStr(arg, s) || matchPath(arg, s) || matchUri(arg, s))
if (atMatch(m, arg) >> "Str" >> s || return makeStr(s);
atMatch(m, arg) >> "Path" >> s ||
atMatch(m, arg) >> "Uri" >> s)
return makeString(s);
else throw Error("cannot coerce value to string"); else throw Error("cannot coerce value to string");
} }
@ -306,29 +301,27 @@ static Expr primToString(EvalState & state, const ATermVector & args)
/* Boolean constructors. */ /* Boolean constructors. */
static Expr primTrue(EvalState & state, const ATermVector & args) static Expr primTrue(EvalState & state, const ATermVector & args)
{ {
return ATmake("Bool(True)"); return eTrue;
} }
static Expr primFalse(EvalState & state, const ATermVector & args) static Expr primFalse(EvalState & state, const ATermVector & args)
{ {
return ATmake("Bool(False)"); return eFalse;
} }
/* Return the null value. */ /* Return the null value. */
Expr primNull(EvalState & state, const ATermVector & args) Expr primNull(EvalState & state, const ATermVector & args)
{ {
return ATmake("Null"); return makeNull();
} }
/* Determine whether the argument is the null value. */ /* Determine whether the argument is the null value. */
Expr primIsNull(EvalState & state, const ATermVector & args) Expr primIsNull(EvalState & state, const ATermVector & args)
{ {
Expr arg = evalExpr(state, args[0]); return makeBool(matchNull(evalExpr(state, args[0])));
ATMatcher m;
return makeBool(atMatch(m, arg) >> "Null");
} }
@ -338,18 +331,15 @@ Expr primMap(EvalState & state, const ATermVector & args)
Expr fun = evalExpr(state, args[0]); Expr fun = evalExpr(state, args[0]);
Expr list = evalExpr(state, args[1]); Expr list = evalExpr(state, args[1]);
ATMatcher m;
ATermList list2; ATermList list2;
if (!(atMatch(m, list) >> "List" >> list2)) if (!matchList(list, list2))
throw Error("`map' expects a list as its second argument"); throw Error("`map' expects a list as its second argument");
ATermList list3 = ATempty; ATermList list3 = ATempty;
for (ATermIterator i(list2); i; ++i) for (ATermIterator i(list2); i; ++i)
list3 = ATinsert(list3, list3 = ATinsert(list3, makeCall(fun, *i));
ATmake("Call(<term>, <term>)", fun, *i));
return ATmake("List(<term>)", ATreverse(list3)); return makeList(ATreverse(list3));
} }

View file

@ -6,6 +6,7 @@
#include "parser.hh" #include "parser.hh"
#include "eval.hh" #include "eval.hh"
#include "help.txt.hh" #include "help.txt.hh"
#include "constructors.hh"
#include <cerrno> #include <cerrno>
#include <ctime> #include <ctime>
@ -47,10 +48,9 @@ void printHelp()
bool parseDerivation(EvalState & state, Expr e, DrvInfo & drv) bool parseDerivation(EvalState & state, Expr e, DrvInfo & drv)
{ {
ATMatcher m; ATermList es;
e = evalExpr(state, e); e = evalExpr(state, e);
if (!(atMatch(m, e) >> "Attrs")) return false; if (!matchAttrs(e, es)) return false;
Expr a = queryAttr(e, "type"); Expr a = queryAttr(e, "type");
if (!a || evalString(state, a) != "derivation") return false; if (!a || evalString(state, a) != "derivation") return false;
@ -82,7 +82,6 @@ bool parseDerivation(EvalState & state, Expr e, DrvInfo & drv)
bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs) bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
{ {
ATMatcher m;
ATermList es; ATermList es;
DrvInfo drv; DrvInfo drv;
@ -91,7 +90,7 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
if (parseDerivation(state, e, drv)) if (parseDerivation(state, e, drv))
drvs[drv.drvPath] = drv; drvs[drv.drvPath] = drv;
else if (atMatch(m, e) >> "Attrs") { else if (matchAttrs(e, es)) {
ATermMap drvMap; ATermMap drvMap;
queryAllAttrs(e, drvMap); queryAllAttrs(e, drvMap);
for (ATermIterator i(drvMap.keys()); i; ++i) { for (ATermIterator i(drvMap.keys()); i; ++i) {
@ -103,7 +102,7 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
} }
} }
else if (atMatch(m, e) >> "List" >> es) { else if (matchList(e, es)) {
for (ATermIterator i(es); i; ++i) { for (ATermIterator i(es); i; ++i) {
debug(format("evaluating list element")); debug(format("evaluating list element"));
if (parseDerivation(state, *i, drv)) if (parseDerivation(state, *i, drv))
@ -152,12 +151,10 @@ struct AddPos : TermFun
{ {
ATerm operator () (ATerm e) ATerm operator () (ATerm e)
{ {
ATMatcher m;
ATerm x, y, z; ATerm x, y, z;
if (atMatch(m, e) >> "Bind" >> x >> y >> z) if (matchBind(e, x, y, z)) return e;
return e; if (matchBind2(e, x, y))
if (atMatch(m, e) >> "Bind" >> x >> y) return makeBind(x, y, makeNoPos());
return ATmake("Bind(<term>, <term>, NoPos)", x, y);
return e; return e;
} }
}; };
@ -194,36 +191,36 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
for (DrvInfos::const_iterator i = drvs.begin(); for (DrvInfos::const_iterator i = drvs.begin();
i != drvs.end(); ++i) i != drvs.end(); ++i)
{ {
ATerm t = ATmake( ATerm t = makeAttrs(ATmakeList6(
"Attrs([" makeBind(string2ATerm("type"),
"Bind(\"type\", Str(\"derivation\"), NoPos), " makeStr(string2ATerm("derivation")), makeNoPos()),
"Bind(\"name\", Str(<str>), NoPos), " makeBind(string2ATerm("name"),
"Bind(\"system\", Str(<str>), NoPos), " makeStr(string2ATerm(i->second.name.c_str())), makeNoPos()),
"Bind(\"drvPath\", Path(<str>), NoPos), " makeBind(string2ATerm("system"),
"Bind(\"drvHash\", Str(<str>), NoPos), " makeStr(string2ATerm(i->second.system.c_str())), makeNoPos()),
"Bind(\"outPath\", Path(<str>), NoPos)" makeBind(string2ATerm("drvPath"),
"])", makePath(string2ATerm(i->second.drvPath.c_str())), makeNoPos()),
i->second.name.c_str(), makeBind(string2ATerm("drvHash"),
i->second.system.c_str(), makeStr(string2ATerm(((string) i->second.drvHash).c_str())), makeNoPos()),
i->second.drvPath.c_str(), makeBind(string2ATerm("outPath"),
((string) i->second.drvHash).c_str(), makePath(string2ATerm(i->second.outPath.c_str())), makeNoPos())
i->second.outPath.c_str()); ));
inputs = ATinsert(inputs, t); inputs = ATinsert(inputs, t);
} }
ATerm inputs2 = ATmake("List(<term>)", ATreverse(inputs)); ATerm inputs2 = makeList(ATreverse(inputs));
/* Also write a copy of the list of inputs to the store; we need /* Also write a copy of the list of inputs to the store; we need
it for future modifications of the environment. */ it for future modifications of the environment. */
Path inputsFile = writeTerm(inputs2, "-env-inputs"); Path inputsFile = writeTerm(inputs2, "-env-inputs");
Expr topLevel = ATmake( Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3(
"Call(<term>, Attrs([" makeBind(string2ATerm("system"),
"Bind(\"system\", Str(<str>), NoPos), " makeStr(string2ATerm(thisSystem.c_str())), makeNoPos()),
"Bind(\"derivations\", <term>, NoPos), " // !!! redundant makeBind(string2ATerm("derivations"), inputs2, makeNoPos()),
"Bind(\"manifest\", Path(<str>), NoPos)" makeBind(string2ATerm("manifest"),
"]))", makePath(string2ATerm(inputsFile.c_str())), makeNoPos())
envBuilder, thisSystem.c_str(), inputs2, inputsFile.c_str()); )));
/* Instantiate it. */ /* Instantiate it. */
debug(format("evaluating builder expression `%1%'") % topLevel); debug(format("evaluating builder expression `%1%'") % topLevel);

View file

@ -6,6 +6,7 @@
#include "shared.hh" #include "shared.hh"
#include "eval.hh" #include "eval.hh"
#include "parser.hh" #include "parser.hh"
#include "constructors.hh"
#include "help.txt.hh" #include "help.txt.hh"
@ -32,7 +33,7 @@ static void printDrvPaths(EvalState & state, Expr e)
/* !!! duplication w.r.t. parseDerivations in nix-env */ /* !!! duplication w.r.t. parseDerivations in nix-env */
if (atMatch(m, e) >> "Attrs" >> es) { if (matchAttrs(e, es)) {
Expr a = queryAttr(e, "type"); Expr a = queryAttr(e, "type");
if (a && evalString(state, a) == "derivation") { if (a && evalString(state, a) == "derivation") {
a = queryAttr(e, "drvPath"); a = queryAttr(e, "drvPath");
@ -50,7 +51,7 @@ static void printDrvPaths(EvalState & state, Expr e)
} }
} }
if (atMatch(m, e) >> "List" >> es) { if (matchList(e, es)) {
for (ATermIterator i(es); i; ++i) for (ATermIterator i(es); i; ++i)
printDrvPaths(state, evalExpr(state, *i)); printDrvPaths(state, evalExpr(state, *i));
return; return;