From c3aa615a5f4a8bdde5d836ce91d5daa743ded065 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 30 Mar 2010 14:39:27 +0000 Subject: [PATCH] * More primops. --- src/libexpr/eval-test.cc | 6 ++- src/libexpr/eval.cc | 32 ++++++++--- src/libexpr/eval.hh | 4 ++ src/libexpr/primops.cc | 111 +++++++++------------------------------ 4 files changed, 56 insertions(+), 97 deletions(-) diff --git a/src/libexpr/eval-test.cc b/src/libexpr/eval-test.cc index 0b20883a3..e4e70c38c 100644 --- a/src/libexpr/eval-test.cc +++ b/src/libexpr/eval-test.cc @@ -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 ]"); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f1437e465..06ca01ff4 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -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) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 385c2d78d..5e7be5fcd 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -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); }; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index bf8271b13..17ea8ee61 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -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()", 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);