From bbfdd64741546863c2412d780097b1fe2457395e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 4 Aug 2004 10:59:20 +0000 Subject: [PATCH] * Allow primops with more that 1 arguments. --- src/libexpr/Makefile.am | 2 +- src/libexpr/eval.cc | 81 +++++++++++++++++++---------------------- src/libexpr/eval.hh | 15 ++++---- src/libexpr/nixexpr.hh | 6 +++ src/libexpr/parser.cc | 2 +- src/libexpr/primops.cc | 62 ++++++++++++++++++++++++------- src/libexpr/primops.hh | 38 ------------------- 7 files changed, 102 insertions(+), 104 deletions(-) delete mode 100644 src/libexpr/primops.hh diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am index f3ffb6a03..45145a6bd 100644 --- a/src/libexpr/Makefile.am +++ b/src/libexpr/Makefile.am @@ -1,7 +1,7 @@ noinst_LIBRARIES = libexpr.a libexpr_a_SOURCES = nixexpr.cc nixexpr.hh parser.cc parser.hh \ - eval.cc eval.hh primops.cc primops.hh \ + eval.cc eval.hh primops.cc \ lexer-tab.c lexer-tab.h parser-tab.c parser-tab.h EXTRA_DIST = lexer.l parser.y diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index af0ab913c..37677d3cb 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1,20 +1,5 @@ #include "eval.hh" #include "parser.hh" -#include "primops.hh" - - -static void addPrimOp(ATermMap & map, const string & name, void * f) -{ - map.set(name, (ATerm) ATmakeBlob(0, f)); -} - - -static void * lookupPrimOp(ATermMap & map, ATerm name) -{ - ATermBlob b = (ATermBlob) map.get(name); - if (!b) return 0; - return ATgetBlobData(b); -} EvalState::EvalState() @@ -25,30 +10,15 @@ EvalState::EvalState() nrEvaluated = nrCached = 0; - addPrimOp0("true", primTrue); - addPrimOp0("false", primFalse); - addPrimOp0("null", primNull); - - addPrimOp1("import", primImport); - addPrimOp1("derivation", primDerivation); - addPrimOp1("baseNameOf", primBaseNameOf); - addPrimOp1("toString", primToString); - addPrimOp1("isNull", primIsNull); - - primOpsAll.add(primOps0); - primOpsAll.add(primOps1); + addPrimOps(); } -void EvalState::addPrimOp0(const string & name, PrimOp0 primOp) +void EvalState::addPrimOp(const string & name, + unsigned int arity, PrimOp primOp) { - addPrimOp(primOps0, name, (void *) primOp); -} - - -void EvalState::addPrimOp1(const string & name, PrimOp1 primOp) -{ - addPrimOp(primOps1, name, (void *) primOp); + primOps.set(name, ATmake("(, )", + arity, ATmakeBlob(0, (void *) primOp))); } @@ -200,7 +170,8 @@ Expr evalExpr2(EvalState & state, Expr e) cons == "Function" || cons == "Function1" || cons == "Attrs" || - cons == "List")) + cons == "List" || + cons == "PrimOp")) return e; /* The `Closed' constructor is just a way to prevent substitutions @@ -208,13 +179,21 @@ Expr evalExpr2(EvalState & state, Expr e) if (atMatch(m, e) >> "Closed" >> e1) return evalExpr(state, e1); - /* Any encountered variables must be undeclared or primops. */ + /* Any encountered variables must be primops (since undefined + variables are detected after parsing). */ if (atMatch(m, e) >> "Var" >> name) { - PrimOp0 primOp = (PrimOp0) lookupPrimOp(state.primOps0, name); - if (primOp) - return primOp(state); + 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(); + if (arity == 0) + return ((PrimOp) ATgetBlobData((ATermBlob) fun)) + (state, ATermVector()); else - return e; + return ATmake("PrimOp(, , )", + arity, fun, ATempty); } /* Function application. */ @@ -227,9 +206,23 @@ Expr evalExpr2(EvalState & state, Expr e) e1 = evalExpr(state, e1); /* Is it a primop or a function? */ - if (atMatch(m, e1) >> "Var" >> name) { - PrimOp1 primOp = (PrimOp1) lookupPrimOp(state.primOps1, name); - if (primOp) return primOp(state, e2); else abort(); + int arity; + ATerm fun; + ATermList args; + if (atMatch(m, e1) >> "PrimOp" >> arity >> fun >> args) { + args = ATinsert(args, e2); + if (ATgetLength(args) == arity) { + /* Put the arguments in a vector in reverse (i.e., + actual) order. */ + ATermVector args2(arity); + for (ATermIterator i(args); i; ++i) + args2[--arity] = *i; + return ((PrimOp) ATgetBlobData((ATermBlob) fun)) + (state, args2); + } else + /* Need more arguments, so propagate the primop. */ + return ATmake("PrimOp(, , )", + arity, fun, args); } else if (atMatch(m, e1) >> "Function" >> formals >> e4 >> pos) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 34ac467f1..b51a5b079 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -12,16 +12,16 @@ typedef map DrvPaths; typedef map DrvHashes; struct EvalState; -typedef Expr (* PrimOp0) (EvalState &); -typedef Expr (* PrimOp1) (EvalState &, Expr arg); + +/* Note: using a ATermVector is safe here, since when we call a primop + we also have an ATermList on the stack. */ +typedef Expr (* PrimOp) (EvalState &, const ATermVector & args); struct EvalState { ATermMap normalForms; - ATermMap primOps0; /* nullary primops */ - ATermMap primOps1; /* unary primops */ - ATermMap primOpsAll; + ATermMap primOps; DrvPaths drvPaths; DrvHashes drvHashes; /* normalised derivation hashes */ Expr blackHole; @@ -31,8 +31,9 @@ struct EvalState EvalState(); - void addPrimOp0(const string & name, PrimOp0 primOp); - void addPrimOp1(const string & name, PrimOp1 primOp); + void addPrimOps(); + void addPrimOp(const string & name, + unsigned int arity, PrimOp primOp); }; diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index ecd253408..30145c87b 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -47,6 +47,12 @@ private: }; +/* A STL vector of ATerms. Should be used with great care since it's + stored on the heap, and the elements are therefore not roots to the + ATerm garbage collector. */ +typedef vector ATermVector; + + /* Convert a string to an ATerm (i.e., a quoted nullary function applicaton). */ ATerm string2ATerm(const string & s); diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc index 2e561c95e..90e008473 100644 --- a/src/libexpr/parser.cc +++ b/src/libexpr/parser.cc @@ -95,7 +95,7 @@ static Expr parse(EvalState & state, if (res) throw Error(data.error); try { - checkVarDefs(state.primOpsAll, data.result); + checkVarDefs(state.primOps, data.result); } catch (Error & e) { throw Error(format("%1%, in `%2%'") % e.msg() % path); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index b0a0a2761..e97c636b8 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1,13 +1,15 @@ -#include "primops.hh" #include "normalise.hh" +#include "eval.hh" #include "globals.hh" -Expr primImport(EvalState & state, Expr arg) +/* Load and evaluate an expression from path specified by the + argument. */ +static Expr primImport(EvalState & state, const ATermVector & args) { ATMatcher m; string path; - if (!(atMatch(m, arg) >> "Path" >> path)) + if (!(atMatch(m, args[0]) >> "Path" >> path)) throw Error("path expected"); return evalFile(state, path); } @@ -158,11 +160,19 @@ static string concatStrings(const Strings & ss) } -Expr primDerivation(EvalState & state, Expr args) +/* Construct (as a unobservable side effect) a Nix derivation + expression that performs the derivation described by the argument + set. Returns the original set extended with the following + attributes: `outPath' containing the primary output path of the + derivation; `drvPath' containing the path of the Nix expression; + and `type' set to `derivation' to indicate that this is a + derivation. */ +static Expr primDerivation(EvalState & state, const ATermVector & _args) { startNest(nest, lvlVomit, "evaluating derivation"); ATermMap attrs; + Expr args = _args[0]; args = evalExpr(state, args); queryAllAttrs(args, attrs, true); @@ -251,16 +261,19 @@ Expr primDerivation(EvalState & state, Expr args) } -Expr primBaseNameOf(EvalState & state, Expr arg) +/* Return the base name of the given string, i.e., everything + following the last slash. */ +static Expr primBaseNameOf(EvalState & state, const ATermVector & args) { - string s = evalString(state, arg); + string s = evalString(state, args[0]); return ATmake("Str()", baseNameOf(s).c_str()); } -Expr primToString(EvalState & state, Expr arg) +/* Convert the argument (which can be a path or a uri) to a string. */ +static Expr primToString(EvalState & state, const ATermVector & args) { - arg = evalExpr(state, arg); + Expr arg = evalExpr(state, args[0]); ATMatcher m; string s; if (atMatch(m, arg) >> "Str" >> s || @@ -271,27 +284,50 @@ Expr primToString(EvalState & state, Expr arg) } -Expr primTrue(EvalState & state) +/* Boolean constructors. */ +static Expr primTrue(EvalState & state, const ATermVector & args) { return ATmake("Bool(True)"); } -Expr primFalse(EvalState & state) +static Expr primFalse(EvalState & state, const ATermVector & args) { return ATmake("Bool(False)"); } -Expr primNull(EvalState & state) +/* Return the null value. */ +Expr primNull(EvalState & state, const ATermVector & args) { return ATmake("Null"); } -Expr primIsNull(EvalState & state, Expr arg) +/* Determine whether the argument is the null value. */ +Expr primIsNull(EvalState & state, const ATermVector & args) { - arg = evalExpr(state, arg); + Expr arg = evalExpr(state, args[0]); ATMatcher m; return makeBool(atMatch(m, arg) >> "Null"); } + + +/* Apply a function to every element of a list. */ +Expr primMap(EvalState & state, Expr fun, Expr list) +{ +} + + +void EvalState::addPrimOps() +{ + addPrimOp("true", 0, primTrue); + addPrimOp("false", 0, primFalse); + addPrimOp("null", 0, primNull); + + addPrimOp("import", 1, primImport); + addPrimOp("derivation", 1, primDerivation); + addPrimOp("baseNameOf", 1, primBaseNameOf); + addPrimOp("toString", 1, primToString); + addPrimOp("isNull", 1, primIsNull); +} diff --git a/src/libexpr/primops.hh b/src/libexpr/primops.hh deleted file mode 100644 index 6b9722dac..000000000 --- a/src/libexpr/primops.hh +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __PRIMOPS_H -#define __PRIMOPS_H - -#include "eval.hh" - - -/* Load and evaluate an expression from path specified by the - argument. */ -Expr primImport(EvalState & state, Expr arg); - -/* Construct (as a unobservable side effect) a Nix derivation - expression that performs the derivation described by the argument - set. Returns the original set extended with the following - attributes: `outPath' containing the primary output path of the - derivation; `drvPath' containing the path of the Nix expression; - and `type' set to `derivation' to indicate that this is a - derivation. */ -Expr primDerivation(EvalState & state, Expr args); - -/* Return the base name of the given string, i.e., everything - following the last slash. */ -Expr primBaseNameOf(EvalState & state, Expr arg); - -/* Convert the argument (which can be a path or a uri) to a string. */ -Expr primToString(EvalState & state, Expr arg); - -/* Boolean constructors. */ -Expr primTrue(EvalState & state); -Expr primFalse(EvalState & state); - -/* Return the null value. */ -Expr primNull(EvalState & state); - -/* Determine whether the argument is the null value. */ -Expr primIsNull(EvalState & state, Expr arg); - - -#endif /* !__PRIMOPS_H */