diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index e0451dfa77..44d75bd8c0 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -574,6 +574,16 @@ inline bool EvalState::evalBool(Env & env, Expr * e) } +inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos) +{ + Value v; + e->eval(*this, env, v); + if (v.type != tBool) + throwTypeError("value is %1% while a Boolean was expected, at %2%", v, pos); + return v.boolean; +} + + inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v) { e->eval(*this, env, v); @@ -975,7 +985,7 @@ void ExprIf::eval(EvalState & state, Env & env, Value & v) void ExprAssert::eval(EvalState & state, Env & env, Value & v) { - if (!state.evalBool(env, cond)) + if (!state.evalBool(env, cond, pos)) throwAssertionError("assertion failed at %1%", pos); body->eval(state, env, v); } @@ -1016,19 +1026,19 @@ void ExprOpNEq::eval(EvalState & state, Env & env, Value & v) void ExprOpAnd::eval(EvalState & state, Env & env, Value & v) { - mkBool(v, state.evalBool(env, e1) && state.evalBool(env, e2)); + mkBool(v, state.evalBool(env, e1, pos) && state.evalBool(env, e2, pos)); } void ExprOpOr::eval(EvalState & state, Env & env, Value & v) { - mkBool(v, state.evalBool(env, e1) || state.evalBool(env, e2)); + mkBool(v, state.evalBool(env, e1, pos) || state.evalBool(env, e2, pos)); } void ExprOpImpl::eval(EvalState & state, Env & env, Value & v) { - mkBool(v, !state.evalBool(env, e1) || state.evalBool(env, e2)); + mkBool(v, !state.evalBool(env, e1, pos) || state.evalBool(env, e2, pos)); } @@ -1073,18 +1083,18 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v) Value v1; e1->eval(state, env, v1); Value v2; e2->eval(state, env, v2); Value * lists[2] = { &v1, &v2 }; - state.concatLists(v, 2, lists); + state.concatLists(v, 2, lists, pos); } -void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists) +void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists, const Pos & pos) { nrListConcats++; Value * nonEmpty = 0; unsigned int len = 0; for (unsigned int n = 0; n < nrLists; ++n) { - forceList(*lists[n]); + forceList(*lists[n], pos); unsigned int l = lists[n]->list.length; len += l; if (l) nonEmpty = lists[n]; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index d1bd27f162..6d4cb8abe8 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -145,6 +145,7 @@ public: /* Evaluation the expression, then verify that it has the expected type. */ inline bool evalBool(Env & env, Expr * e); + inline bool evalBool(Env & env, Expr * e, const Pos & pos); inline void evalAttrs(Env & env, Expr * e, Value & v); /* If `v' is a thunk, enter it and overwrite `v' with the result @@ -246,7 +247,7 @@ public: void mkThunk_(Value & v, Expr * expr); void mkPos(Value & v, Pos * pos); - void concatLists(Value & v, unsigned int nrLists, Value * * lists); + void concatLists(Value & v, unsigned int nrLists, Value * * lists, const Pos & pos); /* Print statistics. */ void printStats(); diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index d781d92ba7..f07b85c834 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -277,28 +277,13 @@ struct ExprBuiltin : Expr COMMON_METHODS }; -struct ExprApp : Expr -{ - Pos pos; - Expr * e1, * e2; - ExprApp(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; - ExprApp(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; - void show(std::ostream & str) - { - str << *e1 << " " << *e2; - } - void bindVars(const StaticEnv & env) - { - e1->bindVars(env); e2->bindVars(env); - } - void eval(EvalState & state, Env & env, Value & v); -}; - #define MakeBinOp(name, s) \ struct Expr##name : Expr \ { \ + Pos pos; \ Expr * e1, * e2; \ Expr##name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \ + Expr##name(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \ void show(std::ostream & str) \ { \ str << *e1 << " " s " " << *e2; \ @@ -310,6 +295,7 @@ struct ExprApp : Expr void eval(EvalState & state, Env & env, Value & v); \ }; +MakeBinOp(App, "") MakeBinOp(OpEq, "==") MakeBinOp(OpNEq, "!=") MakeBinOp(OpAnd, "&&") diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index d39d0c0a75..021f8b0266 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -335,10 +335,10 @@ expr_op | expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $3), $1)); } | expr_op '>' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $3), $1); } | expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $1), $3)); } - | expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); } - | expr_op OR expr_op { $$ = new ExprOpOr($1, $3); } - | expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); } - | expr_op UPDATE expr_op { $$ = new ExprOpUpdate($1, $3); } + | expr_op AND expr_op { $$ = new ExprOpAnd(CUR_POS, $1, $3); } + | expr_op OR expr_op { $$ = new ExprOpOr(CUR_POS, $1, $3); } + | expr_op IMPL expr_op { $$ = new ExprOpImpl(CUR_POS, $1, $3); } + | expr_op UPDATE expr_op { $$ = new ExprOpUpdate(CUR_POS, $1, $3); } | expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, *$3); } | expr_op '+' expr_op { vector * l = new vector; @@ -349,7 +349,7 @@ expr_op | expr_op '-' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("sub")), $1), $3); } | expr_op '*' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("mul")), $1), $3); } | expr_op '/' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("div")), $1), $3); } - | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); } + | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists(CUR_POS, $1, $3); } | expr_app ; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 84ef967ffa..b4e75648f8 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1042,7 +1042,7 @@ static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceList(*args[0], pos); - state.concatLists(v, args[0]->list.length, args[0]->list.elems); + state.concatLists(v, args[0]->list.length, args[0]->list.elems, pos); }