about summary refs log tree commit diff
path: root/nix-repl.cc
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-09-02T15·53+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-09-02T15·53+0200
commit287c88ca59c5eae2b33874acc6271ca30b7b7e52 (patch)
tree459bda1e7b81dade3408fc3e184bbf5e92bc283d /nix-repl.cc
parente90569905ecdfe3225314f0e5f122263aa68efb2 (diff)
Support adding variables to the scope
The command ":a <expr>" evaluates <expr> and adds the attributes in
the resulting attribute set to the interpreter scope.  For instance:

nix-repl> :a import <nixpkgs> {}

nix-repl> lib.range 0 10
[ 0 1 2 3 4 5 6 7 8 9 10 ]
Diffstat (limited to 'nix-repl.cc')
-rw-r--r--nix-repl.cc95
1 files changed, 86 insertions, 9 deletions
diff --git a/nix-repl.cc b/nix-repl.cc
index ea248b5ca15f..10e91ec5328e 100644
--- a/nix-repl.cc
+++ b/nix-repl.cc
@@ -6,6 +6,8 @@
 
 #include "shared.hh"
 #include "eval.hh"
+#include "eval-inline.hh"
+#include "store-api.hh"
 
 using namespace std;
 using namespace nix;
@@ -14,6 +16,23 @@ using namespace nix;
 string programId = "nix-repl";
 
 
+struct NixRepl
+{
+    string curDir;
+    EvalState state;
+
+    StaticEnv staticEnv;
+    Env * env;
+    int displ;
+
+    NixRepl();
+    void mainLoop();
+    void processLine(string line);
+    void addVar(const Symbol & name, Value * v);
+    Expr * parseString(string s);
+};
+
+
 void printHelp()
 {
     std::cout << "Usage: nix-repl\n";
@@ -22,7 +41,7 @@ void printHelp()
 
 bool getLine(string & line)
 {
-    char * s = readline ("nix-repl> ");
+    char * s = readline("nix-repl> ");
     if (!s) return false;
     line = chomp(string(s));
     free(s);
@@ -31,21 +50,33 @@ bool getLine(string & line)
 }
 
 
-void run(nix::Strings args)
+NixRepl::NixRepl()
+    : staticEnv(false, &state.staticBaseEnv)
 {
-    EvalState state;
-    Path curDir = absPath(".");
+    curDir = absPath(".");
+
+    env = &state.allocEnv(32768);
+    env->up = &state.baseEnv;
+    displ = 0;
+
+    store = openStore();
+}
+
+
+void NixRepl::mainLoop()
+{
+    std::cerr << "Welcome to Nix version " << NIX_VERSION << ". Type :? for help." << std::endl << std::endl;
 
     while (true) {
         string line;
         if (!getLine(line)) break;
 
+        /* Remove preceeding whitespace. */
+        size_t n = line.find_first_not_of(" \n\r\t");
+        if (n != string::npos) line = string(line, n);
+
         try {
-            Expr * e = state.parseExprFromString(line, curDir);
-            Value v;
-            state.eval(e, v);
-            state.strictForceValue(v);
-            std::cout << v << std::endl;
+            processLine(line);
         } catch (Error & e) {
             printMsg(lvlError, e.msg());
         }
@@ -55,3 +86,49 @@ void run(nix::Strings args)
 
     std::cout << std::endl;
 }
+
+
+void NixRepl::processLine(string line)
+{
+    if (string(line, 0, 2) == ":a") {
+        Expr * e = parseString(string(line, 2));
+        Value v;
+        e->eval(state, *env, v);
+        state.forceAttrs(v);
+        foreach (Bindings::iterator, i, *v.attrs)
+            addVar(i->name, i->value);
+    }
+
+    else if (string(line, 0, 1) == ":") {
+        throw Error(format("unknown command ‘%1%’") % string(line, 0, 2));
+    }
+
+    else {
+        Expr * e = parseString(line);
+        Value v;
+        e->eval(state, *env, v);
+        state.strictForceValue(v);
+        std::cout << v << std::endl;
+    }
+}
+
+
+void NixRepl::addVar(const Symbol & name, Value * v)
+{
+    staticEnv.vars[name] = displ;
+    env->values[displ++] = v;
+}
+
+
+Expr * NixRepl::parseString(string s)
+{
+    Expr * e = state.parseExprFromString(s, curDir, staticEnv);
+    return e;
+}
+
+
+void run(nix::Strings args)
+{
+    NixRepl repl;
+    repl.mainLoop();
+}