* More primops.
This commit is contained in:
parent
5b72d8a749
commit
c3aa615a5f
4 changed files with 56 additions and 97 deletions
|
@ -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 ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -1123,26 +1064,24 @@ void EvalState::createBaseEnv()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add global constants such as `true' to the base environment. */
|
/* Add global constants such as `true' to the base environment. */
|
||||||
{ Value & v = baseEnv.bindings[toATerm("true")];
|
Value v;
|
||||||
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
|
mkBool(v, true);
|
||||||
// Constants
|
addConstant("true", v);
|
||||||
addPrimOp("__currentSystem", 0, prim_currentSystem);
|
|
||||||
addPrimOp("__currentTime", 0, prim_currentTime);
|
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);
|
||||||
|
|
Loading…
Reference in a new issue