Add sugar for defining a variable

‘x = <expr>’ is short for ‘:a { x = <expr>; }’.  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.
This commit is contained in:
Eelco Dolstra 2013-09-09 13:56:53 +02:00
parent 4b33c2dd4c
commit 3c67df928f

View file

@ -42,7 +42,7 @@ struct NixRepl
void processLine(string line); void processLine(string line);
void loadFile(const Path & path); void loadFile(const Path & path);
void addAttrsToScope(Value & attrs); void addAttrsToScope(Value & attrs);
void addVarToScope(const Symbol & name, Value * v); void addVarToScope(const Symbol & name, Value & v);
Expr * parseString(string s); Expr * parseString(string s);
void evalString(string s, Value & v); 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) void NixRepl::processLine(string line)
{ {
if (line == "") return; if (line == "") return;
@ -251,13 +264,14 @@ void NixRepl::processLine(string line)
if (command == ":?") { if (command == ":?") {
cout << "The following commands are available:\n" cout << "The following commands are available:\n"
<< "\n" << "\n"
<< " <expr> Evaluate and print expression\n" << " <expr> Evaluate and print expression\n"
<< " :a <expr> Add attributes from resulting set to scope\n" << " <x> = <expr> Bind expression to variable\n"
<< " :b <expr> Build derivation\n" << " :a <expr> Add attributes from resulting set to scope\n"
<< " :l <path> Load Nix expression and add it to scope\n" << " :b <expr> Build derivation\n"
<< " :p <expr> Evaluate and print expression recursively\n" << " :l <path> Load Nix expression and add it to scope\n"
<< " :s <expr> Build dependencies of derivation, then start nix-shell\n" << " :p <expr> Evaluate and print expression recursively\n"
<< " :t <expr> Describe result of evaluation\n"; << " :s <expr> Build dependencies of derivation, then start nix-shell\n"
<< " :t <expr> Describe result of evaluation\n";
} }
else if (command == ":a") { else if (command == ":a") {
@ -310,9 +324,22 @@ void NixRepl::processLine(string line)
throw Error(format("unknown command %1%") % string(line, 0, 2)); throw Error(format("unknown command %1%") % string(line, 0, 2));
else { else {
Value v; size_t p = line.find('=');
evalString(line, v); string name;
printValue(std::cout, v, 1) << std::endl; 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); state.forceAttrs(attrs);
foreach (Bindings::iterator, i, *attrs.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; 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; staticEnv.vars[name] = displ;
env->values[displ++] = v; env->values[displ++] = &v;
varNames.insert((string) name); varNames.insert((string) name);
} }