From 3c67df928f8d311d7dfd565e8c3a16db9d6a0278 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 13:56:53 +0200 Subject: [PATCH] Add sugar for defining a variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ‘x = ’ is short for ‘:a { x = ; }’. Note that the right-hand side refers to the original scope, so you get: nix-repl> x = 1 nix-repl> x = x + 1 nix-repl> x 2 rather than an infinite recursion. --- nix-repl.cc | 55 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 72099f46e..bcd80ffc7 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -42,7 +42,7 @@ struct NixRepl void processLine(string line); void loadFile(const Path & path); void addAttrsToScope(Value & attrs); - void addVarToScope(const Symbol & name, Value * v); + void addVarToScope(const Symbol & name, Value & v); Expr * parseString(string s); void evalString(string s, Value & v); @@ -242,6 +242,19 @@ static int runProgram(const string & program, const Strings & args) } +bool isVarName(const string & s) +{ + // FIXME: not quite correct. + foreach (string::const_iterator, i, s) + if (!((*i >= 'a' && *i <= 'z') || + (*i >= 'A' && *i <= 'Z') || + (*i >= '0' && *i <= '9') || + *i == '_' || *i == '\'')) + return false; + return true; +} + + void NixRepl::processLine(string line) { if (line == "") return; @@ -251,13 +264,14 @@ void NixRepl::processLine(string line) if (command == ":?") { cout << "The following commands are available:\n" << "\n" - << " Evaluate and print expression\n" - << " :a Add attributes from resulting set to scope\n" - << " :b Build derivation\n" - << " :l Load Nix expression and add it to scope\n" - << " :p Evaluate and print expression recursively\n" - << " :s Build dependencies of derivation, then start nix-shell\n" - << " :t Describe result of evaluation\n"; + << " Evaluate and print expression\n" + << " = Bind expression to variable\n" + << " :a Add attributes from resulting set to scope\n" + << " :b Build derivation\n" + << " :l Load Nix expression and add it to scope\n" + << " :p Evaluate and print expression recursively\n" + << " :s Build dependencies of derivation, then start nix-shell\n" + << " :t Describe result of evaluation\n"; } else if (command == ":a") { @@ -310,9 +324,22 @@ void NixRepl::processLine(string line) throw Error(format("unknown command ‘%1%’") % string(line, 0, 2)); else { - Value v; - evalString(line, v); - printValue(std::cout, v, 1) << std::endl; + size_t p = line.find('='); + string name; + if (p != string::npos && + isVarName(name = removeWhitespace(string(line, 0, p)))) + { + Expr * e = parseString(string(line, p + 1)); + Value & v(*state.allocValue()); + v.type = tThunk; + v.thunk.env = env; + v.thunk.expr = e; + addVarToScope(state.symbols.create(name), v); + } else { + Value v; + evalString(line, v); + printValue(std::cout, v, 1) << std::endl; + } } } @@ -331,15 +358,15 @@ void NixRepl::addAttrsToScope(Value & attrs) { state.forceAttrs(attrs); foreach (Bindings::iterator, i, *attrs.attrs) - addVarToScope(i->name, i->value); + addVarToScope(i->name, *i->value); std::cout << format("Added %1% variables.") % attrs.attrs->size() << std::endl; } -void NixRepl::addVarToScope(const Symbol & name, Value * v) +void NixRepl::addVarToScope(const Symbol & name, Value & v) { staticEnv.vars[name] = displ; - env->values[displ++] = v; + env->values[displ++] = &v; varNames.insert((string) name); }