* 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("{ x = [ 1 2 ]; } == { x = [ 1 ] ++ [ 2 ]; }");
doTest("1 != 1"); doTest("1 != 1");
doTest("true"); doTest("true");
doTest("builtins.true");
doTest("true == false"); doTest("true == false");
doTest("__head [ 1 2 3 ]"); doTest("__head [ 1 2 3 ]");
doTest("__add 1 2"); doTest("__add 1 2");
doTest("null"); doTest("null");
doTest("null");
doTest("\"foo\""); doTest("\"foo\"");
doTest("let s = \"bar\"; in \"foo${s}\""); doTest("let s = \"bar\"; in \"foo${s}\"");
doTest("if true then 1 else 2"); doTest("if true then 1 else 2");
@ -67,9 +69,9 @@ void run(Strings args)
doTest("if false || true then 1 else 2"); doTest("if false || true then 1 else 2");
doTest("let x = x; in if true || x then 1 else 2"); doTest("let x = x; in if true || x then 1 else 2");
doTest("/etc/passwd"); doTest("/etc/passwd");
doTest("import ./foo.nix"); //doTest("import ./foo.nix");
doTest("map (x: __add 1 x) [ 1 2 3 ]"); 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, void EvalState::addPrimOp(const string & name,
unsigned int arity, PrimOp primOp) unsigned int arity, PrimOp primOp)
{ {
Value & v = baseEnv.bindings[toATerm(name)]; Value v;
nrValues++;
v.type = tPrimOp; v.type = tPrimOp;
v.primOp.arity = arity; v.primOp.arity = arity;
v.primOp.fun = primOp; 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) void EvalState::evalFile(const Path & path, Value & v)
{ {
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); 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)) { if (matchList(e, es)) {
v.type = tList; mkList(v, ATgetLength(es));
v.list.length = ATgetLength(es);
v.list.elems = allocValues(v.list.length);
for (unsigned int n = 0; n < v.list.length; ++n, es = ATgetNext(es)) for (unsigned int n = 0; n < v.list.length; ++n, es = ATgetNext(es))
mkThunk(v.list.elems[n], env, ATgetFirst(es)); mkThunk(v.list.elems[n], env, ATgetFirst(es));
return; return;
@ -376,9 +394,7 @@ void EvalState::eval(Env & env, Expr e, Value & v)
forceList(v1); forceList(v1);
Value v2; eval(env, e2, v2); Value v2; eval(env, e2, v2);
forceList(v2); forceList(v2);
v.type = tList; mkList(v, v1.list.length + v2.list.length);
v.list.length = v1.list.length + v2.list.length;
v.list.elems = allocValues(v.list.length);
/* !!! This loses sharing with the original lists. We could /* !!! This loses sharing with the original lists. We could
use a tCopy node, but that would use more memory. */ use a tCopy node, but that would use more memory. */
for (unsigned int n = 0; n < v1.list.length; ++n) for (unsigned int n = 0; n < v1.list.length; ++n)

View file

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

View file

@ -20,63 +20,6 @@
namespace nix { 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 * 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 /* Return a list consisting of everything but the the first element of
a list. */ 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]); state.forceList(*args[0]);
if (ATisEmpty(list)) if (args[0]->list.length == 0)
throw Error("`tail' called on an empty list"); 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. */ /* 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.forceFunction(*args[0]);
state.forceList(*args[1]); state.forceList(*args[1]);
v.type = tList; state.mkList(v, args[1]->list.length);
v.list.length = args[1]->list.length;
v.list.elems = state.allocValues(v.list.length);
for (unsigned int n = 0; n < v.list.length; ++n) { for (unsigned int n = 0; n < v.list.length; ++n) {
v.list.elems[n].type = tApp; v.list.elems[n].type = tApp;
@ -1121,28 +1062,26 @@ void EvalState::createBaseEnv()
v.type = tAttrs; v.type = tAttrs;
v.attrs = new Bindings; 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 /* Add global constants such as `true' to the base environment. */
// Constants Value v;
addPrimOp("__currentSystem", 0, prim_currentSystem);
addPrimOp("__currentTime", 0, prim_currentTime); 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 // Miscellaneous
#endif
addPrimOp("import", 1, prim_import); addPrimOp("import", 1, prim_import);
#if 0 #if 0
addPrimOp("isNull", 1, prim_isNull); addPrimOp("isNull", 1, prim_isNull);
@ -1193,9 +1132,7 @@ void EvalState::createBaseEnv()
addPrimOp("__isList", 1, prim_isList); addPrimOp("__isList", 1, prim_isList);
#endif #endif
addPrimOp("__head", 1, prim_head); addPrimOp("__head", 1, prim_head);
#if 0
addPrimOp("__tail", 1, prim_tail); addPrimOp("__tail", 1, prim_tail);
#endif
addPrimOp("map", 2, prim_map); addPrimOp("map", 2, prim_map);
#if 0 #if 0
addPrimOp("__length", 1, prim_length); addPrimOp("__length", 1, prim_length);