🐐 Several fixes
This commit is contained in:
@@ -92,7 +92,7 @@ def num_to_int(n, m, s=False):
|
||||
|
||||
return sum(nums)
|
||||
|
||||
def int_to_num(n, m, s=False):
|
||||
def int_to_num(n, m, s=False) -> str:
|
||||
if n < 0:
|
||||
if not s:
|
||||
raise CentvrionError("Cannot display negative numbers without 'SVBNVLLA' module")
|
||||
@@ -120,7 +120,7 @@ def int_to_num(n, m, s=False):
|
||||
|
||||
return ''.join(nums)
|
||||
|
||||
def make_string(val, magnvm=False, svbnvlla=False):
|
||||
def make_string(val, magnvm=False, svbnvlla=False) -> str:
|
||||
if isinstance(val, ValStr):
|
||||
return val.value()
|
||||
elif isinstance(val, ValInt):
|
||||
@@ -128,7 +128,7 @@ def make_string(val, magnvm=False, svbnvlla=False):
|
||||
elif isinstance(val, ValFrac):
|
||||
return fraction_to_frac(val.value(), magnvm, svbnvlla)
|
||||
elif isinstance(val, ValBool):
|
||||
return "VERVS" if val.value() else "FALSVS"
|
||||
return "VERITAS" if val.value() else "FALSITAS"
|
||||
elif isinstance(val, ValNul):
|
||||
return "NVLLVS"
|
||||
elif isinstance(val, ValList):
|
||||
@@ -166,7 +166,7 @@ def frac_to_fraction(s, magnvm=False, svbnvlla=False):
|
||||
|
||||
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 not svbnvlla:
|
||||
raise CentvrionError("Cannot display negative numbers without 'SVBNVLLA' module")
|
||||
@@ -200,16 +200,20 @@ class Node(BaseBox):
|
||||
def _eval(self, vtable):
|
||||
raise NotImplementedError
|
||||
|
||||
def print(self):
|
||||
return "Node()"
|
||||
|
||||
|
||||
class ExpressionStatement(Node):
|
||||
def __init__(self, expression) -> None:
|
||||
def __init__(self, expression: Node) -> None:
|
||||
self.expression = expression
|
||||
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other) and self.expression == other.expression
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.expression.__repr__()
|
||||
expr = repr(self.expression).replace('\n', '\n ')
|
||||
return f"ExpressionStatement(\n {expr}\n)"
|
||||
|
||||
def print(self):
|
||||
return self.expression.print()
|
||||
@@ -284,7 +288,7 @@ class String(Node):
|
||||
|
||||
|
||||
class Numeral(Node):
|
||||
def __init__(self, value) -> None:
|
||||
def __init__(self, value: str) -> None:
|
||||
self.value = value
|
||||
|
||||
def __eq__(self, other):
|
||||
@@ -301,7 +305,7 @@ class Numeral(Node):
|
||||
|
||||
|
||||
class Fractio(Node):
|
||||
def __init__(self, value) -> None:
|
||||
def __init__(self, value: str) -> None:
|
||||
self.value = value
|
||||
|
||||
def __eq__(self, other):
|
||||
@@ -372,7 +376,7 @@ class ID(Node):
|
||||
|
||||
|
||||
class Designa(Node):
|
||||
def __init__(self, variable: ID, value) -> None:
|
||||
def __init__(self, variable: ID, value: Node) -> None:
|
||||
self.id = variable
|
||||
self.value = value
|
||||
|
||||
@@ -426,7 +430,7 @@ class DesignaIndex(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.parameters = parameters
|
||||
self.statements = statements
|
||||
@@ -453,7 +457,7 @@ class Defini(Node):
|
||||
|
||||
|
||||
class Redi(Node):
|
||||
def __init__(self, values) -> None:
|
||||
def __init__(self, values: list[Node]) -> None:
|
||||
self.values = values
|
||||
|
||||
def __eq__(self, other):
|
||||
@@ -524,7 +528,7 @@ class Nullus(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.right = right
|
||||
self.op = op
|
||||
@@ -601,7 +605,7 @@ class BinOp(Node):
|
||||
|
||||
|
||||
class UnaryMinus(Node):
|
||||
def __init__(self, expr):
|
||||
def __init__(self, expr: Node):
|
||||
self.expr = expr
|
||||
|
||||
def __eq__(self, other):
|
||||
@@ -617,9 +621,12 @@ class UnaryMinus(Node):
|
||||
if "SVBNVLLA" not in vtable["#modules"]:
|
||||
raise CentvrionError("Cannot use unary minus without 'SVBNVLLA' module")
|
||||
vtable, val = self.expr.eval(vtable)
|
||||
if not isinstance(val, ValInt):
|
||||
if isinstance(val, ValInt):
|
||||
return vtable, ValInt(-val.value())
|
||||
elif isinstance(val, ValFrac):
|
||||
return vtable, ValFrac(-val.value())
|
||||
else:
|
||||
raise CentvrionError("Unary minus requires a number")
|
||||
return vtable, ValInt(-val.value())
|
||||
|
||||
|
||||
class UnaryNot(Node):
|
||||
@@ -661,9 +668,12 @@ class ArrayIndex(Node):
|
||||
vtable, index = self.index.eval(vtable)
|
||||
if not isinstance(array, ValList):
|
||||
raise CentvrionError("Cannot index a non-array value")
|
||||
if not isinstance(index, ValInt):
|
||||
if isinstance(index, ValInt):
|
||||
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")
|
||||
i = index.value()
|
||||
lst = array.value()
|
||||
if i < 1 or i > 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:
|
||||
test = repr(self.test)
|
||||
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])
|
||||
return f"Si({si_string})"
|
||||
|
||||
@@ -713,7 +726,7 @@ class SiStatement(Node):
|
||||
|
||||
|
||||
class DumStatement(Node):
|
||||
def __init__(self, test, statements) -> None:
|
||||
def __init__(self, test: Node, statements: list[Node]) -> None:
|
||||
self.test = test
|
||||
self.statements = statements
|
||||
|
||||
@@ -838,7 +851,7 @@ class Invoca(Node):
|
||||
|
||||
|
||||
class BuiltIn(Node):
|
||||
def __init__(self, builtin, parameters) -> None:
|
||||
def __init__(self, builtin: str, parameters: list[Node]) -> None:
|
||||
self.builtin = builtin
|
||||
self.parameters = parameters
|
||||
|
||||
@@ -907,7 +920,7 @@ class BuiltIn(Node):
|
||||
|
||||
|
||||
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.statements = statements
|
||||
|
||||
|
||||
@@ -221,11 +221,11 @@ static int write_val(CentValue v, char *buf, int bufsz) {
|
||||
|
||||
case CENT_BOOL:
|
||||
if (v.bval) {
|
||||
if (buf && bufsz > 5) { memcpy(buf, "VERVS", 5); buf[5] = '\0'; }
|
||||
return 5;
|
||||
if (buf && bufsz > 7) { memcpy(buf, "VERITAS", 7); buf[7] = '\0'; }
|
||||
return 7;
|
||||
} else {
|
||||
if (buf && bufsz > 6) { memcpy(buf, "FALSVS", 6); buf[6] = '\0'; }
|
||||
return 6;
|
||||
if (buf && bufsz > 8) { memcpy(buf, "FALSITAS", 8); buf[8] = '\0'; }
|
||||
return 8;
|
||||
}
|
||||
|
||||
case CENT_NULL:
|
||||
@@ -527,9 +527,13 @@ void cent_list_push(CentValue *lst, CentValue v) {
|
||||
CentValue cent_list_index(CentValue lst, CentValue idx) {
|
||||
if (lst.type != CENT_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");
|
||||
long i = idx.ival;
|
||||
if (i < 1 || i > lst.lval.len)
|
||||
cent_runtime_error("list index out of range");
|
||||
return lst.lval.items[i - 1];
|
||||
|
||||
214
tests.py
214
tests.py
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user