diff options
author | Eelco Dolstra <e.dolstra@tudelft.nl> | 2004-10-26T22·54+0000 |
---|---|---|
committer | Eelco Dolstra <e.dolstra@tudelft.nl> | 2004-10-26T22·54+0000 |
commit | 5fe9222b36ad49d74c84edb04d6bc4a7d844be01 (patch) | |
tree | e46926a3d60274e5b2dc9e6090df2804986292b0 /src/libexpr | |
parent | eb8284ddaa66448d369647f68cb9f89b93a187de (diff) |
* 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.
Diffstat (limited to 'src/libexpr')
-rw-r--r-- | src/libexpr/Makefile.am | 13 | ||||
-rwxr-xr-x | src/libexpr/aterm-helper.pl | 108 | ||||
-rw-r--r-- | src/libexpr/constructors.def | 53 | ||||
-rw-r--r-- | src/libexpr/eval.cc | 160 | ||||
-rw-r--r-- | src/libexpr/nixexpr.cc | 137 | ||||
-rw-r--r-- | src/libexpr/nixexpr.hh | 7 | ||||
-rw-r--r-- | src/libexpr/parser.cc | 17 | ||||
-rw-r--r-- | src/libexpr/parser.y | 71 | ||||
-rw-r--r-- | src/libexpr/primops.cc | 80 |
9 files changed, 377 insertions, 269 deletions
diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am index 45145a6bdb18..99ed1a5ed3f8 100644 --- a/src/libexpr/Makefile.am +++ b/src/libexpr/Makefile.am @@ -2,9 +2,10 @@ 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 + 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 = \ -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 +# 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 = diff --git a/src/libexpr/aterm-helper.pl b/src/libexpr/aterm-helper.pl new file mode 100755 index 000000000000..568141cb4ac2 --- /dev/null +++ b/src/libexpr/aterm-helper.pl @@ -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; diff --git a/src/libexpr/constructors.def b/src/libexpr/constructors.def new file mode 100644 index 000000000000..497cd33c336d --- /dev/null +++ b/src/libexpr/constructors.def @@ -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()) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 35b9cae00b7c..88362333c29d 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1,15 +1,17 @@ #include "eval.hh" #include "parser.hh" +#include "constructors.hh" EvalState::EvalState() : normalForms(32768, 50) { - blackHole = ATmake("BlackHole()"); - if (!blackHole) throw Error("cannot build black hole"); + blackHole = makeBlackHole(); nrEvaluated = nrCached = 0; + initSyms(); + addPrimOps(); } @@ -17,24 +19,22 @@ EvalState::EvalState() void EvalState::addPrimOp(const string & name, unsigned int arity, PrimOp primOp) { - primOps.set(name, ATmake("(<int>, <term>)", - arity, ATmakeBlob(0, (void *) primOp))); + primOps.set(name, makePrimOpDef(arity, ATmakeBlob(0, (void *) primOp))); } /* Substitute an argument set into the body of a function. */ static Expr substArgs(Expr body, ATermList formals, Expr arg) { - ATMatcher m; ATermMap subs; - Expr undefined = ATmake("Undefined"); + Expr undefined = makeUndefined(); /* Get the formal arguments. */ for (ATermIterator i(formals); i; ++i) { Expr name, def; - if (atMatch(m, *i) >> "NoDefFormal" >> name) + if (matchNoDefFormal(*i, name)) subs.set(name, undefined); - else if (atMatch(m, *i) >> "DefFormal" >> name >> def) + else if (matchDefFormal(*i, name, def)) subs.set(name, def); 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;}'. */ ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds) { - ATMatcher m; ATerm name; Expr e2; + Pos pos; /* Create the substitution list. */ ATermMap subs; for (ATermIterator i(rbnds); i; ++i) { - if (!(atMatch(m, *i) >> "Bind" >> name >> e2)) - abort(); /* can't happen */ - subs.set(name, ATmake("Select(<term>, <term>)", e, name)); + if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ + subs.set(name, makeSelect(e, name)); } for (ATermIterator i(nrbnds); i; ++i) { - if (!(atMatch(m, *i) >> "Bind" >> name >> e2)) - abort(); /* can't happen */ + if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ subs.set(name, e2); } /* Create the non-recursive set. */ ATermMap as; for (ATermIterator i(rbnds); i; ++i) { - ATerm pos; - if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos)) - abort(); /* can't happen */ - as.set(name, ATmake("(<term>, <term>)", substitute(subs, e2), pos)); + if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ + as.set(name, makeAttrRHS(substitute(subs, e2), pos)); } /* Copy the non-recursive bindings. !!! inefficient */ for (ATermIterator i(nrbnds); i; ++i) { - ATerm pos; - if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos)) - abort(); /* can't happen */ - as.set(name, ATmake("(<term>, <term>)", e2, pos)); + if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ + as.set(name, makeAttrRHS(e2, pos)); } return makeAttrs(as); @@ -122,82 +116,73 @@ static Expr updateAttrs(Expr e1, Expr e2) string evalString(EvalState & state, Expr e) { e = evalExpr(state, e); - ATMatcher m; - string s; - if (!(atMatch(m, e) >> "Str" >> s)) - throw Error("string expected"); - return s; + ATerm s; + if (!matchStr(e, s)) throw Error("string expected"); + return aterm2String(s); } Path evalPath(EvalState & state, Expr e) { e = evalExpr(state, e); - ATMatcher m; - string s; - if (!(atMatch(m, e) >> "Path" >> s)) - throw Error("path expected"); - return s; + ATerm s; + if (!matchPath(e, s)) throw Error("path expected"); + return aterm2String(s); } bool evalBool(EvalState & state, Expr e) { e = evalExpr(state, e); - ATMatcher m; - if (atMatch(m, e) >> "Bool" >> "True") return true; - else if (atMatch(m, e) >> "Bool" >> "False") return false; + if (e == eTrue) return true; + else if (e == eFalse) return false; else throw Error("boolean expected"); } Expr evalExpr2(EvalState & state, Expr e) { - ATMatcher m; Expr e1, e2, e3, e4; ATerm name, pos; + AFun sym = ATgetAFun(e); /* Normal forms. */ - string cons; - if (atMatch(m, e) >> cons && - (cons == "Str" || - cons == "Path" || - cons == "SubPath" || - cons == "Uri" || - cons == "Null" || - cons == "Int" || - cons == "Bool" || - cons == "Function" || - cons == "Function1" || - cons == "Attrs" || - cons == "List" || - cons == "PrimOp")) + if (sym == symStr || + sym == symPath || + sym == symSubPath || + sym == symUri || + sym == symNull || + sym == symInt || + sym == symBool || + sym == symFunction || + sym == symFunction1 || + sym == symAttrs || + sym == symList || + sym == symPrimOp) return e; - + /* The `Closed' constructor is just a way to prevent substitutions into expressions not containing free variables. */ - if (atMatch(m, e) >> "Closed" >> e1) + if (matchClosed(e, e1)) return evalExpr(state, e1); /* Any encountered variables must be primops (since undefined variables are detected after parsing). */ - if (atMatch(m, e) >> "Var" >> name) { + if (matchVar(e, name)) { ATerm primOp = state.primOps.get(name); if (!primOp) throw Error(format("impossible: undefined variable `%1%'") % name); int arity; - ATerm fun; - if (!(atMatch(m, primOp) >> "" >> arity >> fun)) abort(); + ATermBlob fun; + if (!matchPrimOpDef(primOp, arity, fun)) abort(); if (arity == 0) - return ((PrimOp) ATgetBlobData((ATermBlob) fun)) - (state, ATermVector()); + return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector()); else - return ATmake("PrimOp(<int>, <term>, <term>)", - arity, fun, ATempty); + return makePrimOp(arity, fun, ATempty); } /* Function application. */ - if (atMatch(m, e) >> "Call" >> e1 >> e2) { + if (matchCall(e, e1, e2)) { ATermList formals; ATerm pos; @@ -207,9 +192,9 @@ Expr evalExpr2(EvalState & state, Expr e) /* Is it a primop or a function? */ int arity; - ATerm fun; + ATermBlob fun; ATermList args; - if (atMatch(m, e1) >> "PrimOp" >> arity >> fun >> args) { + if (matchPrimOp(e1, arity, fun, args)) { args = ATinsert(args, e2); if (ATgetLength(args) == arity) { /* Put the arguments in a vector in reverse (i.e., @@ -221,11 +206,10 @@ Expr evalExpr2(EvalState & state, Expr e) (state, args2); } else /* Need more arguments, so propagate the primop. */ - return ATmake("PrimOp(<int>, <term>, <term>)", - arity, fun, args); + return makePrimOp(arity, fun, args); } - else if (atMatch(m, e1) >> "Function" >> formals >> e4 >> pos) { + else if (matchFunction(e1, formals, e4, pos)) { e2 = evalExpr(state, e2); try { 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 { ATermMap subs; subs.set(name, e2); @@ -250,9 +234,9 @@ Expr evalExpr2(EvalState & state, Expr e) } /* Attribute selection. */ - string s1; - if (atMatch(m, e) >> "Select" >> e1 >> s1) { + if (matchSelect(e, e1, name)) { ATerm pos; + string s1 = aterm2String(name); Expr a = queryAttr(evalExpr(state, e1), s1, pos); if (!a) throw Error(format("attribute `%1%' missing") % s1); try { @@ -265,11 +249,11 @@ Expr evalExpr2(EvalState & state, Expr e) /* Mutually recursive sets. */ ATermList rbnds, nrbnds; - if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) + if (matchRec(e, rbnds, nrbnds)) return expandRec(e, rbnds, nrbnds); /* Conditionals. */ - if (atMatch(m, e) >> "If" >> e1 >> e2 >> e3) { + if (matchIf(e, e1, e2, e3)) { if (evalBool(state, e1)) return evalExpr(state, e2); else @@ -277,14 +261,14 @@ Expr evalExpr2(EvalState & state, Expr e) } /* Assertions. */ - if (atMatch(m, e) >> "Assert" >> e1 >> e2 >> pos) { + if (matchAssert(e, e1, e2, pos)) { if (!evalBool(state, e1)) throw Error(format("assertion failed at %1%") % showPos(pos)); return evalExpr(state, e2); } /* Withs. */ - if (atMatch(m, e) >> "With" >> e1 >> e2 >> pos) { + if (matchWith(e, e1, e2, pos)) { ATermMap attrs; try { e1 = evalExpr(state, e1); @@ -304,51 +288,51 @@ Expr evalExpr2(EvalState & state, Expr e) } /* Generic equality. */ - if (atMatch(m, e) >> "OpEq" >> e1 >> e2) + if (matchOpEq(e, e1, e2)) return makeBool(evalExpr(state, e1) == evalExpr(state, e2)); /* Generic inequality. */ - if (atMatch(m, e) >> "OpNEq" >> e1 >> e2) + if (matchOpNEq(e, e1, e2)) return makeBool(evalExpr(state, e1) != evalExpr(state, e2)); /* Negation. */ - if (atMatch(m, e) >> "OpNot" >> e1) + if (matchOpNot(e, e1)) return makeBool(!evalBool(state, e1)); /* Implication. */ - if (atMatch(m, e) >> "OpImpl" >> e1 >> e2) + if (matchOpImpl(e, e1, e2)) return makeBool(!evalBool(state, e1) || evalBool(state, e2)); /* Conjunction (logical AND). */ - if (atMatch(m, e) >> "OpAnd" >> e1 >> e2) + if (matchOpAnd(e, e1, e2)) return makeBool(evalBool(state, e1) && evalBool(state, e2)); /* Disjunction (logical OR). */ - if (atMatch(m, e) >> "OpOr" >> e1 >> e2) + if (matchOpOr(e, e1, e2)) return makeBool(evalBool(state, e1) || evalBool(state, e2)); /* Attribute set update (//). */ - if (atMatch(m, e) >> "OpUpdate" >> e1 >> e2) + if (matchOpUpdate(e, e1, e2)) return updateAttrs(evalExpr(state, e1), evalExpr(state, e2)); /* Attribute existence test (?). */ - if (atMatch(m, e) >> "OpHasAttr" >> e1 >> name) { + if (matchOpHasAttr(e, e1, name)) { ATermMap attrs; queryAllAttrs(evalExpr(state, e1), attrs); return makeBool(attrs.get(name) != 0); } /* String or path concatenation. */ - if (atMatch(m, e) >> "OpPlus" >> e1 >> e2) { + if (matchOpPlus(e, e1, e2)) { e1 = evalExpr(state, e1); e2 = evalExpr(state, e2); - string s1, s2; - if (atMatch(m, e1) >> "Str" >> s1 && - atMatch(m, e2) >> "Str" >> s2) - return makeString(s1 + s2); - else if (atMatch(m, e1) >> "Path" >> s1 && - atMatch(m, e2) >> "Path" >> s2) - return makePath(canonPath(s1 + "/" + s2)); + ATerm s1, s2; + if (matchStr(e1, s1) && matchStr(e2, s2)) + return makeStr(string2ATerm(( + (string) aterm2String(s1) + (string) aterm2String(s2)).c_str())); + else if (matchPath(e1, s1) && matchPath(e2, s2)) + return makePath(string2ATerm(canonPath( + (string) aterm2String(s1) + "/" + (string) aterm2String(s2)).c_str())); else throw Error("wrong argument types in `+' operator"); } diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 37288804d0eb..cbfb5576bf04 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -2,6 +2,10 @@ #include "storeexpr.hh" +#include "constructors.hh" +#include "constructors.cc" + + ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct) { this->maxLoadPct = maxLoadPct; @@ -38,7 +42,7 @@ void ATermMap::set(ATerm 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 { - 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) { - 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) { - ATMatcher m; - Path path; + ATerm path; int line, column; - if (atMatch(m, pos) >> "NoPos") - return "undefined position"; - if (!(atMatch(m, pos) >> "Pos" >> path >> line >> column)) + if (matchNoPos(pos)) return "undefined position"; + if (!matchPos(pos, path, line, column)) 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) { - ATMatcher m; ATermList bnds; - if (!(atMatch(m, e) >> "Attrs" >> bnds)) + if (!matchAttrs(e, bnds)) throw Error("attribute set expected"); for (ATermIterator i(bnds); i; ++i) { - string s; + ATerm name; Expr e; ATerm pos; - if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos)) - abort(); /* can't happen */ - attrs.set(s, withPos ? ATmake("(<term>, <term>)", e, pos) : e); + if (!matchBind(*i, name, e, pos)) abort(); /* can't happen */ + attrs.set(name, withPos ? makeAttrRHS(e, pos) : e); } } @@ -175,18 +163,16 @@ Expr queryAttr(Expr e, const string & name) Expr queryAttr(Expr e, const string & name, ATerm & pos) { - ATMatcher m; ATermList bnds; - if (!(atMatch(m, e) >> "Attrs" >> bnds)) + if (!matchAttrs(e, bnds)) throw Error("attribute set expected"); for (ATermIterator i(bnds); i; ++i) { - string s; + ATerm name2, pos2; Expr e; - ATerm pos2; - if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos2)) + if (!matchBind(*i, name2, e, pos2)) abort(); /* can't happen */ - if (s == name) { + if (aterm2String(name2) == name) { pos = pos2; return e; } @@ -198,17 +184,15 @@ Expr queryAttr(Expr e, const string & name, ATerm & pos) Expr makeAttrs(const ATermMap & attrs) { - ATMatcher m; ATermList bnds = ATempty; for (ATermIterator i(attrs.keys()); i; ++i) { Expr e; ATerm pos; - if (!(atMatch(m, attrs.get(*i)) >> "" >> e >> pos)) + if (!matchAttrRHS(attrs.get(*i), e, pos)) abort(); /* can't happen */ - bnds = ATinsert(bnds, - ATmake("Bind(<term>, <term>, <term>)", *i, e, pos)); + bnds = ATinsert(bnds, makeBind(*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(); - ATMatcher m; - ATerm name, pos; + ATerm name, pos, e2; /* As an optimisation, don't substitute in subterms known to be 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); - return sub ? ATmake("Closed(<term>)", sub) : e; + return sub ? makeClosed(sub) : e; } /* In case of a function, filter out all variables bound by this function. */ ATermList formals; - ATerm body; - if (atMatch(m, e) >> "Function" >> formals >> body >> pos) { + ATerm body, def; + if (matchFunction(e, formals, body, pos)) { ATermMap subs2(subs); for (ATermIterator i(formals); i; ++i) { - if (!(atMatch(m, *i) >> "NoDefFormal" >> name) && - !(atMatch(m, *i) >> "DefFormal" >> name)) + if (!matchNoDefFormal(*i, name) && + !matchDefFormal(*i, name, def)) abort(); subs2.remove(name); } - return ATmake("Function(<term>, <term>, <term>)", - substitute(subs, (ATerm) formals), + return makeFunction( + (ATermList) substitute(subs, (ATerm) formals), substitute(subs2, body), pos); } - if (atMatch(m, e) >> "Function1" >> name >> body >> pos) { + if (matchFunction1(e, name, body, pos)) { ATermMap subs2(subs); subs2.remove(name); - return ATmake("Function1(<term>, <term>, <term>)", name, - substitute(subs2, body), pos); + return makeFunction1(name, substitute(subs2, body), pos); } /* Idem for a mutually recursive attribute set. */ ATermList rbnds, nrbnds; - if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) { + if (matchRec(e, rbnds, nrbnds)) { ATermMap subs2(subs); for (ATermIterator i(rbnds); i; ++i) - if (atMatch(m, *i) >> "Bind" >> name) - subs2.remove(name); + if (matchBind(*i, name, e2, pos)) subs2.remove(name); else abort(); /* can't happen */ for (ATermIterator i(nrbnds); i; ++i) - if (atMatch(m, *i) >> "Bind" >> name) - subs2.remove(name); + if (matchBind(*i, name, e2, pos)) subs2.remove(name); else abort(); /* can't happen */ - return ATmake("Rec(<term>, <term>)", - substitute(subs2, (ATerm) rbnds), - substitute(subs, (ATerm) nrbnds)); + return makeRec( + (ATermList) substitute(subs2, (ATerm) rbnds), + (ATermList) substitute(subs, (ATerm) nrbnds)); } if (ATgetType(e) == AT_APPL) { @@ -293,24 +273,23 @@ Expr substitute(const ATermMap & subs, Expr e) void checkVarDefs(const ATermMap & defs, Expr e) { - ATMatcher m; - ATerm name; + ATerm name, pos, value; ATermList formals; ATerm with, body; ATermList rbnds, nrbnds; - if (atMatch(m, e) >> "Var" >> name) { + if (matchVar(e, name)) { if (!defs.get(name)) throw Error(format("undefined variable `%1%'") % aterm2String(name)); } - else if (atMatch(m, e) >> "Function" >> formals >> body) { + else if (matchFunction(e, formals, body, pos)) { ATermMap defs2(defs); for (ATermIterator i(formals); i; ++i) { Expr deflt; - if (!(atMatch(m, *i) >> "NoDefFormal" >> name)) - if (atMatch(m, *i) >> "DefFormal" >> name >> deflt) + if (!matchNoDefFormal(*i, name)) + if (matchDefFormal(*i, name, deflt)) checkVarDefs(defs, deflt); else abort(); @@ -319,29 +298,27 @@ void checkVarDefs(const ATermMap & defs, Expr e) checkVarDefs(defs2, body); } - else if (atMatch(m, e) >> "Function1" >> name >> body) { + else if (matchFunction1(e, name, body, pos)) { ATermMap defs2(defs); defs2.set(name, (ATerm) ATempty); checkVarDefs(defs2, body); } - else if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) { + else if (matchRec(e, rbnds, nrbnds)) { checkVarDefs(defs, (ATerm) nrbnds); ATermMap defs2(defs); for (ATermIterator i(rbnds); i; ++i) { - if (!(atMatch(m, *i) >> "Bind" >> name)) - abort(); /* can't happen */ + if (!matchBind(*i, name, value, pos)) abort(); /* can't happen */ defs2.set(name, (ATerm) ATempty); } for (ATermIterator i(nrbnds); i; ++i) { - if (!(atMatch(m, *i) >> "Bind" >> name)) - abort(); /* can't happen */ + if (!matchBind(*i, name, value, pos)) abort(); /* can't happen */ defs2.set(name, (ATerm) ATempty); } 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 (which is an arbitrary expression), so we don't do that here but only when actually evaluating the `with'. */ @@ -362,17 +339,5 @@ void checkVarDefs(const ATermMap & defs, Expr e) Expr makeBool(bool b) { - return b ? ATmake("Bool(True)") : ATmake("Bool(False)"); -} - - -Expr makeString(const string & s) -{ - return ATmake("Str(<str>)", s.c_str()); -} - - -Expr makePath(const Path & path) -{ - return ATmake("Path(<str>)", path.c_str()); + return b ? eTrue : eFalse; } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 657e6055c40e..9c49751c7dbb 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -13,6 +13,8 @@ normals forms efficiently. */ typedef ATerm Expr; +typedef ATerm Pos; + /* Mappings from ATerms to ATerms. This is just a wrapper around ATerm tables. */ @@ -53,11 +55,6 @@ private: 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. */ string showPos(ATerm pos); diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc index 763faacf7be3..a0a6c01df762 100644 --- a/src/libexpr/parser.cc +++ b/src/libexpr/parser.cc @@ -7,6 +7,7 @@ #include "aterm.hh" #include "parser.hh" +#include "constructors.hh" struct ParseData @@ -45,28 +46,24 @@ void parseError(ParseData * data, char * error, int line, int column) ATerm fixAttrs(int recursive, ATermList as) { - ATMatcher m; ATermList bs = ATempty, cs = ATempty; ATermList * is = recursive ? &cs : &bs; for (ATermIterator i(as); i; ++i) { ATermList names; Expr src; ATerm pos; - if (atMatch(m, *i) >> "Inherit" >> src >> names >> pos) { - bool fromScope = atMatch(m, src) >> "Scope"; + if (matchInherit(*i, src, names, pos)) { + bool fromScope = matchScope(src); for (ATermIterator j(names); j; ++j) { - Expr rhs = fromScope - ? ATmake("Var(<term>)", *j) - : ATmake("Select(<term>, <term>)", src, *j); - *is = ATinsert(*is, ATmake("Bind(<term>, <term>, <term>)", - *j, rhs, pos)); + Expr rhs = fromScope ? makeVar(*j) : makeSelect(src, *j); + *is = ATinsert(*is, makeBind(*j, rhs, pos)); } } else bs = ATinsert(bs, *i); } if (recursive) - return ATmake("Rec(<term>, <term>)", bs, cs); + return makeRec(bs, cs); else - return ATmake("Attrs(<term>)", bs); + return makeAttrs(bs); } const char * getPath(ParseData * data) diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index c56d89809f49..2864b1600e73 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -15,6 +15,11 @@ #include "parser-tab.h" #include "lexer-tab.h" +typedef ATerm Expr; +typedef ATerm Pos; + +#include "constructors.hh" + void setParseResult(void * data, ATerm t); void parseError(void * data, char * error, int line, int column); 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); } -ATerm makePos(YYLTYPE * loc, void * data) +static Pos makeCurPos(YYLTYPE * loc, void * data) { - return ATmake("Pos(<str>, <int>, <int>)", - getPath(data), loc->first_line, loc->first_column); + return makePos(string2ATerm(getPath(data)), + 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 : '{' formals '}' ':' expr_function - { $$ = ATmake("Function(<term>, <term>, <term>)", $2, $5, CUR_POS); } + { $$ = makeFunction($2, $5, CUR_POS); } | ID ':' expr_function - { $$ = ATmake("Function1(<term>, <term>, <term>)", $1, $3, CUR_POS); } + { $$ = makeFunction1($1, $3, CUR_POS); } | ASSERT expr ';' expr_function - { $$ = ATmake("Assert(<term>, <term>, <term>)", $2, $4, CUR_POS); } + { $$ = makeAssert($2, $4, CUR_POS); } | WITH expr ';' expr_function - { $$ = ATmake("With(<term>, <term>, <term>)", $2, $4, CUR_POS); } + { $$ = makeWith($2, $4, CUR_POS); } | expr_if ; expr_if : IF expr THEN expr ELSE expr - { $$ = ATmake("If(<term>, <term>, <term>)", $2, $4, $6); } + { $$ = makeIf($2, $4, $6); } | expr_op ; expr_op - : '!' expr_op %prec NEG { $$ = ATmake("OpNot(<term>)", $2); } - | expr_op EQ expr_op { $$ = ATmake("OpEq(<term>, <term>)", $1, $3); } - | expr_op NEQ expr_op { $$ = ATmake("OpNEq(<term>, <term>)", $1, $3); } - | expr_op AND expr_op { $$ = ATmake("OpAnd(<term>, <term>)", $1, $3); } - | expr_op OR expr_op { $$ = ATmake("OpOr(<term>, <term>)", $1, $3); } - | expr_op IMPL expr_op { $$ = ATmake("OpImpl(<term>, <term>)", $1, $3); } - | expr_op UPDATE expr_op { $$ = ATmake("OpUpdate(<term>, <term>)", $1, $3); } - | expr_op '~' expr_op { $$ = ATmake("SubPath(<term>, <term>)", $1, $3); } - | expr_op '?' ID { $$ = ATmake("OpHasAttr(<term>, <term>)", $1, $3); } - | expr_op '+' expr_op { $$ = ATmake("OpPlus(<term>, <term>)", $1, $3); } + : '!' expr_op %prec NEG { $$ = makeOpNot($2); } + | expr_op EQ expr_op { $$ = makeOpEq($1, $3); } + | expr_op NEQ expr_op { $$ = makeOpNEq($1, $3); } + | expr_op AND expr_op { $$ = makeOpAnd($1, $3); } + | expr_op OR expr_op { $$ = makeOpOr($1, $3); } + | expr_op IMPL expr_op { $$ = makeOpImpl($1, $3); } + | expr_op UPDATE expr_op { $$ = makeOpUpdate($1, $3); } + | expr_op '~' expr_op { $$ = makeSubPath($1, $3); } + | expr_op '?' ID { $$ = makeOpHasAttr($1, $3); } + | expr_op '+' expr_op { $$ = makeOpPlus($1, $3); } | expr_app ; expr_app : expr_app expr_select - { $$ = ATmake("Call(<term>, <term>)", $1, $2); } + { $$ = makeCall($1, $2); } | expr_select { $$ = $1; } ; expr_select : expr_select '.' ID - { $$ = ATmake("Select(<term>, <term>)", $1, $3); } + { $$ = makeSelect($1, $3); } | expr_simple { $$ = $1; } ; expr_simple - : ID { $$ = ATmake("Var(<term>)", $1); } - | INT { $$ = ATmake("Int(<term>)", $1); } - | STR { $$ = ATmake("Str(<term>)", $1); } - | PATH { $$ = ATmake("Path(<term>)", absParsedPath(data, $1)); } - | URI { $$ = ATmake("Uri(<term>)", $1); } + : ID { $$ = makeVar($1); } + | INT { $$ = makeInt(ATgetInt((ATermInt) $1)); } + | STR { $$ = makeStr($1); } + | PATH { $$ = makePath(absParsedPath(data, $1)); } + | URI { $$ = makeUri($1); } | '(' expr ')' { $$ = $2; } /* Let expressions `let {..., body = ...}' are just desugared into `(rec {..., body = ...}).body'. */ | LET '{' binds '}' - { $$ = ATmake("Select(<term>, \"body\")", fixAttrs(1, $3)); } + { $$ = makeSelect(fixAttrs(1, $3), string2ATerm("body")); } | REC '{' binds '}' { $$ = fixAttrs(1, $3); } | '{' binds '}' { $$ = fixAttrs(0, $2); } - | '[' expr_list ']' { $$ = ATmake("List(<term>)", $2); } + | '[' expr_list ']' { $$ = makeList($2); } ; binds @@ -132,14 +137,14 @@ binds bind : ID '=' expr ';' - { $$ = ATmake("Bind(<term>, <term>, <term>)", $1, $3, CUR_POS); } + { $$ = makeBind($1, $3, CUR_POS); } | INHERIT inheritsrc ids ';' - { $$ = ATmake("Inherit(<term>, <term>, <term>)", $2, $3, CUR_POS); } + { $$ = makeInherit($2, $3, CUR_POS); } ; inheritsrc : '(' expr ')' { $$ = $2; } - | { $$ = ATmake("Scope"); } + | { $$ = makeScope(); } ; ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; }; @@ -158,8 +163,8 @@ formals ; formal - : ID { $$ = ATmake("NoDefFormal(<term>)", $1); } - | ID '?' expr { $$ = ATmake("DefFormal(<term>, <term>)", $1, $3); } + : ID { $$ = makeNoDefFormal($1); } + | ID '?' expr { $$ = makeDefFormal($1, $3); } ; %% diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index a51a5119af3d..e230d35ce6b1 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1,18 +1,18 @@ #include "normalise.hh" #include "eval.hh" #include "globals.hh" +#include "constructors.hh" /* Load and evaluate an expression from path specified by the argument. */ static Expr primImport(EvalState & state, const ATermVector & args) { - ATMatcher m; - string path; + ATerm path; Expr fn = evalExpr(state, args[0]); - if (!(atMatch(m, fn) >> "Path" >> path)) + if (!matchPath(fn, path)) 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); - ATMatcher m; - string s; + ATerm s; ATermList es; int n; Expr e1, e2; - if (atMatch(m, e) >> "Str" >> s) ss.push_back(s); - else if (atMatch(m, e) >> "Uri" >> s) ss.push_back(s); - else if (atMatch(m, e) >> "Bool" >> "True") ss.push_back("1"); - else if (atMatch(m, e) >> "Bool" >> "False") ss.push_back(""); + if (matchStr(e, s)) ss.push_back(aterm2String(s)); + else if (matchUri(e, s)) ss.push_back(aterm2String(s)); + else if (e == eTrue) ss.push_back("1"); + else if (e == eFalse) ss.push_back(""); - else if (atMatch(m, e) >> "Int" >> n) { + else if (matchInt(e, n)) { ostringstream st; st << n; ss.push_back(st.str()); } - else if (atMatch(m, e) >> "Attrs") { + else if (matchAttrs(e, es)) { Expr a = queryAttr(e, "type"); if (a && evalString(state, a) == "derivation") { a = queryAttr(e, "drvPath"); @@ -127,30 +126,29 @@ static void processBinding(EvalState & state, Expr e, StoreExpr & ne, throw Error("invalid derivation attribute"); } - else if (atMatch(m, e) >> "Path" >> s) { - Path drvPath = copyAtom(state, s); + else if (matchPath(e, s)) { + Path drvPath = copyAtom(state, aterm2String(s)); 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) { startNest(nest, lvlVomit, format("processing list element")); 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; processBinding(state, evalExpr(state, e1), ne, ss2); if (ss2.size() != 1) throw Error("left-hand side of `~' operator cannot be a list"); e2 = evalExpr(state, e2); - if (!(atMatch(m, e2) >> "Str" >> s || - (atMatch(m, e2) >> "Path" >> s))) + if (!(matchStr(e2, s) || matchPath(e2, s))) 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"); @@ -198,8 +196,7 @@ static Expr primDerivation(EvalState & state, const ATermVector & _args) ATerm value; Expr pos; ATerm rhs = attrs.get(key); - ATMatcher m; - if (!(atMatch(m, rhs) >> "" >> value >> pos)) abort(); + if (!matchAttrRHS(rhs, value, pos)) abort(); startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); Strings ss; @@ -272,10 +269,11 @@ static Expr primDerivation(EvalState & state, const ATermVector & _args) printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'") % drvName % drvPath); - attrs.set("outPath", ATmake("(Path(<str>), NoPos)", outPath.c_str())); - attrs.set("drvPath", ATmake("(Path(<str>), NoPos)", drvPath.c_str())); - attrs.set("drvHash", ATmake("(<term>, NoPos)", makeString(drvHash))); - attrs.set("type", ATmake("(<term>, NoPos)", makeString("derivation"))); + attrs.set("outPath", makeAttrRHS(makePath(string2ATerm(outPath.c_str())), makeNoPos())); + attrs.set("drvPath", makeAttrRHS(makePath(string2ATerm(drvPath.c_str())), makeNoPos())); + attrs.set("drvHash", + makeAttrRHS(makeStr(string2ATerm(((string) drvHash).c_str())), makeNoPos())); + attrs.set("type", makeAttrRHS(makeStr(string2ATerm("derivation")), makeNoPos())); return makeAttrs(attrs); } @@ -285,7 +283,7 @@ static Expr primDerivation(EvalState & state, const ATermVector & _args) following the last slash. */ 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) { Expr arg = evalExpr(state, args[0]); - ATMatcher m; - string s; - if (atMatch(m, arg) >> "Str" >> s || - atMatch(m, arg) >> "Path" >> s || - atMatch(m, arg) >> "Uri" >> s) - return makeString(s); + ATerm s; + if (matchStr(arg, s) || matchPath(arg, s) || matchUri(arg, s)) + return makeStr(s); else throw Error("cannot coerce value to string"); } @@ -306,29 +301,27 @@ static Expr primToString(EvalState & state, const ATermVector & args) /* Boolean constructors. */ static Expr primTrue(EvalState & state, const ATermVector & args) { - return ATmake("Bool(True)"); + return eTrue; } static Expr primFalse(EvalState & state, const ATermVector & args) { - return ATmake("Bool(False)"); + return eFalse; } /* Return the null value. */ Expr primNull(EvalState & state, const ATermVector & args) { - return ATmake("Null"); + return makeNull(); } /* Determine whether the argument is the null value. */ Expr primIsNull(EvalState & state, const ATermVector & args) { - Expr arg = evalExpr(state, args[0]); - ATMatcher m; - return makeBool(atMatch(m, arg) >> "Null"); + return makeBool(matchNull(evalExpr(state, args[0]))); } @@ -338,18 +331,15 @@ Expr primMap(EvalState & state, const ATermVector & args) Expr fun = evalExpr(state, args[0]); Expr list = evalExpr(state, args[1]); - ATMatcher m; - ATermList list2; - if (!(atMatch(m, list) >> "List" >> list2)) + if (!matchList(list, list2)) throw Error("`map' expects a list as its second argument"); ATermList list3 = ATempty; for (ATermIterator i(list2); i; ++i) - list3 = ATinsert(list3, - ATmake("Call(<term>, <term>)", fun, *i)); + list3 = ATinsert(list3, makeCall(fun, *i)); - return ATmake("List(<term>)", ATreverse(list3)); + return makeList(ATreverse(list3)); } |