🐐 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

View File

@@ -92,7 +92,7 @@ def num_to_int(n, m, s=False):
return sum(nums) return sum(nums)
def int_to_num(n, m, s=False): def int_to_num(n, m, s=False) -> str:
if n < 0: if n < 0:
if not s: if not s:
raise CentvrionError("Cannot display negative numbers without 'SVBNVLLA' module") raise CentvrionError("Cannot display negative numbers without 'SVBNVLLA' module")
@@ -120,7 +120,7 @@ def int_to_num(n, m, s=False):
return ''.join(nums) return ''.join(nums)
def make_string(val, magnvm=False, svbnvlla=False): def make_string(val, magnvm=False, svbnvlla=False) -> str:
if isinstance(val, ValStr): if isinstance(val, ValStr):
return val.value() return val.value()
elif isinstance(val, ValInt): elif isinstance(val, ValInt):
@@ -128,7 +128,7 @@ def make_string(val, magnvm=False, svbnvlla=False):
elif isinstance(val, ValFrac): elif isinstance(val, ValFrac):
return fraction_to_frac(val.value(), magnvm, svbnvlla) return fraction_to_frac(val.value(), magnvm, svbnvlla)
elif isinstance(val, ValBool): elif isinstance(val, ValBool):
return "VERVS" if val.value() else "FALSVS" return "VERITAS" if val.value() else "FALSITAS"
elif isinstance(val, ValNul): elif isinstance(val, ValNul):
return "NVLLVS" return "NVLLVS"
elif isinstance(val, ValList): elif isinstance(val, ValList):
@@ -166,7 +166,7 @@ def frac_to_fraction(s, magnvm=False, svbnvlla=False):
return total return total
def fraction_to_frac(f, magnvm=False, svbnvlla=False): def fraction_to_frac(f, magnvm=False, svbnvlla=False) -> str:
if f < 0: if f < 0:
if not svbnvlla: if not svbnvlla:
raise CentvrionError("Cannot display negative numbers without 'SVBNVLLA' module") raise CentvrionError("Cannot display negative numbers without 'SVBNVLLA' module")
@@ -200,16 +200,20 @@ class Node(BaseBox):
def _eval(self, vtable): def _eval(self, vtable):
raise NotImplementedError raise NotImplementedError
def print(self):
return "Node()"
class ExpressionStatement(Node): class ExpressionStatement(Node):
def __init__(self, expression) -> None: def __init__(self, expression: Node) -> None:
self.expression = expression self.expression = expression
def __eq__(self, other): def __eq__(self, other):
return type(self) == type(other) and self.expression == other.expression return type(self) == type(other) and self.expression == other.expression
def __repr__(self) -> str: def __repr__(self) -> str:
return self.expression.__repr__() expr = repr(self.expression).replace('\n', '\n ')
return f"ExpressionStatement(\n {expr}\n)"
def print(self): def print(self):
return self.expression.print() return self.expression.print()
@@ -284,7 +288,7 @@ class String(Node):
class Numeral(Node): class Numeral(Node):
def __init__(self, value) -> None: def __init__(self, value: str) -> None:
self.value = value self.value = value
def __eq__(self, other): def __eq__(self, other):
@@ -301,7 +305,7 @@ class Numeral(Node):
class Fractio(Node): class Fractio(Node):
def __init__(self, value) -> None: def __init__(self, value: str) -> None:
self.value = value self.value = value
def __eq__(self, other): def __eq__(self, other):
@@ -372,7 +376,7 @@ class ID(Node):
class Designa(Node): class Designa(Node):
def __init__(self, variable: ID, value) -> None: def __init__(self, variable: ID, value: Node) -> None:
self.id = variable self.id = variable
self.value = value self.value = value
@@ -426,7 +430,7 @@ class DesignaIndex(Node):
class Defini(Node): class Defini(Node):
def __init__(self, name, parameters, statements) -> None: def __init__(self, name: ID, parameters: list[ID], statements: list[Node]) -> None:
self.name = name self.name = name
self.parameters = parameters self.parameters = parameters
self.statements = statements self.statements = statements
@@ -453,7 +457,7 @@ class Defini(Node):
class Redi(Node): class Redi(Node):
def __init__(self, values) -> None: def __init__(self, values: list[Node]) -> None:
self.values = values self.values = values
def __eq__(self, other): def __eq__(self, other):
@@ -524,7 +528,7 @@ class Nullus(Node):
class BinOp(Node): class BinOp(Node):
def __init__(self, left, right, op) -> None: def __init__(self, left: Node, right: Node, op: str) -> None:
self.left = left self.left = left
self.right = right self.right = right
self.op = op self.op = op
@@ -601,7 +605,7 @@ class BinOp(Node):
class UnaryMinus(Node): class UnaryMinus(Node):
def __init__(self, expr): def __init__(self, expr: Node):
self.expr = expr self.expr = expr
def __eq__(self, other): def __eq__(self, other):
@@ -617,9 +621,12 @@ class UnaryMinus(Node):
if "SVBNVLLA" not in vtable["#modules"]: if "SVBNVLLA" not in vtable["#modules"]:
raise CentvrionError("Cannot use unary minus without 'SVBNVLLA' module") raise CentvrionError("Cannot use unary minus without 'SVBNVLLA' module")
vtable, val = self.expr.eval(vtable) vtable, val = self.expr.eval(vtable)
if not isinstance(val, ValInt): if isinstance(val, ValInt):
raise CentvrionError("Unary minus requires a number")
return vtable, ValInt(-val.value()) return vtable, ValInt(-val.value())
elif isinstance(val, ValFrac):
return vtable, ValFrac(-val.value())
else:
raise CentvrionError("Unary minus requires a number")
class UnaryNot(Node): class UnaryNot(Node):
@@ -661,9 +668,12 @@ class ArrayIndex(Node):
vtable, index = self.index.eval(vtable) vtable, index = self.index.eval(vtable)
if not isinstance(array, ValList): if not isinstance(array, ValList):
raise CentvrionError("Cannot index a non-array value") raise CentvrionError("Cannot index a non-array value")
if not isinstance(index, ValInt): if isinstance(index, ValInt):
raise CentvrionError("Array index must be a number")
i = index.value() i = index.value()
elif isinstance(index, ValFrac) and index.value().denominator == 1:
i = index.value().numerator
else:
raise CentvrionError("Array index must be a number")
lst = array.value() lst = array.value()
if i < 1 or i > len(lst): if i < 1 or i > len(lst):
raise CentvrionError(f"Index {i} out of range for array of length {len(lst)}") raise CentvrionError(f"Index {i} out of range for array of length {len(lst)}")
@@ -682,7 +692,10 @@ class SiStatement(Node):
def __repr__(self) -> str: def __repr__(self) -> str:
test = repr(self.test) test = repr(self.test)
statements = f"statements([{rep_join(self.statements)}])" statements = f"statements([{rep_join(self.statements)}])"
else_part = f"statements([{rep_join(self.else_part) if self.else_part else ''}])" if self.else_part is None:
else_part = "None"
else:
else_part = f"statements([{rep_join(self.else_part)}])"
si_string = rep_join([test, statements, else_part]) si_string = rep_join([test, statements, else_part])
return f"Si({si_string})" return f"Si({si_string})"
@@ -713,7 +726,7 @@ class SiStatement(Node):
class DumStatement(Node): class DumStatement(Node):
def __init__(self, test, statements) -> None: def __init__(self, test: Node, statements: list[Node]) -> None:
self.test = test self.test = test
self.statements = statements self.statements = statements
@@ -838,7 +851,7 @@ class Invoca(Node):
class BuiltIn(Node): class BuiltIn(Node):
def __init__(self, builtin, parameters) -> None: def __init__(self, builtin: str, parameters: list[Node]) -> None:
self.builtin = builtin self.builtin = builtin
self.parameters = parameters self.parameters = parameters
@@ -907,7 +920,7 @@ class BuiltIn(Node):
class Program(BaseBox): class Program(BaseBox):
def __init__(self, module_calls: list[ModuleCall], statements) -> None: def __init__(self, module_calls: list[ModuleCall], statements: list[Node]) -> None:
self.modules = module_calls self.modules = module_calls
self.statements = statements self.statements = statements

View File

@@ -221,11 +221,11 @@ static int write_val(CentValue v, char *buf, int bufsz) {
case CENT_BOOL: case CENT_BOOL:
if (v.bval) { if (v.bval) {
if (buf && bufsz > 5) { memcpy(buf, "VERVS", 5); buf[5] = '\0'; } if (buf && bufsz > 7) { memcpy(buf, "VERITAS", 7); buf[7] = '\0'; }
return 5; return 7;
} else { } else {
if (buf && bufsz > 6) { memcpy(buf, "FALSVS", 6); buf[6] = '\0'; } if (buf && bufsz > 8) { memcpy(buf, "FALSITAS", 8); buf[8] = '\0'; }
return 6; return 8;
} }
case CENT_NULL: case CENT_NULL:
@@ -527,9 +527,13 @@ void cent_list_push(CentValue *lst, CentValue v) {
CentValue cent_list_index(CentValue lst, CentValue idx) { CentValue cent_list_index(CentValue lst, CentValue idx) {
if (lst.type != CENT_LIST) if (lst.type != CENT_LIST)
cent_type_error("index requires a list"); cent_type_error("index requires a list");
if (idx.type != CENT_INT) long i;
if (idx.type == CENT_INT)
i = idx.ival;
else if (idx.type == CENT_FRAC && idx.fval.den == 1)
i = idx.fval.num;
else
cent_type_error("list index must be an integer"); cent_type_error("list index must be an integer");
long i = idx.ival;
if (i < 1 || i > lst.lval.len) if (i < 1 || i > lst.lval.len)
cent_runtime_error("list index out of range"); cent_runtime_error("list index out of range");
return lst.lval.items[i - 1]; return lst.lval.items[i - 1];

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_c_path)
os.unlink(tmp_bin_path) os.unlink(tmp_bin_path)
assert target_nodes is not None, "All tests must have target nodes"
# --- Output --- # --- Output ---
@@ -429,6 +431,8 @@ error_tests = [
("DESIGNA x VT I\nINVOCA x ()", CentvrionError), # invoking a non-function ("DESIGNA x VT I\nINVOCA x ()", CentvrionError), # invoking a non-function
("SI I TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: int ("SI I TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: int
("IIIS", CentvrionError), # fraction without FRACTIO module ("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 ("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 [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 ("SI [] TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: empty list
@@ -489,21 +493,22 @@ repr_tests = [
("erumpe", Erumpe(), "Erumpe()"), ("erumpe", Erumpe(), "Erumpe()"),
("module_call", ModuleCall("FORS"), "FORS"), ("module_call", ModuleCall("FORS"), "FORS"),
("id", ID("x"), "ID(x)"), ("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_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])"), ("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)"), ("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)"), ("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])"), ("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_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 Erumpe()\n ]),\n statements([\n Erumpe()\n ])\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)"),
("dum", DumStatement(Bool(False), [ExpressionStatement(Erumpe())]), "Dum(\n Bool(False),\n statements([\n Erumpe()\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)"),
("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)"), ("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)"), ("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)"), ("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)"), ("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 Numeral(I)\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 Numeral(I)\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): class TestRepr(unittest.TestCase):
@@ -584,10 +589,10 @@ class TestMakeString(unittest.TestCase):
self.assertEqual(make_string(ValInt(3)), "III") self.assertEqual(make_string(ValInt(3)), "III")
def test_bool_true(self): def test_bool_true(self):
self.assertEqual(make_string(ValBool(True)), "VERVS") self.assertEqual(make_string(ValBool(True)), "VERITAS")
def test_bool_false(self): def test_bool_false(self):
self.assertEqual(make_string(ValBool(False)), "FALSVS") self.assertEqual(make_string(ValBool(False)), "FALSITAS")
def test_nul(self): def test_nul(self):
self.assertEqual(make_string(ValNul()), "NVLLVS") self.assertEqual(make_string(ValNul()), "NVLLVS")
@@ -601,22 +606,22 @@ class TestMakeString(unittest.TestCase):
def test_nested_list(self): def test_nested_list(self):
self.assertEqual( self.assertEqual(
make_string(ValList([ValStr("a"), ValBool(True)])), make_string(ValList([ValStr("a"), ValBool(True)])),
"[a VERVS]" "[a VERITAS]"
) )
# --- DICE with non-integer types --- # --- DICE with non-integer types ---
dice_type_tests = [ dice_type_tests = [
("DICE(VERITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(True)]))]), ValStr("VERVS"), "VERVS\n"), ("DICE(VERITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(True)]))]), ValStr("VERITAS"), "VERITAS\n"),
("DICE(FALSITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(False)]))]), ValStr("FALSVS"), "FALSVS\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(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([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"), ('DICE("")', Program([], [ExpressionStatement(BuiltIn("DICE", [String("")]))]), ValStr(""), "\n"),
# arithmetic result printed as numeral # arithmetic result printed as numeral
("DICE(II + III)", Program([], [ExpressionStatement(BuiltIn("DICE", [BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS")]))]), ValStr("V"), "V\n"), ("DICE(II + III)", Program([], [ExpressionStatement(BuiltIn("DICE", [BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS")]))]), ValStr("V"), "V\n"),
# multiple args of mixed types # 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): class TestDiceTypes(unittest.TestCase):
@@ -756,8 +761,6 @@ function_edge_tests = [
]), ]),
ValInt(7), 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 # parameter shadows outer variable inside function
( (
"DESIGNA n VT I\nDEFINI f (n) VT { REDI (n * II) }\nINVOCA f (X)\nn", "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 # REDI inside SI exits function, skips remaining statements in block
( (
"DEFINI f () VT {\nSI VERITAS TVNC {\nREDI (I)\nREDI (II)\n}\n}\nINVOCA f ()", "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), ValInt(1),
), ),
# REDI inside DVM exits loop and function # REDI inside DVM exits loop and function
( (
"DEFINI f () VT {\nDESIGNA x VT I\nDVM FALSITAS FACE {\nREDI (x)\n}\n}\nINVOCA f ()", "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), ValInt(1),
), ),
# REDI inside PER exits loop and function # 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 ()", "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), ValInt(2),
), ),
# REDI inside nested loops exits all loops and function # 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 ()", "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), ValInt(1),
), ),
] ]
@@ -1026,7 +1057,7 @@ et_avt_tests = [
("VERITAS AVT FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(False), "KEYWORD_AVT"))]), ValBool(True)), ("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 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)), ("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)", ("(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"))]), Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("I"), "KEYWORD_EST"), BinOp(Numeral("II"), Numeral("II"), "KEYWORD_EST"), "KEYWORD_ET"))]),
ValBool(True)), ValBool(True)),
@@ -1062,6 +1093,24 @@ array_index_tests = [
ValInt(20)), # second element ValInt(20)), # second element
# index into range array # 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] ("[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): class TestArrayIndex(unittest.TestCase):
@@ -1342,22 +1391,57 @@ fractio_tests = [
ValFrac(Fraction(7) + Fraction(100, 144))), ValFrac(Fraction(7) + Fraction(100, 144))),
# Arithmetic # Arithmetic
("CVM FRACTIO\nIIIS + S", ("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", ("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", ("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 # Division returns fraction
("CVM FRACTIO\nI / IV", ("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", ("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 # Integer division still works without fractions in operands... but with FRACTIO returns ValFrac
("CVM FRACTIO\nX / II", ("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 # String concatenation with fraction
("CVM FRACTIO\nDICE(IIIS & \"!\")", ("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): class TestFractio(unittest.TestCase):
@@ -1368,18 +1452,72 @@ class TestFractio(unittest.TestCase):
fractio_comparison_tests = [ fractio_comparison_tests = [
# fraction vs fraction # fraction vs fraction
("CVM FRACTIO\nIIIS PLVS III", None, ValBool(True)), # 3.5 > 3 ("CVM FRACTIO\nIIIS PLVS III",
("CVM FRACTIO\nIII MINVS IIIS", None, ValBool(True)), # 3 < 3.5 Program([ModuleCall("FRACTIO")], [
("CVM FRACTIO\nIIIS MINVS IV", None, ValBool(True)), # 3.5 < 4 ExpressionStatement(BinOp(Fractio("IIIS"), Numeral("III"), "KEYWORD_PLVS"))
("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 ValBool(True)
("CVM FRACTIO\nIIIS MINVS IIIS", None, ValBool(False)), # 3.5 < 3.5 is False ),
("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 # equality: fraction == fraction
("CVM FRACTIO\nIIIS EST IIIS", None, ValBool(True)), ("CVM FRACTIO\nIIIS EST IIIS",
("CVM FRACTIO\nIIIS EST IV", None, ValBool(False)), 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)) # 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\nIIIS + S EST IV",
("CVM FRACTIO\nS + S EST I", None, ValBool(True)), # 0.5+0.5 == 1 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): class TestFractioComparisons(unittest.TestCase):