diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 85c044c2fa9..07035cea3d6 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1911,7 +1911,6 @@ void ExprOpImpl::eval(EvalState & state, Env & env, Value & v) v.mkBool(!state.evalBool(env, e1, pos, "in the left operand of the IMPL (->) operator") || state.evalBool(env, e2, pos, "in the right operand of the IMPL (->) operator")); } - void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) { Value v1, v2; @@ -1949,6 +1948,110 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) state.nrOpUpdateValuesCopied += v.attrs()->size(); } +void ExprOpSub::eval(EvalState & state, Env & env, Value & v) +{ + Value v1, v2; + try { + e1->eval(state, env, v1); + e2->eval(state, env, v2); + } catch (Error & e) { + e.addTrace(state.positions[pos], "while evaluating the - operator"); + throw; + } + + prim_sub(state, pos, v1, v2, v); +} + +void ExprOpDiv::eval(EvalState & state, Env & env, Value & v) +{ + Value v1, v2; + try { + e1->eval(state, env, v1); + e2->eval(state, env, v2); + } catch (Error & e) { + e.addTrace(state.positions[pos], "while evaluating the / operator"); + throw; + } + + prim_div(state, pos, v1, v2, v); +} + +void ExprOpMul::eval(EvalState & state, Env & env, Value & v) +{ + Value v1, v2; + try { + e1->eval(state, env, v1); + e2->eval(state, env, v2); + } catch (Error & e) { + e.addTrace(state.positions[pos], "while evaluating the * operator"); + throw; + } + + prim_mul(state, pos, v1, v2, v); +} + +void ExprOpLessThan::eval(EvalState & state, Env & env, Value & v) +{ + Value v1, v2; + try { + e1->eval(state, env, v1); + e2->eval(state, env, v2); + } catch (Error & e) { + e.addTrace(state.positions[pos], "while evaluating the < operator"); + throw; + } + + Value *args[2] = { &v1, &v2 }; + prim_lessThan(state, pos, args, v); +} + +void ExprOpLessEqual::eval(EvalState & state, Env & env, Value & v) +{ + Value v1, v2; + try { + e1->eval(state, env, v1); + e2->eval(state, env, v2); + } catch (Error & e) { + e.addTrace(state.positions[pos], "while evaluating the <= operator"); + throw; + } + + Value *args[2] = { &v2, &v1 }; + prim_lessThan(state, pos, args, v); + v.mkBool(!state.forceBool(v, pos, "while evaluating the <= operator")); +} + +void ExprOpGreaterThan::eval(EvalState & state, Env & env, Value & v) +{ + Value v1, v2; + try { + e1->eval(state, env, v1); + e2->eval(state, env, v2); + } catch (Error & e) { + e.addTrace(state.positions[pos], "while evaluating the > operator"); + throw; + } + + Value *args[2] = { &v2, &v1 }; + prim_lessThan(state, pos, args, v); +} + +void ExprOpGreaterEqual::eval(EvalState & state, Env & env, Value & v) +{ + Value v1, v2; + try { + e1->eval(state, env, v1); + e2->eval(state, env, v2); + } catch (Error & e) { + e.addTrace(state.positions[pos], "while evaluating the >= operator"); + throw; + } + + Value *args[2] = { &v1, &v2 }; + prim_lessThan(state, pos, args, v); + v.mkBool(!state.forceBool(v, pos, "while evaluating the >= operator")); +} + void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v) { diff --git a/src/libexpr/include/nix/expr/nixexpr.hh b/src/libexpr/include/nix/expr/nixexpr.hh index a5ce0fd8922..6bf01faff9a 100644 --- a/src/libexpr/include/nix/expr/nixexpr.hh +++ b/src/libexpr/include/nix/expr/nixexpr.hh @@ -442,6 +442,13 @@ MakeBinOp(ExprOpOr, "||") MakeBinOp(ExprOpImpl, "->") MakeBinOp(ExprOpUpdate, "//") MakeBinOp(ExprOpConcatLists, "++") +MakeBinOp(ExprOpSub, "-") +MakeBinOp(ExprOpDiv, "+") +MakeBinOp(ExprOpMul, "-") +MakeBinOp(ExprOpLessThan, "<") +MakeBinOp(ExprOpLessEqual, "<=") +MakeBinOp(ExprOpGreaterThan, ">") +MakeBinOp(ExprOpGreaterEqual, ">=") struct ExprConcatStrings : Expr { diff --git a/src/libexpr/include/nix/expr/primops.hh b/src/libexpr/include/nix/expr/primops.hh index f0742a13804..757c688fd2d 100644 --- a/src/libexpr/include/nix/expr/primops.hh +++ b/src/libexpr/include/nix/expr/primops.hh @@ -51,6 +51,11 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu */ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v); +void prim_sub(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v); +void prim_div(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v); +void prim_mul(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v); +void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v); + void makePositionThunks(EvalState & state, const PosIdx pos, Value & line, Value & column); } diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 99cc687cc79..65d7974aeea 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -245,10 +245,10 @@ expr_op | '-' expr_op %prec NEGATE { $$ = new ExprCall(CUR_POS, new ExprVar(state->s.sub), {new ExprInt(0), $2}); } | expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); } | expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); } - | expr_op '<' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.lessThan), {$1, $3}); } - | expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprCall(state->at(@2), new ExprVar(state->s.lessThan), {$3, $1})); } - | expr_op '>' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.lessThan), {$3, $1}); } - | expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprCall(state->at(@2), new ExprVar(state->s.lessThan), {$1, $3})); } + | expr_op '<' expr_op { $$ = new ExprOpLessThan(state->at(@2), $1, $3); } + | expr_op LEQ expr_op { $$ = new ExprOpLessEqual(state->at(@2), $1, $3); } + | expr_op '>' expr_op { $$ = new ExprOpGreaterThan(state->at(@2), $1, $3); } + | expr_op GEQ expr_op { $$ = new ExprOpGreaterEqual(state->at(@2), $1, $3); } | expr_op AND expr_op { $$ = new ExprOpAnd(state->at(@2), $1, $3); } | expr_op OR expr_op { $$ = new ExprOpOr(state->at(@2), $1, $3); } | expr_op IMPL expr_op { $$ = new ExprOpImpl(state->at(@2), $1, $3); } @@ -256,9 +256,9 @@ expr_op | expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, std::move(*$3)); delete $3; } | expr_op '+' expr_op { $$ = new ExprConcatStrings(state->at(@2), false, new std::vector >({{state->at(@1), $1}, {state->at(@3), $3}})); } - | expr_op '-' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.sub), {$1, $3}); } - | expr_op '*' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.mul), {$1, $3}); } - | expr_op '/' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.div), {$1, $3}); } + | expr_op '-' expr_op { $$ = new ExprOpSub(state->at(@2), $1, $3); } + | expr_op '*' expr_op { $$ = new ExprOpMul(state->at(@2), $1, $3); } + | expr_op '/' expr_op { $$ = new ExprOpDiv(state->at(@2), $1, $3); } | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists(state->at(@2), $1, $3); } | expr_app ; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index c6a97fdaee0..7d8e30e3e16 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -3648,9 +3648,6 @@ static RegisterPrimOp primop_genList({ .fun = prim_genList, }); -static void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v); - - static void prim_sort(EvalState & state, const PosIdx pos, Value * * args, Value & v) { state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.sort"); @@ -3867,16 +3864,16 @@ static RegisterPrimOp primop_concatMap({ *************************************************************/ -static void prim_add(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_add(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v) { - state.forceValue(*args[0], pos); - state.forceValue(*args[1], pos); - if (args[0]->type() == nFloat || args[1]->type() == nFloat) - v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first argument of the addition") - + state.forceFloat(*args[1], pos, "while evaluating the second argument of the addition")); + state.forceValue(left, pos); + state.forceValue(right, pos); + if (left.type() == nFloat || right.type() == nFloat) + v.mkFloat(state.forceFloat(left, pos, "while evaluating the first argument of the addition") + + state.forceFloat(right, pos, "while evaluating the second argument of the addition")); else { - auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument of the addition"); - auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument of the addition"); + auto i1 = state.forceInt(left, pos, "while evaluating the first argument of the addition"); + auto i2 = state.forceInt(right, pos, "while evaluating the second argument of the addition"); auto result_ = i1 + i2; if (auto result = result_.valueChecked(); result.has_value()) { @@ -3893,19 +3890,19 @@ static RegisterPrimOp primop_add({ .doc = R"( Return the sum of the numbers *e1* and *e2*. )", - .fun = prim_add, + .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { prim_add(state, pos, *args[0], *args[1], v); }, }); -static void prim_sub(EvalState & state, const PosIdx pos, Value * * args, Value & v) +void prim_sub(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v) { - state.forceValue(*args[0], pos); - state.forceValue(*args[1], pos); - if (args[0]->type() == nFloat || args[1]->type() == nFloat) - v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first argument of the subtraction") - - state.forceFloat(*args[1], pos, "while evaluating the second argument of the subtraction")); + state.forceValue(left, pos); + state.forceValue(right, pos); + if (left.type() == nFloat || right.type() == nFloat) + v.mkFloat(state.forceFloat(left, pos, "while evaluating the first argument of the subtraction") + - state.forceFloat(right, pos, "while evaluating the second argument of the subtraction")); else { - auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument of the subtraction"); - auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument of the subtraction"); + auto i1 = state.forceInt(left, pos, "while evaluating the first argument of the subtraction"); + auto i2 = state.forceInt(right, pos, "while evaluating the second argument of the subtraction"); auto result_ = i1 - i2; @@ -3923,19 +3920,19 @@ static RegisterPrimOp primop_sub({ .doc = R"( Return the difference between the numbers *e1* and *e2*. )", - .fun = prim_sub, + .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { prim_sub(state, pos, *args[0], *args[1], v); }, }); -static void prim_mul(EvalState & state, const PosIdx pos, Value * * args, Value & v) +void prim_mul(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v) { - state.forceValue(*args[0], pos); - state.forceValue(*args[1], pos); - if (args[0]->type() == nFloat || args[1]->type() == nFloat) - v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first of the multiplication") - * state.forceFloat(*args[1], pos, "while evaluating the second argument of the multiplication")); + state.forceValue(left, pos); + state.forceValue(right, pos); + if (left.type() == nFloat || right.type() == nFloat) + v.mkFloat(state.forceFloat(left, pos, "while evaluating the first argument of the multiplication") + * state.forceFloat(right, pos, "while evaluating the second argument of the multiplication")); else { - auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument of the multiplication"); - auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument of the multiplication"); + auto i1 = state.forceInt(left, pos, "while evaluating the first argument of the multiplication"); + auto i2 = state.forceInt(right, pos, "while evaluating the second argument of the multiplication"); auto result_ = i1 * i2; @@ -3953,23 +3950,23 @@ static RegisterPrimOp primop_mul({ .doc = R"( Return the product of the numbers *e1* and *e2*. )", - .fun = prim_mul, + .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { prim_mul(state, pos, *args[0], *args[1], v); }, }); -static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value & v) +void prim_div(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v) { - state.forceValue(*args[0], pos); - state.forceValue(*args[1], pos); + state.forceValue(left, pos); + state.forceValue(right, pos); - NixFloat f2 = state.forceFloat(*args[1], pos, "while evaluating the second operand of the division"); + NixFloat f2 = state.forceFloat(right, pos, "while evaluating the second operand of the division"); if (f2 == 0) state.error("division by zero").atPos(pos).debugThrow(); - if (args[0]->type() == nFloat || args[1]->type() == nFloat) { - v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first operand of the division") / f2); + if (left.type() == nFloat || right.type() == nFloat) { + v.mkFloat(state.forceFloat(left, pos, "while evaluating the first operand of the division") / f2); } else { - NixInt i1 = state.forceInt(*args[0], pos, "while evaluating the first operand of the division"); - NixInt i2 = state.forceInt(*args[1], pos, "while evaluating the second operand of the division"); + NixInt i1 = state.forceInt(left, pos, "while evaluating the first operand of the division"); + NixInt i2 = state.forceInt(right, pos, "while evaluating the second operand of the division"); /* Avoid division overflow as it might raise SIGFPE. */ auto result_ = i1 / i2; if (auto result = result_.valueChecked(); result.has_value()) { @@ -3986,7 +3983,7 @@ static RegisterPrimOp primop_div({ .doc = R"( Return the quotient of the numbers *e1* and *e2*. )", - .fun = prim_div, + .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { prim_div(state, pos, *args[0], *args[1], v); }, }); static void prim_bitAnd(EvalState & state, const PosIdx pos, Value * * args, Value & v) @@ -4039,7 +4036,7 @@ static RegisterPrimOp primop_bitXor({ .fun = prim_bitXor, }); -static void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v) +void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos);