about summary refs log tree commit diff
path: root/src/libexpr
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/eval.cc68
-rw-r--r--src/libexpr/eval.hh11
-rw-r--r--src/libexpr/nixexpr.cc23
-rw-r--r--src/libexpr/nixexpr.hh9
-rw-r--r--src/libexpr/parser.cc24
-rw-r--r--src/libexpr/parser.hh6
-rw-r--r--src/libexpr/primops.cc12
-rw-r--r--src/libexpr/primops.hh6
8 files changed, 121 insertions, 38 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index bbb1393f8388..802b83aa160d 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -3,12 +3,52 @@
 #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()
-    : normalForms(32768, 75)
+    : normalForms(32768, 50)
 {
     blackHole = ATmake("BlackHole()");
     if (!blackHole) throw Error("cannot build black hole");
+    
     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);
+}
+
+
+void EvalState::addPrimOp0(const string & name, PrimOp0 primOp)
+{
+    addPrimOp(primOps0, name, (void *) primOp);
+}
+
+
+void EvalState::addPrimOp1(const string & name, PrimOp1 primOp)
+{
+    addPrimOp(primOps1, name, (void *) primOp);
 }
 
 
@@ -130,7 +170,7 @@ Expr evalExpr2(EvalState & state, Expr e)
 {
     ATMatcher m;
     Expr e1, e2, e3, e4;
-    string s1;
+    ATerm name;
 
     /* Normal forms. */
     if (atMatch(m, e) >> "Str" ||
@@ -144,11 +184,12 @@ Expr evalExpr2(EvalState & state, Expr e)
         return e;
 
     /* Any encountered variables must be undeclared or primops. */
-    if (atMatch(m, e) >> "Var" >> s1) {
-        if (s1 == "null") return primNull(state);
-        if (s1 == "true") return ATmake("Bool(True)");
-        if (s1 == "false") return ATmake("Bool(False)");
-        return e;
+    if (atMatch(m, e) >> "Var" >> name) {
+        PrimOp0 primOp = (PrimOp0) lookupPrimOp(state.primOps0, name);
+        if (primOp)
+            return primOp(state);
+        else
+            return e;
     }
 
     /* Function application. */
@@ -160,13 +201,9 @@ Expr evalExpr2(EvalState & state, Expr e)
         e1 = evalExpr(state, e1);
 
         /* Is it a primop or a function? */
-        if (atMatch(m, e1) >> "Var" >> s1) {
-            if (s1 == "import") return primImport(state, e2);
-            if (s1 == "derivation") return primDerivation(state, e2);
-            if (s1 == "toString") return primToString(state, e2);
-            if (s1 == "baseNameOf") return primBaseNameOf(state, e2);
-            if (s1 == "isNull") return primIsNull(state, e2);
-            else throw badTerm("undefined variable/primop", e1);
+        if (atMatch(m, e1) >> "Var" >> name) {
+            PrimOp1 primOp = (PrimOp1) lookupPrimOp(state.primOps1, name);
+            if (primOp) return primOp(state, e2); else abort();
         }
 
         else if (atMatch(m, e1) >> "Function" >> formals >> e4)
@@ -177,6 +214,7 @@ Expr evalExpr2(EvalState & state, Expr e)
     }
 
     /* Attribute selection. */
+    string s1;
     if (atMatch(m, e) >> "Select" >> e1 >> s1) {
         Expr a = queryAttr(evalExpr(state, e1), s1);
         if (!a) throw badTerm(format("missing attribute `%1%'") % s1, e);
@@ -261,7 +299,7 @@ Expr evalExpr(EvalState & state, Expr e)
 Expr evalFile(EvalState & state, const Path & path)
 {
     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
-    Expr e = parseExprFromFile(path);
+    Expr e = parseExprFromFile(state, path);
     return evalExpr(state, e);
 }
 
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 0bc052676deb..34ac467f1d80 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -11,9 +11,17 @@
 typedef map<Path, PathSet> DrvPaths;
 typedef map<Path, Hash> DrvHashes;
 
+struct EvalState;
+typedef Expr (* PrimOp0) (EvalState &);
+typedef Expr (* PrimOp1) (EvalState &, Expr arg);
+
+
 struct EvalState 
 {
     ATermMap normalForms;
+    ATermMap primOps0; /* nullary primops */
+    ATermMap primOps1; /* unary primops */
+    ATermMap primOpsAll;
     DrvPaths drvPaths;
     DrvHashes drvHashes; /* normalised derivation hashes */
     Expr blackHole;
@@ -22,6 +30,9 @@ struct EvalState
     unsigned int nrCached;
 
     EvalState();
+
+    void addPrimOp0(const string & name, PrimOp0 primOp);
+    void addPrimOp1(const string & name, PrimOp1 primOp);
 };
 
 
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 92027a70ebd7..7739e99a96be 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -20,8 +20,7 @@ ATermMap::ATermMap(const ATermMap & map)
     table = ATtableCreate(ATgetLength(keys), maxLoadPct);
     if (!table) throw Error("cannot create ATerm table");
 
-    for (ATermIterator i(keys); i; ++i)
-        set(*i, map.get(*i));
+    add(map, keys);
 }
 
 
@@ -75,6 +74,26 @@ ATermList ATermMap::keys() const
 }
 
 
+void ATermMap::add(const ATermMap & map)
+{
+    ATermList keys = map.keys();
+    add(map, keys);
+}
+
+
+void ATermMap::add(const ATermMap & map, ATermList & keys)
+{
+    for (ATermIterator i(keys); i; ++i)
+        set(*i, map.get(*i));
+}
+
+
+void ATermMap::reset()
+{
+    ATtableReset(table);
+}
+
+
 ATerm string2ATerm(const string & s)
 {
     return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue));
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index 26c29a2f38b1..924f8b912f77 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -23,7 +23,7 @@ private:
     ATermTable table;
     
 public:
-    ATermMap(unsigned int initialSize = 16, unsigned int maxLoadPct = 75);
+    ATermMap(unsigned int initialSize = 64, unsigned int maxLoadPct = 75);
     ATermMap(const ATermMap & map);
     ~ATermMap();
 
@@ -37,6 +37,13 @@ public:
     void remove(const string & key);
 
     ATermList keys() const;
+
+    void add(const ATermMap & map);
+    
+    void reset();
+
+private:
+    void add(const ATermMap & map, ATermList & keys);
 };
 
 
diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc
index 0a550fb35507..68b367340acf 100644
--- a/src/libexpr/parser.cc
+++ b/src/libexpr/parser.cc
@@ -66,7 +66,8 @@ int yyparse(yyscan_t scanner, ParseData * data);
 }
 
 
-static Expr parse(const char * text, const string & location,
+static Expr parse(EvalState & state,
+    const char * text, const string & location,
     const Path & basePath)
 {
     yyscan_t scanner;
@@ -81,18 +82,8 @@ static Expr parse(const char * text, const string & location,
     
     if (res) throw Error(data.error);
 
-    ATermMap primOps;
-    primOps.set("import", (ATerm) ATempty);
-    primOps.set("derivation", (ATerm) ATempty);
-    primOps.set("true", (ATerm) ATempty);
-    primOps.set("false", (ATerm) ATempty);
-    primOps.set("null", (ATerm) ATempty);
-    primOps.set("isNull", (ATerm) ATempty);
-    primOps.set("toString", (ATerm) ATempty);
-    primOps.set("baseNameOf", (ATerm) ATempty);
-
     try {
-        checkVarDefs(primOps, data.result);
+        checkVarDefs(state.primOpsAll, data.result);
     } catch (Error & e) {
         throw Error(format("%1%, in %2%") % e.msg() % location);
     }
@@ -101,7 +92,7 @@ static Expr parse(const char * text, const string & location,
 }
 
 
-Expr parseExprFromFile(Path path)
+Expr parseExprFromFile(EvalState & state, Path path)
 {
     assert(path[0] == '/');
 
@@ -137,11 +128,12 @@ Expr parseExprFromFile(Path path)
     readFull(fd, (unsigned char *) text, st.st_size);
     text[st.st_size] = 0;
 
-    return parse(text, "`" + path + "'", dirOf(path));
+    return parse(state, text, "`" + path + "'", dirOf(path));
 }
 
 
-Expr parseExprFromString(const string & s, const Path & basePath)
+Expr parseExprFromString(EvalState & state,
+    const string & s, const Path & basePath)
 {
-    return parse(s.c_str(), "(string)", basePath);
+    return parse(state, s.c_str(), "(string)", basePath);
 }
diff --git a/src/libexpr/parser.hh b/src/libexpr/parser.hh
index 461dae08cd92..2af5385f6275 100644
--- a/src/libexpr/parser.hh
+++ b/src/libexpr/parser.hh
@@ -1,15 +1,15 @@
 #ifndef __PARSER_H
 #define __PARSER_H
 
-#include "nixexpr.hh"
+#include "eval.hh"
 
 
 /* Parse a Nix expression from the specified file.  If `path' refers
    to a directory, the "/default.nix" is appended. */
-Expr parseExprFromFile(Path path);
+Expr parseExprFromFile(EvalState & state, Path path);
 
 /* Parse a Nix expression from the specified string. */
-Expr parseExprFromString(const string & s,
+Expr parseExprFromString(EvalState & state, const string & s,
     const Path & basePath);
 
 
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index d1c398a34831..92683fcac53d 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -245,6 +245,18 @@ Expr primToString(EvalState & state, Expr arg)
 }
 
 
+Expr primTrue(EvalState & state)
+{
+    return ATmake("Bool(True)");
+}
+
+
+Expr primFalse(EvalState & state)
+{
+    return ATmake("Bool(False)");
+}
+
+
 Expr primNull(EvalState & state)
 {
     return ATmake("Null");
diff --git a/src/libexpr/primops.hh b/src/libexpr/primops.hh
index 76d587afdb1e..6b9722dac38e 100644
--- a/src/libexpr/primops.hh
+++ b/src/libexpr/primops.hh
@@ -8,7 +8,7 @@
    argument. */ 
 Expr primImport(EvalState & state, Expr arg);
 
-/* Construct (as a unobservable) side effect) a Nix derivation
+/* 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
@@ -24,6 +24,10 @@ 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);