* More primops.

This commit is contained in:
Eelco Dolstra 2010-03-30 14:39:27 +00:00
parent 5b72d8a749
commit c3aa615a5f
4 changed files with 56 additions and 97 deletions

View File

@ -56,10 +56,12 @@ void run(Strings args)
doTest("{ x = [ 1 2 ]; } == { x = [ 1 ] ++ [ 2 ]; }");
doTest("1 != 1");
doTest("true");
doTest("builtins.true");
doTest("true == false");
doTest("__head [ 1 2 3 ]");
doTest("__add 1 2");
doTest("null");
doTest("null");
doTest("\"foo\"");
doTest("let s = \"bar\"; in \"foo${s}\"");
doTest("if true then 1 else 2");
@ -67,9 +69,9 @@ void run(Strings args)
doTest("if false || true then 1 else 2");
doTest("let x = x; in if true || x then 1 else 2");
doTest("/etc/passwd");
doTest("import ./foo.nix");
//doTest("import ./foo.nix");
doTest("map (x: __add 1 x) [ 1 2 3 ]");
doTest("map (__add 1) [ 1 2 3 ]");
doTest("map (builtins.add 1) [ 1 2 3 ]");
}

View File

@ -95,14 +95,26 @@ EvalState::EvalState() : baseEnv(allocEnv())
}
void EvalState::addConstant(const string & name, Value & v)
{
baseEnv.bindings[toATerm(name)] = v;
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
(*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm(name2)] = v;
nrValues += 2;
}
void EvalState::addPrimOp(const string & name,
unsigned int arity, PrimOp primOp)
{
Value & v = baseEnv.bindings[toATerm(name)];
nrValues++;
Value v;
v.type = tPrimOp;
v.primOp.arity = arity;
v.primOp.fun = primOp;
baseEnv.bindings[toATerm(name)] = v;
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
(*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm(name2)] = v;
nrValues += 2;
}
@ -212,6 +224,14 @@ Env & EvalState::allocEnv()
}
void EvalState::mkList(Value & v, unsigned int length)
{
v.type = tList;
v.list.length = length;
v.list.elems = allocValues(length);
}
void EvalState::evalFile(const Path & path, Value & v)
{
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
@ -349,9 +369,7 @@ void EvalState::eval(Env & env, Expr e, Value & v)
}
if (matchList(e, es)) {
v.type = tList;
v.list.length = ATgetLength(es);
v.list.elems = allocValues(v.list.length);
mkList(v, ATgetLength(es));
for (unsigned int n = 0; n < v.list.length; ++n, es = ATgetNext(es))
mkThunk(v.list.elems[n], env, ATgetFirst(es));
return;
@ -376,9 +394,7 @@ void EvalState::eval(Env & env, Expr e, Value & v)
forceList(v1);
Value v2; eval(env, e2, v2);
forceList(v2);
v.type = tList;
v.list.length = v1.list.length + v2.list.length;
v.list.elems = allocValues(v.list.length);
mkList(v, v1.list.length + v2.list.length);
/* !!! This loses sharing with the original lists. We could
use a tCopy node, but that would use more memory. */
for (unsigned int n = 0; n < v1.list.length; ++n)

View File

@ -196,6 +196,8 @@ private:
void createBaseEnv();
void addConstant(const string & name, Value & v);
void addPrimOp(const string & name,
unsigned int arity, PrimOp primOp);
@ -210,6 +212,8 @@ public:
/* Allocation primitives. */
Value * allocValues(unsigned int count);
Env & allocEnv();
void mkList(Value & v, unsigned int length);
};

View File

@ -20,63 +20,6 @@
namespace nix {
#if 0
/*************************************************************
* Constants
*************************************************************/
static Expr prim_builtins(EvalState & state, const ATermVector & args)
{
/* Return an attribute set containing all primops. This allows
Nix expressions to test for new primops and take appropriate
action if they're not available. For instance, rather than
calling a primop `foo' directly, they could say `if builtins ?
foo then builtins.foo ... else ...'. */
ATermMap builtins(state.primOps.size());
for (ATermMap::const_iterator i = state.primOps.begin();
i != state.primOps.end(); ++i)
{
string name = aterm2String(i->key);
if (string(name, 0, 2) == "__")
name = string(name, 2);
/* !!! should use makePrimOp here, I guess. */
builtins.set(toATerm(name), makeAttrRHS(makeVar(i->key), makeNoPos()));
}
return makeAttrs(builtins);
}
/* Boolean constructors. */
static Expr prim_true(EvalState & state, const ATermVector & args)
{
return eTrue;
}
static Expr prim_false(EvalState & state, const ATermVector & args)
{
return eFalse;
}
/* Return the null value. */
static Expr prim_null(EvalState & state, const ATermVector & args)
{
return makeNull();
}
static Expr prim_currentTime(EvalState & state, const ATermVector & args)
{
return ATmake("Int(<int>)", time(0));
}
#endif
/*************************************************************
* Miscellaneous
*************************************************************/
@ -903,17 +846,17 @@ static void prim_head(EvalState & state, Value * * args, Value & v)
}
#if 0
/* Return a list consisting of everything but the the first element of
a list. */
static Expr prim_tail(EvalState & state, const ATermVector & args)
static void prim_tail(EvalState & state, Value * * args, Value & v)
{
ATermList list = evalList(state, args[0]);
if (ATisEmpty(list))
state.forceList(*args[0]);
if (args[0]->list.length == 0)
throw Error("`tail' called on an empty list");
return makeList(ATgetNext(list));
state.mkList(v, args[0]->list.length - 1);
for (unsigned int n = 0; n < v.list.length; ++n)
v.list.elems[n] = args[0]->list.elems[n + 1];
}
#endif
/* Apply a function to every element of a list. */
@ -922,9 +865,7 @@ static void prim_map(EvalState & state, Value * * args, Value & v)
state.forceFunction(*args[0]);
state.forceList(*args[1]);
v.type = tList;
v.list.length = args[1]->list.length;
v.list.elems = state.allocValues(v.list.length);
state.mkList(v, args[1]->list.length);
for (unsigned int n = 0; n < v.list.length; ++n) {
v.list.elems[n].type = tApp;
@ -1121,28 +1062,26 @@ void EvalState::createBaseEnv()
v.type = tAttrs;
v.attrs = new Bindings;
}
/* Add global constants such as `true' to the base environment. */
{ Value & v = baseEnv.bindings[toATerm("true")];
mkBool(v, true);
}
{ Value & v = baseEnv.bindings[toATerm("false")];
mkBool(v, false);
}
{ Value & v = baseEnv.bindings[toATerm("null")];
v.type = tNull;
}
{ Value & v = (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm("currentSystem")];
mkString(v, strdup(thisSystem.c_str()));
}
#if 0
// Constants
addPrimOp("__currentSystem", 0, prim_currentSystem);
addPrimOp("__currentTime", 0, prim_currentTime);
/* Add global constants such as `true' to the base environment. */
Value v;
mkBool(v, true);
addConstant("true", v);
mkBool(v, false);
addConstant("false", v);
v.type = tNull;
addConstant("null", v);
mkInt(v, time(0));
addConstant("__currentTime", v);
mkString(v, strdup(thisSystem.c_str()));
addConstant("__currentSystem", v);
// Miscellaneous
#endif
addPrimOp("import", 1, prim_import);
#if 0
addPrimOp("isNull", 1, prim_isNull);
@ -1193,9 +1132,7 @@ void EvalState::createBaseEnv()
addPrimOp("__isList", 1, prim_isList);
#endif
addPrimOp("__head", 1, prim_head);
#if 0
addPrimOp("__tail", 1, prim_tail);
#endif
addPrimOp("map", 2, prim_map);
#if 0
addPrimOp("__length", 1, prim_length);