🐐 Several fixes

This commit is contained in:
2026-04-16 17:48:45 +02:00
parent 0b13d9f027
commit c720d75c79
3 changed files with 220 additions and 65 deletions

214
tests.py
View File

@@ -103,6 +103,8 @@ def run_test(self, source, target_nodes, target_value, target_output="", input_l
os.unlink(tmp_c_path)
os.unlink(tmp_bin_path)
assert target_nodes is not None, "All tests must have target nodes"
# --- Output ---
@@ -429,6 +431,8 @@ error_tests = [
("DESIGNA x VT I\nINVOCA x ()", CentvrionError), # invoking a non-function
("SI I TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: int
("IIIS", CentvrionError), # fraction without FRACTIO module
("CVM FRACTIO\n[I, II, III][IIIS]", CentvrionError), # fractional index (IIIS = 7/2)
("CVM FRACTIO\n[I, II, III][I / II]", CentvrionError), # fractional index from division (1/2)
("DESIGNA z VT I - I\nSI z TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: zero int
("SI [I] TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: non-empty list
("SI [] TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: empty list
@@ -489,21 +493,22 @@ repr_tests = [
("erumpe", Erumpe(), "Erumpe()"),
("module_call", ModuleCall("FORS"), "FORS"),
("id", ID("x"), "ID(x)"),
("expression_stmt", ExpressionStatement(String("hi")), "String(hi)"),
("expression_stmt", ExpressionStatement(String("hi")), "ExpressionStatement(\n String(hi)\n)"),
("data_array", DataArray([Numeral("I"), Numeral("II")]), "Array([\n Numeral(I),\n Numeral(II)\n])"),
("data_range_array", DataRangeArray(Numeral("I"), Numeral("X")), "RangeArray([\n Numeral(I),\n Numeral(X)\n])"),
("designa", Designa(ID("x"), Numeral("III")), "Designa(\n ID(x),\n Numeral(III)\n)"),
("binop", BinOp(Numeral("I"), Numeral("II"), "SYMBOL_PLUS"), "BinOp(\n Numeral(I),\n Numeral(II),\n SYMBOL_PLUS\n)"),
("redi", Redi([Numeral("I")]), "Redi([\n Numeral(I)\n])"),
("si_no_else", SiStatement(Bool(True), [ExpressionStatement(Erumpe())], None), "Si(\n Bool(True),\n statements([\n Erumpe()\n ]),\n statements([])\n)"),
("si_with_else", SiStatement(Bool(True), [ExpressionStatement(Erumpe())], [ExpressionStatement(Erumpe())]), "Si(\n Bool(True),\n statements([\n Erumpe()\n ]),\n statements([\n Erumpe()\n ])\n)"),
("dum", DumStatement(Bool(False), [ExpressionStatement(Erumpe())]), "Dum(\n Bool(False),\n statements([\n Erumpe()\n ])\n)"),
("per", PerStatement(DataArray([Numeral("I")]), ID("i"), [ExpressionStatement(Erumpe())]), "Per(\n Array([\n Numeral(I)\n ]),\n ID(i),\n statements([\n Erumpe()\n ])\n)"),
("si_no_else", SiStatement(Bool(True), [ExpressionStatement(Erumpe())], None), "Si(\n Bool(True),\n statements([\n ExpressionStatement(\n Erumpe()\n )\n ]),\n None\n)"),
("si_with_else", SiStatement(Bool(True), [ExpressionStatement(Erumpe())], [ExpressionStatement(Erumpe())]), "Si(\n Bool(True),\n statements([\n ExpressionStatement(\n Erumpe()\n )\n ]),\n statements([\n ExpressionStatement(\n Erumpe()\n )\n ])\n)"),
("si_empty_else", SiStatement(Bool(True), [ExpressionStatement(Erumpe())], []), "Si(\n Bool(True),\n statements([\n ExpressionStatement(\n Erumpe()\n )\n ]),\n statements([])\n)"),
("dum", DumStatement(Bool(False), [ExpressionStatement(Erumpe())]), "Dum(\n Bool(False),\n statements([\n ExpressionStatement(\n Erumpe()\n )\n ])\n)"),
("per", PerStatement(DataArray([Numeral("I")]), ID("i"), [ExpressionStatement(Erumpe())]), "Per(\n Array([\n Numeral(I)\n ]),\n ID(i),\n statements([\n ExpressionStatement(\n Erumpe()\n )\n ])\n)"),
("invoca", Invoca(ID("f"), [Numeral("I")]), "Invoca(\n ID(f),\n parameters([\n Numeral(I)\n ])\n)"),
("builtin", BuiltIn("DICE", [String("hi")]), "Builtin(\n DICE,\n parameters([\n String(hi)\n ])\n)"),
("defini", Defini(ID("f"), [ID("n")], [ExpressionStatement(Redi([Numeral("I")]))]), "Defini(\n ID(f),\n parameters([\n ID(n)\n ]),\n statements([\n Redi([\n Numeral(I)\n ])\n ])\n)"),
("program_no_modules", Program([], [ExpressionStatement(Numeral("I"))]), "modules([]),\nstatements([\n Numeral(I)\n])"),
("program_with_module", Program([ModuleCall("FORS")], [ExpressionStatement(Numeral("I"))]), "modules([\n FORS\n]),\nstatements([\n Numeral(I)\n])"),
("defini", Defini(ID("f"), [ID("n")], [ExpressionStatement(Redi([Numeral("I")]))]), "Defini(\n ID(f),\n parameters([\n ID(n)\n ]),\n statements([\n ExpressionStatement(\n Redi([\n Numeral(I)\n ])\n )\n ])\n)"),
("program_no_modules", Program([], [ExpressionStatement(Numeral("I"))]), "modules([]),\nstatements([\n ExpressionStatement(\n Numeral(I)\n )\n])"),
("program_with_module", Program([ModuleCall("FORS")], [ExpressionStatement(Numeral("I"))]), "modules([\n FORS\n]),\nstatements([\n ExpressionStatement(\n Numeral(I)\n )\n])"),
]
class TestRepr(unittest.TestCase):
@@ -584,10 +589,10 @@ class TestMakeString(unittest.TestCase):
self.assertEqual(make_string(ValInt(3)), "III")
def test_bool_true(self):
self.assertEqual(make_string(ValBool(True)), "VERVS")
self.assertEqual(make_string(ValBool(True)), "VERITAS")
def test_bool_false(self):
self.assertEqual(make_string(ValBool(False)), "FALSVS")
self.assertEqual(make_string(ValBool(False)), "FALSITAS")
def test_nul(self):
self.assertEqual(make_string(ValNul()), "NVLLVS")
@@ -601,22 +606,22 @@ class TestMakeString(unittest.TestCase):
def test_nested_list(self):
self.assertEqual(
make_string(ValList([ValStr("a"), ValBool(True)])),
"[a VERVS]"
"[a VERITAS]"
)
# --- DICE with non-integer types ---
dice_type_tests = [
("DICE(VERITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(True)]))]), ValStr("VERVS"), "VERVS\n"),
("DICE(FALSITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(False)]))]), ValStr("FALSVS"), "FALSVS\n"),
("DICE(VERITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(True)]))]), ValStr("VERITAS"), "VERITAS\n"),
("DICE(FALSITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(False)]))]), ValStr("FALSITAS"), "FALSITAS\n"),
("DICE(NVLLVS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Nullus()]))]), ValStr("NVLLVS"), "NVLLVS\n"),
('DICE([I, II])', Program([], [ExpressionStatement(BuiltIn("DICE", [DataArray([Numeral("I"), Numeral("II")])]))]), ValStr("[I II]"), "[I II]\n"),
('DICE("")', Program([], [ExpressionStatement(BuiltIn("DICE", [String("")]))]), ValStr(""), "\n"),
# arithmetic result printed as numeral
("DICE(II + III)", Program([], [ExpressionStatement(BuiltIn("DICE", [BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS")]))]), ValStr("V"), "V\n"),
# multiple args of mixed types
('DICE("x", VERITAS)', Program([], [ExpressionStatement(BuiltIn("DICE", [String("x"), Bool(True)]))]), ValStr("x VERVS"), "x VERVS\n"),
('DICE("x", VERITAS)', Program([], [ExpressionStatement(BuiltIn("DICE", [String("x"), Bool(True)]))]), ValStr("x VERITAS"), "x VERITAS\n"),
]
class TestDiceTypes(unittest.TestCase):
@@ -756,8 +761,6 @@ function_edge_tests = [
]),
ValInt(7),
),
# function defined after use is still a parse error (definition must precede call at runtime)
# (skipped — ftable is populated at eval time, so definition order matters)
# parameter shadows outer variable inside function
(
"DESIGNA n VT I\nDEFINI f (n) VT { REDI (n * II) }\nINVOCA f (X)\nn",
@@ -793,25 +796,53 @@ function_edge_tests = [
# REDI inside SI exits function, skips remaining statements in block
(
"DEFINI f () VT {\nSI VERITAS TVNC {\nREDI (I)\nREDI (II)\n}\n}\nINVOCA f ()",
None,
Program([],[
Defini(ID("f"), [], [SiStatement(Bool(True),[Redi([Numeral("I")]),Redi([Numeral("II")])],None)]),
ExpressionStatement(Invoca(ID("f"),[]))
]),
ValInt(1),
),
# REDI inside DVM exits loop and function
(
"DEFINI f () VT {\nDESIGNA x VT I\nDVM FALSITAS FACE {\nREDI (x)\n}\n}\nINVOCA f ()",
None,
Program([],[
Defini(ID("f"), [], [
Designa(ID("x"), Numeral("I")),
DumStatement(Bool(False), [Redi([ID("x")])])
]),
ExpressionStatement(Invoca(ID("f"),[]))
]),
ValInt(1),
),
# REDI inside PER exits loop and function
(
"DEFINI f () VT {\nPER x IN [I, II, III] FACE {\nSI x EST II TVNC {\nREDI (x)\n}\n}\n}\nINVOCA f ()",
None,
Program([],[
Defini(ID("f"), [], [
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("x"), [
SiStatement(BinOp(ID("x"), Numeral("II"), "KEYWORD_EST"), [
Redi([ID("x")])
], None)
])
]),
ExpressionStatement(Invoca(ID("f"),[]))
]),
ValInt(2),
),
# REDI inside nested loops exits all loops and function
(
"DEFINI f () VT {\nDESIGNA x VT I\nDVM FALSITAS FACE {\nDVM FALSITAS FACE {\nREDI (x)\n}\n}\n}\nINVOCA f ()",
None,
Program([],[
Defini(ID("f"), [], [
Designa(ID("x"), Numeral("I")),
DumStatement(Bool(False), [
DumStatement(Bool(False), [
Redi([ID("x")])
])
])
]),
ExpressionStatement(Invoca(ID("f"),[]))
]),
ValInt(1),
),
]
@@ -1026,7 +1057,7 @@ et_avt_tests = [
("VERITAS AVT FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(False), "KEYWORD_AVT"))]), ValBool(True)),
("FALSITAS AVT VERITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(True), "KEYWORD_AVT"))]), ValBool(True)),
("FALSITAS AVT FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(False), "KEYWORD_AVT"))]), ValBool(False)),
# short-circuit behaviour: combined with comparisons
# short-circuit behavior: combined with comparisons
("(I EST I) ET (II EST II)",
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("I"), "KEYWORD_EST"), BinOp(Numeral("II"), Numeral("II"), "KEYWORD_EST"), "KEYWORD_ET"))]),
ValBool(True)),
@@ -1062,6 +1093,24 @@ array_index_tests = [
ValInt(20)), # second element
# index into range array
("[I VSQVE V][II]", Program([], [ExpressionStatement(ArrayIndex(DataRangeArray(Numeral("I"), Numeral("V")), Numeral("II")))]), ValInt(2)), # second element of [1,2,3,4]
# expression as index
("[I, II, III][I + I]",
Program([], [ExpressionStatement(ArrayIndex(
DataArray([Numeral("I"), Numeral("II"), Numeral("III")]),
BinOp(Numeral("I"), Numeral("I"), "SYMBOL_PLUS")))]),
ValInt(2)),
# division result as index (no FRACTIO): IV / II = 2
("[X, XX, XXX][IV / II]",
Program([], [ExpressionStatement(ArrayIndex(
DataArray([Numeral("X"), Numeral("XX"), Numeral("XXX")]),
BinOp(Numeral("IV"), Numeral("II"), "SYMBOL_DIVIDE")))]),
ValInt(20)),
# whole-number fraction (from division) as index, with FRACTIO imported
("CVM FRACTIO\n[X, XX, XXX][IV / II]",
Program([ModuleCall("FRACTIO")], [ExpressionStatement(ArrayIndex(
DataArray([Numeral("X"), Numeral("XX"), Numeral("XXX")]),
BinOp(Numeral("IV"), Numeral("II"), "SYMBOL_DIVIDE")))]),
ValInt(20)),
]
class TestArrayIndex(unittest.TestCase):
@@ -1342,22 +1391,57 @@ fractio_tests = [
ValFrac(Fraction(7) + Fraction(100, 144))),
# Arithmetic
("CVM FRACTIO\nIIIS + S",
None, ValFrac(Fraction(4))),
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("IIIS"), Fractio("S"), "SYMBOL_PLUS"))
]),
ValFrac(Fraction(4))
),
("CVM FRACTIO\nIIIS - S",
None, ValFrac(Fraction(3))),
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("IIIS"), Fractio("S"), "SYMBOL_MINUS"))
]),
ValFrac(Fraction(3))
),
("CVM FRACTIO\nS * IV",
None, ValFrac(Fraction(2))),
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("S"), Numeral("IV"), "SYMBOL_TIMES"))
]),
ValFrac(Fraction(2))
),
# Division returns fraction
("CVM FRACTIO\nI / IV",
None, ValFrac(Fraction(1, 4))),
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Numeral("I"), Numeral("IV"), "SYMBOL_DIVIDE"))
]),
ValFrac(Fraction(1, 4))
),
("CVM FRACTIO\nI / III",
None, ValFrac(Fraction(1, 3))),
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Numeral("I"), Numeral("III"), "SYMBOL_DIVIDE"))
]),
ValFrac(Fraction(1, 3))
),
# Integer division still works without fractions in operands... but with FRACTIO returns ValFrac
("CVM FRACTIO\nX / II",
None, ValFrac(Fraction(5))),
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Numeral("X"), Numeral("II"), "SYMBOL_DIVIDE"))
]),
ValFrac(Fraction(5))
),
# String concatenation with fraction
("CVM FRACTIO\nDICE(IIIS & \"!\")",
None, ValStr("IIIS!"), "IIIS!\n"),
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BuiltIn("DICE", [BinOp(Fractio("IIIS"), String("!"), "SYMBOL_AMPERSAND")]))
]),
ValStr("IIIS!"), "IIIS!\n"
),
# Negative fractions
("CVM FRACTIO\nCVM SVBNVLLA\n-IIS",
Program([ModuleCall("FRACTIO"),ModuleCall("SVBNVLLA")],[
ExpressionStatement(UnaryMinus(Fractio("IIS")))
]),
ValFrac(Fraction(-5,2))
)
]
class TestFractio(unittest.TestCase):
@@ -1368,18 +1452,72 @@ class TestFractio(unittest.TestCase):
fractio_comparison_tests = [
# fraction vs fraction
("CVM FRACTIO\nIIIS PLVS III", None, ValBool(True)), # 3.5 > 3
("CVM FRACTIO\nIII MINVS IIIS", None, ValBool(True)), # 3 < 3.5
("CVM FRACTIO\nIIIS MINVS IV", None, ValBool(True)), # 3.5 < 4
("CVM FRACTIO\nIV PLVS IIIS", None, ValBool(True)), # 4 > 3.5
("CVM FRACTIO\nIIIS PLVS IIIS", None, ValBool(False)), # 3.5 > 3.5 is False
("CVM FRACTIO\nIIIS MINVS IIIS", None, ValBool(False)), # 3.5 < 3.5 is False
("CVM FRACTIO\nIIIS PLVS III",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("IIIS"), Numeral("III"), "KEYWORD_PLVS"))
]),
ValBool(True)
),
("CVM FRACTIO\nIII MINVS IIIS",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Numeral("III"), Fractio("IIIS"), "KEYWORD_MINVS"))
]),
ValBool(True)
),
("CVM FRACTIO\nIIIS MINVS IV",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("IIIS"), Numeral("IV"), "KEYWORD_MINVS"))
]),
ValBool(True)
),
("CVM FRACTIO\nIV PLVS IIIS",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Numeral("IV"), Fractio("IIIS"), "KEYWORD_PLVS"))
]),
ValBool(True)
),
("CVM FRACTIO\nIIIS PLVS IIIS",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("IIIS"), Fractio("IIIS"), "KEYWORD_PLVS"))
]),
ValBool(False)
),
("CVM FRACTIO\nIIIS MINVS IIIS",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("IIIS"), Fractio("IIIS"), "KEYWORD_MINVS"))
]),
ValBool(False)
),
# equality: fraction == fraction
("CVM FRACTIO\nIIIS EST IIIS", None, ValBool(True)),
("CVM FRACTIO\nIIIS EST IV", None, ValBool(False)),
("CVM FRACTIO\nIIIS EST IIIS",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("IIIS"), Fractio("IIIS"), "KEYWORD_EST"))
]),
ValBool(True)
),
("CVM FRACTIO\nIIIS EST IV",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("IIIS"), Numeral("IV"), "KEYWORD_EST"))
]),
ValBool(False)
),
# equality: fraction == whole number (ValFrac(4) vs ValInt(4))
("CVM FRACTIO\nIIIS + S EST IV", None, ValBool(True)), # 3.5+0.5 == 4
("CVM FRACTIO\nS + S EST I", None, ValBool(True)), # 0.5+0.5 == 1
("CVM FRACTIO\nIIIS + S EST IV",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(
BinOp(Fractio("IIIS"), Fractio("S"), "SYMBOL_PLUS"),
Numeral("IV"), "KEYWORD_EST"))
]),
ValBool(True)
),
("CVM FRACTIO\nS + S EST I",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(
BinOp(Fractio("S"), Fractio("S"), "SYMBOL_PLUS"),
Numeral("I"), "KEYWORD_EST"))
]),
ValBool(True)
),
]
class TestFractioComparisons(unittest.TestCase):