From f5b8986681c7c7124a81b1c38ee7673bc863f463 Mon Sep 17 00:00:00 2001 From: NikolajDanger Date: Wed, 22 Apr 2026 13:24:55 +0200 Subject: [PATCH] :goat: Compiler fix --- centvrion/compiler/runtime/cent_runtime.c | 18 +++++++++++++++--- tests.py | 13 +++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/centvrion/compiler/runtime/cent_runtime.c b/centvrion/compiler/runtime/cent_runtime.c index afb9012..936bfe5 100644 --- a/centvrion/compiler/runtime/cent_runtime.c +++ b/centvrion/compiler/runtime/cent_runtime.c @@ -380,7 +380,9 @@ static long gcd(long a, long b) { static CentValue frac_reduce(long num, long den) { if (den < 0) { num = -num; den = -den; } long g = gcd(num < 0 ? -num : num, den); - return cent_frac(num / g, den / g); + num /= g; den /= g; + if (den == 1) return cent_int(num); + return cent_frac(num, den); } static void to_frac(CentValue v, long *num, long *den) { @@ -445,11 +447,16 @@ CentValue cent_mul(CentValue a, CentValue b) { } CentValue cent_div(CentValue a, CentValue b) { + if (a.type == CENT_NULL) a = cent_int(0); + if (b.type == CENT_NULL) b = cent_int(0); if (a.type != CENT_INT || b.type != CENT_INT) cent_type_error("'/' requires two integers"); if (b.ival == 0) cent_runtime_error("division by zero"); - return cent_int(a.ival / b.ival); + /* floored division (Python // semantics) */ + long q = a.ival / b.ival; + if ((a.ival % b.ival != 0) && ((a.ival < 0) != (b.ival < 0))) q -= 1; + return cent_int(q); } CentValue cent_div_frac(CentValue a, CentValue b) { @@ -460,11 +467,16 @@ CentValue cent_div_frac(CentValue a, CentValue b) { } CentValue cent_mod(CentValue a, CentValue b) { + if (a.type == CENT_NULL) a = cent_int(0); + if (b.type == CENT_NULL) b = cent_int(0); if (a.type != CENT_INT || b.type != CENT_INT) cent_type_error("'RELIQVVM' requires two integers"); if (b.ival == 0) cent_runtime_error("modulo by zero"); - return cent_int(a.ival % b.ival); + /* floored modulo (Python % semantics) */ + long r = a.ival % b.ival; + if (r != 0 && ((a.ival < 0) != (b.ival < 0))) r += b.ival; + return cent_int(r); } CentValue cent_mod_frac(CentValue a, CentValue b) { diff --git a/tests.py b/tests.py index 9e69873..60c1ef3 100644 --- a/tests.py +++ b/tests.py @@ -689,6 +689,8 @@ error_tests = [ ("CVM SVBNVLLA\n[I, II][-I]", CentvrionError), # negative index ("[I, II][-I]", CentvrionError), # negative value ("I / NVLLVS", CentvrionError), # division by zero (NVLLVS coerces to 0) + ("V RELIQVVM NVLLVS", CentvrionError), # modulo by zero (NVLLVS coerces to 0) + ("NVLLVS RELIQVVM NVLLVS", CentvrionError), # modulo by zero (both NVLLVS) ("I / [I, II]", CentvrionError), # division with array operand ("I - \"hello\"", CentvrionError), # subtraction with string ("I * \"hello\"", CentvrionError), # multiplication with string @@ -990,6 +992,17 @@ arithmetic_edge_tests = [ ("NVLLVS + NVLLVS", Program([], [ExpressionStatement(BinOp(Nullus(), Nullus(), "SYMBOL_PLUS"))]), ValNul()), ("NVLLVS - V", Program([], [ExpressionStatement(BinOp(Nullus(), Numeral("V"), "SYMBOL_MINUS"))]), ValInt(-5)), ("V - NVLLVS", Program([], [ExpressionStatement(BinOp(Numeral("V"), Nullus(), "SYMBOL_MINUS"))]), ValInt(5)), + # NVLLVS coerces to 0 in modulo and division + ("NVLLVS RELIQVVM V", Program([], [ExpressionStatement(BinOp(Nullus(), Numeral("V"), "KEYWORD_RELIQVVM"))]), ValInt(0)), + ("NVLLVS / V", Program([], [ExpressionStatement(BinOp(Nullus(), Numeral("V"), "SYMBOL_DIVIDE"))]), ValInt(0)), + # floored division and modulo with negative operands (Python semantics) + ("CVM SVBNVLLA\n- VII RELIQVVM III", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(UnaryMinus(Numeral("VII")), Numeral("III"), "KEYWORD_RELIQVVM"))]), ValInt(2)), + ("CVM SVBNVLLA\nVII RELIQVVM - III", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(Numeral("VII"), UnaryMinus(Numeral("III")), "KEYWORD_RELIQVVM"))]), ValInt(-2)), + ("CVM SVBNVLLA\n- VII RELIQVVM - III", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(UnaryMinus(Numeral("VII")), UnaryMinus(Numeral("III")), "KEYWORD_RELIQVVM"))]), ValInt(-1)), + ("CVM SVBNVLLA\n- VII / III", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(UnaryMinus(Numeral("VII")), Numeral("III"), "SYMBOL_DIVIDE"))]), ValInt(-3)), + ("CVM SVBNVLLA\nVII / - III", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(Numeral("VII"), UnaryMinus(Numeral("III")), "SYMBOL_DIVIDE"))]), ValInt(-3)), + ("CVM SVBNVLLA\n- VII / - III", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(UnaryMinus(Numeral("VII")), UnaryMinus(Numeral("III")), "SYMBOL_DIVIDE"))]), ValInt(2)), + ("CVM SVBNVLLA\n- L RELIQVVM C", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(UnaryMinus(Numeral("L")), Numeral("C"), "KEYWORD_RELIQVVM"))]), ValInt(50)), ] class TestArithmeticEdge(unittest.TestCase):