🐐 __eq__ and precendence rules
This commit is contained in:
@@ -130,6 +130,9 @@ class ExpressionStatement(Node):
|
|||||||
def __init__(self, expression) -> None:
|
def __init__(self, expression) -> None:
|
||||||
self.expression = expression
|
self.expression = expression
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.expression == other.expression
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return self.expression.__repr__()
|
return self.expression.__repr__()
|
||||||
|
|
||||||
@@ -141,6 +144,9 @@ class DataArray(Node):
|
|||||||
def __init__(self, content) -> None:
|
def __init__(self, content) -> None:
|
||||||
self.content = content
|
self.content = content
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.content == other.content
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
content_string = rep_join(self.content)
|
content_string = rep_join(self.content)
|
||||||
return f"Array([{content_string}])"
|
return f"Array([{content_string}])"
|
||||||
@@ -158,6 +164,9 @@ class DataRangeArray(Node):
|
|||||||
self.from_value = from_value
|
self.from_value = from_value
|
||||||
self.to_value = to_value
|
self.to_value = to_value
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.from_value == other.from_value and self.to_value == other.to_value
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
content_string = rep_join([self.from_value, self.to_value])
|
content_string = rep_join([self.from_value, self.to_value])
|
||||||
return f"RangeArray([{content_string}])"
|
return f"RangeArray([{content_string}])"
|
||||||
@@ -172,6 +181,9 @@ class String(Node):
|
|||||||
def __init__(self, value) -> None:
|
def __init__(self, value) -> None:
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.value == other.value
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"String({self.value})"
|
return f"String({self.value})"
|
||||||
|
|
||||||
@@ -183,6 +195,9 @@ class Numeral(Node):
|
|||||||
def __init__(self, value) -> None:
|
def __init__(self, value) -> None:
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.value == other.value
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"Numeral({self.value})"
|
return f"Numeral({self.value})"
|
||||||
|
|
||||||
@@ -194,6 +209,9 @@ class Bool(Node):
|
|||||||
def __init__(self, value) -> None:
|
def __init__(self, value) -> None:
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.value == other.value
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"Bool({self.value})"
|
return f"Bool({self.value})"
|
||||||
|
|
||||||
@@ -205,6 +223,9 @@ class ModuleCall(BaseBox):
|
|||||||
def __init__(self, module_name) -> None:
|
def __init__(self, module_name) -> None:
|
||||||
self.module_name = module_name
|
self.module_name = module_name
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.module_name == other.module_name
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"{self.module_name}"
|
return f"{self.module_name}"
|
||||||
|
|
||||||
@@ -213,6 +234,9 @@ class ID(Node):
|
|||||||
def __init__(self, name: str) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.name == other.name
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"ID({self.name})"
|
return f"ID({self.name})"
|
||||||
|
|
||||||
@@ -225,6 +249,9 @@ class Designa(Node):
|
|||||||
self.id = variable
|
self.id = variable
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.id == other.id and self.value == other.value
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
id_string = repr(self.id).replace('\n', '\n ')
|
id_string = repr(self.id).replace('\n', '\n ')
|
||||||
value_string = repr(self.value).replace('\n', '\n ')
|
value_string = repr(self.value).replace('\n', '\n ')
|
||||||
@@ -242,6 +269,9 @@ class Defini(Node):
|
|||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
self.statements = statements
|
self.statements = statements
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.name == other.name and self.parameters == other.parameters and self.statements == other.statements
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
||||||
statements_string = f"statements([{rep_join(self.statements)}])"
|
statements_string = f"statements([{rep_join(self.statements)}])"
|
||||||
@@ -259,6 +289,9 @@ class Redi(Node):
|
|||||||
def __init__(self, values) -> None:
|
def __init__(self, values) -> None:
|
||||||
self.values = values
|
self.values = values
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.values == other.values
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
values_string = f"[{rep_join(self.values)}]"
|
values_string = f"[{rep_join(self.values)}]"
|
||||||
return f"Redi({values_string})"
|
return f"Redi({values_string})"
|
||||||
@@ -276,6 +309,9 @@ class Redi(Node):
|
|||||||
|
|
||||||
|
|
||||||
class Erumpe(Node):
|
class Erumpe(Node):
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return "Erumpe()"
|
return "Erumpe()"
|
||||||
|
|
||||||
@@ -285,6 +321,9 @@ class Erumpe(Node):
|
|||||||
|
|
||||||
|
|
||||||
class Nullus(Node):
|
class Nullus(Node):
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return "Nullus()"
|
return "Nullus()"
|
||||||
|
|
||||||
@@ -298,6 +337,9 @@ class BinOp(Node):
|
|||||||
self.right = right
|
self.right = right
|
||||||
self.op = op
|
self.op = op
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.left == other.left and self.right == other.right and self.op == other.op
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
binop_string = rep_join([self.left, self.right, self.op])
|
binop_string = rep_join([self.left, self.right, self.op])
|
||||||
return f"BinOp({binop_string})"
|
return f"BinOp({binop_string})"
|
||||||
@@ -334,6 +376,9 @@ class UnaryMinus(Node):
|
|||||||
def __init__(self, expr):
|
def __init__(self, expr):
|
||||||
self.expr = expr
|
self.expr = expr
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.expr == other.expr
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"UnaryMinus({self.expr!r})"
|
return f"UnaryMinus({self.expr!r})"
|
||||||
|
|
||||||
@@ -347,6 +392,9 @@ class ArrayIndex(Node):
|
|||||||
self.array = array
|
self.array = array
|
||||||
self.index = index
|
self.index = index
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.array == other.array and self.index == other.index
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"ArrayIndex({self.array!r}, {self.index!r})"
|
return f"ArrayIndex({self.array!r}, {self.index!r})"
|
||||||
|
|
||||||
@@ -366,6 +414,9 @@ class SiStatement(Node):
|
|||||||
self.statements = statements
|
self.statements = statements
|
||||||
self.else_part = else_part
|
self.else_part = else_part
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.test == other.test and self.statements == other.statements and self.else_part == other.else_part
|
||||||
|
|
||||||
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)}])"
|
||||||
@@ -390,6 +441,9 @@ class DumStatement(Node):
|
|||||||
self.test = test
|
self.test = test
|
||||||
self.statements = statements
|
self.statements = statements
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.test == other.test and self.statements == other.statements
|
||||||
|
|
||||||
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)}])"
|
||||||
@@ -418,6 +472,9 @@ class PerStatement(Node):
|
|||||||
self.variable_name = variable_name
|
self.variable_name = variable_name
|
||||||
self.statements = statements
|
self.statements = statements
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.data_list == other.data_list and self.variable_name == other.variable_name and self.statements == other.statements
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
test = repr(self.data_list)
|
test = repr(self.data_list)
|
||||||
variable_name = repr(self.variable_name)
|
variable_name = repr(self.variable_name)
|
||||||
@@ -447,6 +504,9 @@ class Invoca(Node):
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.name == other.name and self.parameters == other.parameters
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
parameters_string = f"parameters([{rep_join(self.parameters)}])"
|
parameters_string = f"parameters([{rep_join(self.parameters)}])"
|
||||||
invoca_string = rep_join([self.name, parameters_string])
|
invoca_string = rep_join([self.name, parameters_string])
|
||||||
@@ -475,6 +535,9 @@ class BuiltIn(Node):
|
|||||||
self.builtin = builtin
|
self.builtin = builtin
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.builtin == other.builtin and self.parameters == other.parameters
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
||||||
builtin_string = rep_join([self.builtin, parameter_string])
|
builtin_string = rep_join([self.builtin, parameter_string])
|
||||||
@@ -521,6 +584,9 @@ class Program(BaseBox):
|
|||||||
self.modules = module_calls
|
self.modules = module_calls
|
||||||
self.statements = statements
|
self.statements = statements
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) == type(other) and self.modules == other.modules and self.statements == other.statements
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
modules_string = f"modules([{rep_join(self.modules)}])"
|
modules_string = f"modules([{rep_join(self.modules)}])"
|
||||||
statements_string = f"statements([{rep_join(self.statements)}])"
|
statements_string = f"statements([{rep_join(self.statements)}])"
|
||||||
|
|||||||
619
tests.py
619
tests.py
@@ -23,13 +23,14 @@ def run_test(self, source, target_nodes, target_value, target_output="", input_l
|
|||||||
program = Parser().parse(tokens)
|
program = Parser().parse(tokens)
|
||||||
|
|
||||||
##########################
|
##########################
|
||||||
####### Parser Test ###### (commented out — no __eq__ on AST nodes yet)
|
####### Parser Test ######
|
||||||
##########################
|
##########################
|
||||||
# self.assertEqual(
|
if target_nodes is not None:
|
||||||
# program,
|
self.assertEqual(
|
||||||
# target_nodes,
|
program,
|
||||||
# f"Parser test:\n{program}\n{target_nodes}"
|
target_nodes,
|
||||||
# )
|
f"Parser test:\n{program}\n{target_nodes}"
|
||||||
|
)
|
||||||
|
|
||||||
##########################
|
##########################
|
||||||
#### Interpreter Test ####
|
#### Interpreter Test ####
|
||||||
@@ -77,16 +78,16 @@ def run_test(self, source, target_nodes, target_value, target_output="", input_l
|
|||||||
# --- Output ---
|
# --- Output ---
|
||||||
|
|
||||||
output_tests = [
|
output_tests = [
|
||||||
("DICE(\"hello\")", None, ValStr("hello"), "hello\n"),
|
("DICE(\"hello\")", Program([], [ExpressionStatement(BuiltIn("DICE", [String("hello")]))]), ValStr("hello"), "hello\n"),
|
||||||
("DICE(\"world\")", None, ValStr("world"), "world\n"),
|
("DICE(\"world\")", Program([], [ExpressionStatement(BuiltIn("DICE", [String("world")]))]), ValStr("world"), "world\n"),
|
||||||
("DICE(III)", None, ValStr("III"), "III\n"),
|
("DICE(III)", Program([], [ExpressionStatement(BuiltIn("DICE", [Numeral("III")]))]), ValStr("III"), "III\n"),
|
||||||
("DICE(X)", None, ValStr("X"), "X\n"),
|
("DICE(X)", Program([], [ExpressionStatement(BuiltIn("DICE", [Numeral("X")]))]), ValStr("X"), "X\n"),
|
||||||
("DICE(MMXXV)", None, ValStr("MMXXV"), "MMXXV\n"),
|
("DICE(MMXXV)", Program([], [ExpressionStatement(BuiltIn("DICE", [Numeral("MMXXV")]))]), ValStr("MMXXV"), "MMXXV\n"),
|
||||||
("DICE('hello')", None, ValStr("hello"), "hello\n"),
|
("DICE('hello')", Program([], [ExpressionStatement(BuiltIn("DICE", [String("hello")]))]), ValStr("hello"), "hello\n"),
|
||||||
("DICE('world')", None, ValStr("world"), "world\n"),
|
("DICE('world')", Program([], [ExpressionStatement(BuiltIn("DICE", [String("world")]))]), ValStr("world"), "world\n"),
|
||||||
("DICE(\"a\", \"b\")", None, ValStr("a b"), "a b\n"),
|
("DICE(\"a\", \"b\")", Program([], [ExpressionStatement(BuiltIn("DICE", [String("a"), String("b")]))]), ValStr("a b"), "a b\n"),
|
||||||
("DICE(\"line one\")\nDICE(\"line two\")", None, ValStr("line two"), "line one\nline two\n"),
|
("DICE(\"line one\")\nDICE(\"line two\")", Program([], [ExpressionStatement(BuiltIn("DICE", [String("line one")])), ExpressionStatement(BuiltIn("DICE", [String("line two")]))]), ValStr("line two"), "line one\nline two\n"),
|
||||||
("DICE(DICE(II))", None, ValStr("II"), "II\nII\n"),
|
("DICE(DICE(II))", Program([], [ExpressionStatement(BuiltIn("DICE", [BuiltIn("DICE", [Numeral("II")])]))]), ValStr("II"), "II\nII\n"),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestOutput(unittest.TestCase):
|
class TestOutput(unittest.TestCase):
|
||||||
@@ -98,17 +99,17 @@ class TestOutput(unittest.TestCase):
|
|||||||
# --- Arithmetic ---
|
# --- Arithmetic ---
|
||||||
|
|
||||||
arithmetic_tests = [
|
arithmetic_tests = [
|
||||||
("I + I", None, ValInt(2)),
|
("I + I", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("I"), "SYMBOL_PLUS"))]), ValInt(2)),
|
||||||
("X - III", None, ValInt(7)),
|
("X - III", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("III"), "SYMBOL_MINUS"))]), ValInt(7)),
|
||||||
("III * IV", None, ValInt(12)),
|
("III * IV", Program([], [ExpressionStatement(BinOp(Numeral("III"), Numeral("IV"), "SYMBOL_TIMES"))]), ValInt(12)),
|
||||||
("X / II", None, ValInt(5)),
|
("X / II", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("II"), "SYMBOL_DIVIDE"))]), ValInt(5)),
|
||||||
("X / III", None, ValInt(3)), # integer division: 10 // 3 = 3
|
("X / III", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("III"), "SYMBOL_DIVIDE"))]), ValInt(3)), # integer division: 10 // 3 = 3
|
||||||
("II + III * IV", None, ValInt(14)), # precedence: 2 + (3*4) = 14
|
("II + III * IV", Program([], [ExpressionStatement(BinOp(Numeral("II"), BinOp(Numeral("III"), Numeral("IV"), "SYMBOL_TIMES"), "SYMBOL_PLUS"))]), ValInt(14)), # precedence: 2 + (3*4) = 14
|
||||||
("(II + III) * IV", None, ValInt(20)), # parens: (2+3)*4 = 20
|
("(II + III) * IV", Program([], [ExpressionStatement(BinOp(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS"), Numeral("IV"), "SYMBOL_TIMES"))]), ValInt(20)), # parens: (2+3)*4 = 20
|
||||||
("- III", None, ValInt(-3)), # unary negation
|
("- III", Program([], [ExpressionStatement(UnaryMinus(Numeral("III")))]), ValInt(-3)), # unary negation
|
||||||
("- (II + III)", None, ValInt(-5)), # unary negation of expression
|
("- (II + III)", Program([], [ExpressionStatement(UnaryMinus(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS")))]), ValInt(-5)), # unary negation of expression
|
||||||
("- - II", None, ValInt(2)), # double negation
|
("- - II", Program([], [ExpressionStatement(UnaryMinus(UnaryMinus(Numeral("II"))))]), ValInt(2)), # double negation
|
||||||
("III + - II", None, ValInt(1)), # unary in binary context
|
("III + - II", Program([], [ExpressionStatement(BinOp(Numeral("III"), UnaryMinus(Numeral("II")), "SYMBOL_PLUS"))]), ValInt(1)), # unary in binary context
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestArithmetic(unittest.TestCase):
|
class TestArithmetic(unittest.TestCase):
|
||||||
@@ -117,14 +118,93 @@ class TestArithmetic(unittest.TestCase):
|
|||||||
run_test(self, source, nodes, value)
|
run_test(self, source, nodes, value)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Precedence and associativity ---
|
||||||
|
#
|
||||||
|
# Precedence (lowest → highest):
|
||||||
|
# AVT < ET < (EST, PLVS, MINVS) < (+ -) < (* /) < UMINUS < INDEX
|
||||||
|
|
||||||
|
precedence_tests = [
|
||||||
|
# * binds tighter than -: 10 - (2*3) = 4, not (10-2)*3 = 24
|
||||||
|
("X - II * III",
|
||||||
|
Program([], [ExpressionStatement(BinOp(Numeral("X"), BinOp(Numeral("II"), Numeral("III"), "SYMBOL_TIMES"), "SYMBOL_MINUS"))]),
|
||||||
|
ValInt(4)),
|
||||||
|
# / binds tighter than +: (10/2) + 3 = 8, not 10/(2+3) = 2
|
||||||
|
("X / II + III",
|
||||||
|
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("X"), Numeral("II"), "SYMBOL_DIVIDE"), Numeral("III"), "SYMBOL_PLUS"))]),
|
||||||
|
ValInt(8)),
|
||||||
|
# + binds tighter than EST: (2+3)==5 = True, not 2+(3==5) = type error
|
||||||
|
("II + III EST V",
|
||||||
|
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS"), Numeral("V"), "KEYWORD_EST"))]),
|
||||||
|
ValBool(True)),
|
||||||
|
# * binds tighter than PLVS: (2*3)>4 = True
|
||||||
|
("II * III PLVS IV",
|
||||||
|
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_TIMES"), Numeral("IV"), "KEYWORD_PLVS"))]),
|
||||||
|
ValBool(True)),
|
||||||
|
# comparison binds tighter than ET: (1==2) AND (2==2) = False AND True = False
|
||||||
|
("I EST II ET II EST II",
|
||||||
|
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_EST"), BinOp(Numeral("II"), Numeral("II"), "KEYWORD_EST"), "KEYWORD_ET"))]),
|
||||||
|
ValBool(False)),
|
||||||
|
# ET binds tighter than AVT: True OR (False AND False) = True
|
||||||
|
("VERITAS AVT FALSITAS ET FALSITAS",
|
||||||
|
Program([], [ExpressionStatement(BinOp(Bool(True), BinOp(Bool(False), Bool(False), "KEYWORD_ET"), "KEYWORD_AVT"))]),
|
||||||
|
ValBool(True)),
|
||||||
|
# UMINUS binds tighter than *: (-2)*3 = -6, not -(2*3) = -6 (same value, different tree)
|
||||||
|
("- II * III",
|
||||||
|
Program([], [ExpressionStatement(BinOp(UnaryMinus(Numeral("II")), Numeral("III"), "SYMBOL_TIMES"))]),
|
||||||
|
ValInt(-6)),
|
||||||
|
# UMINUS binds tighter than +: (-2)+3 = 1, not -(2+3) = -5
|
||||||
|
("- II + III",
|
||||||
|
Program([], [ExpressionStatement(BinOp(UnaryMinus(Numeral("II")), Numeral("III"), "SYMBOL_PLUS"))]),
|
||||||
|
ValInt(1)),
|
||||||
|
# INDEX binds tighter than UMINUS: -(arr[I]) = -1
|
||||||
|
("- [(I, II, III)][I]",
|
||||||
|
Program([], [ExpressionStatement(UnaryMinus(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I"))))]),
|
||||||
|
ValInt(-1)),
|
||||||
|
# INDEX binds tighter than +: (arr[II]) + X = 2 + 10 = 12
|
||||||
|
("[(I, II, III)][II] + X",
|
||||||
|
Program([], [ExpressionStatement(BinOp(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("II")), Numeral("X"), "SYMBOL_PLUS"))]),
|
||||||
|
ValInt(12)),
|
||||||
|
# left-associativity of -: (10-3)-2 = 5, not 10-(3-2) = 9
|
||||||
|
("X - III - II",
|
||||||
|
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("X"), Numeral("III"), "SYMBOL_MINUS"), Numeral("II"), "SYMBOL_MINUS"))]),
|
||||||
|
ValInt(5)),
|
||||||
|
# left-associativity of /: (12/2)/3 = 2, not 12/(2/3) = 18
|
||||||
|
("XII / II / III",
|
||||||
|
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("XII"), Numeral("II"), "SYMBOL_DIVIDE"), Numeral("III"), "SYMBOL_DIVIDE"))]),
|
||||||
|
ValInt(2)),
|
||||||
|
# left-associativity of AVT: (False OR True) OR False = True
|
||||||
|
("FALSITAS AVT VERITAS AVT FALSITAS",
|
||||||
|
Program([], [ExpressionStatement(BinOp(BinOp(Bool(False), Bool(True), "KEYWORD_AVT"), Bool(False), "KEYWORD_AVT"))]),
|
||||||
|
ValBool(True)),
|
||||||
|
]
|
||||||
|
|
||||||
|
class TestPrecedence(unittest.TestCase):
|
||||||
|
@parameterized.expand(precedence_tests)
|
||||||
|
def test_precedence(self, source, nodes, value):
|
||||||
|
run_test(self, source, nodes, value)
|
||||||
|
|
||||||
|
|
||||||
# --- Assignment ---
|
# --- Assignment ---
|
||||||
|
|
||||||
assignment_tests = [
|
assignment_tests = [
|
||||||
("DESIGNA x VT III\nx", None, ValInt(3)),
|
("DESIGNA x VT III\nx",
|
||||||
("DESIGNA msg VT \"hello\"\nmsg", None, ValStr("hello")),
|
Program([], [Designa(ID("x"), Numeral("III")), ExpressionStatement(ID("x"))]),
|
||||||
("DESIGNA msg VT 'hello'\nmsg", None, ValStr("hello")),
|
ValInt(3)),
|
||||||
("DESIGNA a VT V\nDESIGNA b VT X\na + b", None, ValInt(15)),
|
("DESIGNA msg VT \"hello\"\nmsg",
|
||||||
("DESIGNA x VT II\nDESIGNA x VT x + I\nx", None, ValInt(3)),
|
Program([], [Designa(ID("msg"), String("hello")), ExpressionStatement(ID("msg"))]),
|
||||||
|
ValStr("hello")),
|
||||||
|
("DESIGNA msg VT 'hello'\nmsg",
|
||||||
|
Program([], [Designa(ID("msg"), String("hello")), ExpressionStatement(ID("msg"))]),
|
||||||
|
ValStr("hello")),
|
||||||
|
("DESIGNA a VT V\nDESIGNA b VT X\na + b",
|
||||||
|
Program([], [Designa(ID("a"), Numeral("V")), Designa(ID("b"), Numeral("X")),
|
||||||
|
ExpressionStatement(BinOp(ID("a"), ID("b"), "SYMBOL_PLUS"))]),
|
||||||
|
ValInt(15)),
|
||||||
|
("DESIGNA x VT II\nDESIGNA x VT x + I\nx",
|
||||||
|
Program([], [Designa(ID("x"), Numeral("II")),
|
||||||
|
Designa(ID("x"), BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")),
|
||||||
|
ExpressionStatement(ID("x"))]),
|
||||||
|
ValInt(3)),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestAssignment(unittest.TestCase):
|
class TestAssignment(unittest.TestCase):
|
||||||
@@ -137,37 +217,79 @@ class TestAssignment(unittest.TestCase):
|
|||||||
|
|
||||||
control_tests = [
|
control_tests = [
|
||||||
# SI without ALVID — true branch
|
# SI without ALVID — true branch
|
||||||
("SI VERITAS TVNC { DESIGNA r VT I }\nr", None, ValInt(1)),
|
("SI VERITAS TVNC { DESIGNA r VT I }\nr",
|
||||||
|
Program([], [SiStatement(Bool(True), [Designa(ID("r"), Numeral("I"))], None), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(1)),
|
||||||
# SI without ALVID — false branch
|
# SI without ALVID — false branch
|
||||||
("SI FALSITAS TVNC { DESIGNA r VT I }", None, ValNul()),
|
("SI FALSITAS TVNC { DESIGNA r VT I }",
|
||||||
|
Program([], [SiStatement(Bool(False), [Designa(ID("r"), Numeral("I"))], None)]),
|
||||||
|
ValNul()),
|
||||||
# SI with ALVID — true branch
|
# SI with ALVID — true branch
|
||||||
("SI VERITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
("SI VERITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [SiStatement(Bool(True), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(1)),
|
||||||
# SI with ALVID — false branch
|
# SI with ALVID — false branch
|
||||||
("SI FALSITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
("SI FALSITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [SiStatement(Bool(False), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(2)),
|
||||||
# SI with comparison — equal
|
# SI with comparison — equal
|
||||||
("SI I EST I TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
("SI I EST I TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [SiStatement(BinOp(Numeral("I"), Numeral("I"), "KEYWORD_EST"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(1)),
|
||||||
# SI with comparison — unequal
|
# SI with comparison — unequal
|
||||||
("SI I EST II TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
("SI I EST II TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [SiStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_EST"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(2)),
|
||||||
# SI MINVS
|
# SI MINVS
|
||||||
("SI I MINVS II TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
("SI I MINVS II TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [SiStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_MINVS"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(1)),
|
||||||
# SI PLVS
|
# SI PLVS
|
||||||
("SI II PLVS I TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
("SI II PLVS I TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [SiStatement(BinOp(Numeral("II"), Numeral("I"), "KEYWORD_PLVS"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(1)),
|
||||||
# ALVID SI chain
|
# ALVID SI chain
|
||||||
(
|
(
|
||||||
"SI I EST II TVNC { DESIGNA r VT I } ALVID SI I EST I TVNC { DESIGNA r VT II } ALVID { DESIGNA r VT III }\nr",
|
"SI I EST II TVNC { DESIGNA r VT I } ALVID SI I EST I TVNC { DESIGNA r VT II } ALVID { DESIGNA r VT III }\nr",
|
||||||
None, ValInt(2),
|
Program([], [
|
||||||
|
SiStatement(
|
||||||
|
BinOp(Numeral("I"), Numeral("II"), "KEYWORD_EST"),
|
||||||
|
[Designa(ID("r"), Numeral("I"))],
|
||||||
|
[SiStatement(
|
||||||
|
BinOp(Numeral("I"), Numeral("I"), "KEYWORD_EST"),
|
||||||
|
[Designa(ID("r"), Numeral("II"))],
|
||||||
|
[Designa(ID("r"), Numeral("III"))],
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
ExpressionStatement(ID("r")),
|
||||||
|
]),
|
||||||
|
ValInt(2),
|
||||||
),
|
),
|
||||||
# DVM (while not): loops until condition is true
|
# DVM (while not): loops until condition is true
|
||||||
(
|
(
|
||||||
"DESIGNA x VT I\nDVM x EST III FACE {\nDESIGNA x VT x + I\n}\nx",
|
"DESIGNA x VT I\nDVM x EST III FACE {\nDESIGNA x VT x + I\n}\nx",
|
||||||
None, ValInt(3),
|
Program([], [
|
||||||
|
Designa(ID("x"), Numeral("I")),
|
||||||
|
DumStatement(BinOp(ID("x"), Numeral("III"), "KEYWORD_EST"), [Designa(ID("x"), BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS"))]),
|
||||||
|
ExpressionStatement(ID("x")),
|
||||||
|
]),
|
||||||
|
ValInt(3),
|
||||||
),
|
),
|
||||||
# DVM with ERVMPE — loop body prints (testing DICE + ERVMPE together)
|
# DVM with ERVMPE — loop body prints (testing DICE + ERVMPE together)
|
||||||
("DESIGNA x VT I\nDVM FALSITAS FACE {\nDICE(x)\nERVMPE\n}", None, ValStr("I"), "I\n"),
|
("DESIGNA x VT I\nDVM FALSITAS FACE {\nDICE(x)\nERVMPE\n}",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("x"), Numeral("I")),
|
||||||
|
DumStatement(Bool(False), [ExpressionStatement(BuiltIn("DICE", [ID("x")])), Erumpe()]),
|
||||||
|
]),
|
||||||
|
ValStr("I"), "I\n"),
|
||||||
# PER foreach
|
# PER foreach
|
||||||
("PER i IN [(I, II, III)] FACE { DICE(i) }", None, ValStr("III"), "I\nII\nIII\n"),
|
("PER i IN [(I, II, III)] FACE { DICE(i) }",
|
||||||
|
Program([], [PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
||||||
|
ValStr("III"), "I\nII\nIII\n"),
|
||||||
# DONICVM range loop
|
# DONICVM range loop
|
||||||
("DONICVM i VT I VSQVE V FACE { DICE(i) }", None, ValStr("IV"), "I\nII\nIII\nIV\n"),
|
("DONICVM i VT I VSQVE V FACE { DICE(i) }",
|
||||||
|
Program([], [PerStatement(DataRangeArray(Numeral("I"), Numeral("V")), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
||||||
|
ValStr("IV"), "I\nII\nIII\nIV\n"),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestControl(unittest.TestCase):
|
class TestControl(unittest.TestCase):
|
||||||
@@ -181,16 +303,38 @@ class TestControl(unittest.TestCase):
|
|||||||
function_tests = [
|
function_tests = [
|
||||||
(
|
(
|
||||||
"DEFINI bis (n) VT { REDI (n * II) }\nINVOCA bis (III)",
|
"DEFINI bis (n) VT { REDI (n * II) }\nINVOCA bis (III)",
|
||||||
None, ValInt(6),
|
Program([], [
|
||||||
|
Defini(ID("bis"), [ID("n")], [Redi([BinOp(ID("n"), Numeral("II"), "SYMBOL_TIMES")])]),
|
||||||
|
ExpressionStatement(Invoca(ID("bis"), [Numeral("III")])),
|
||||||
|
]),
|
||||||
|
ValInt(6),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"DEFINI add (a, b) VT { REDI (a + b) }\nINVOCA add (III, IV)",
|
"DEFINI add (a, b) VT { REDI (a + b) }\nINVOCA add (III, IV)",
|
||||||
None, ValInt(7),
|
Program([], [
|
||||||
|
Defini(ID("add"), [ID("a"), ID("b")], [Redi([BinOp(ID("a"), ID("b"), "SYMBOL_PLUS")])]),
|
||||||
|
ExpressionStatement(Invoca(ID("add"), [Numeral("III"), Numeral("IV")])),
|
||||||
|
]),
|
||||||
|
ValInt(7),
|
||||||
),
|
),
|
||||||
# Fibonacci: fib(n<3)=1, fib(n)=fib(n-1)+fib(n-2)
|
# Fibonacci: fib(n<3)=1, fib(n)=fib(n-1)+fib(n-2)
|
||||||
(
|
(
|
||||||
"DEFINI fib (n) VT {\nSI n MINVS III TVNC { REDI (I) } ALVID { REDI (INVOCA fib (n - I) + INVOCA fib (n - II)) }\n}\nINVOCA fib (VII)",
|
"DEFINI fib (n) VT {\nSI n MINVS III TVNC { REDI (I) } ALVID { REDI (INVOCA fib (n - I) + INVOCA fib (n - II)) }\n}\nINVOCA fib (VII)",
|
||||||
None, ValInt(13),
|
Program([], [
|
||||||
|
Defini(ID("fib"), [ID("n")], [
|
||||||
|
SiStatement(
|
||||||
|
BinOp(ID("n"), Numeral("III"), "KEYWORD_MINVS"),
|
||||||
|
[Redi([Numeral("I")])],
|
||||||
|
[Redi([BinOp(
|
||||||
|
Invoca(ID("fib"), [BinOp(ID("n"), Numeral("I"), "SYMBOL_MINUS")]),
|
||||||
|
Invoca(ID("fib"), [BinOp(ID("n"), Numeral("II"), "SYMBOL_MINUS")]),
|
||||||
|
"SYMBOL_PLUS",
|
||||||
|
)])],
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
ExpressionStatement(Invoca(ID("fib"), [Numeral("VII")])),
|
||||||
|
]),
|
||||||
|
ValInt(13),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -203,12 +347,12 @@ class TestFunctions(unittest.TestCase):
|
|||||||
# --- Builtins ---
|
# --- Builtins ---
|
||||||
|
|
||||||
builtin_tests = [
|
builtin_tests = [
|
||||||
("AVDI_NVMERVS()", None, ValInt(3), "", ["III"]),
|
("AVDI_NVMERVS()", Program([], [ExpressionStatement(BuiltIn("AVDI_NVMERVS", []))]), ValInt(3), "", ["III"]),
|
||||||
("AVDI_NVMERVS()", None, ValInt(10), "", ["X"]),
|
("AVDI_NVMERVS()", Program([], [ExpressionStatement(BuiltIn("AVDI_NVMERVS", []))]), ValInt(10), "", ["X"]),
|
||||||
("CVM FORS\nFORTIS_NVMERVS(I, X)", None, ValInt(3)),
|
("CVM FORS\nFORTIS_NVMERVS(I, X)", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("FORTIS_NVMERVS", [Numeral("I"), Numeral("X")]))]), ValInt(3)),
|
||||||
("AVDI()", None, ValStr("hello"), "", ["hello"]),
|
("AVDI()", Program([], [ExpressionStatement(BuiltIn("AVDI", []))]), ValStr("hello"), "", ["hello"]),
|
||||||
("LONGITVDO([(I, II, III)])", None, ValInt(3)),
|
("LONGITVDO([(I, II, III)])", Program([], [ExpressionStatement(BuiltIn("LONGITVDO", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValInt(3)),
|
||||||
("CVM FORS\nFORTIS_ELECTIONIS([(I, II, III)])", None, ValInt(1)),
|
("CVM FORS\nFORTIS_ELECTIONIS([(I, II, III)])", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("FORTIS_ELECTIONIS", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValInt(1)),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestBuiltins(unittest.TestCase):
|
class TestBuiltins(unittest.TestCase):
|
||||||
@@ -364,15 +508,15 @@ class TestMakeString(unittest.TestCase):
|
|||||||
# --- DICE with non-integer types ---
|
# --- DICE with non-integer types ---
|
||||||
|
|
||||||
dice_type_tests = [
|
dice_type_tests = [
|
||||||
("DICE(VERITAS)", None, ValStr("VERVS"), "VERVS\n"),
|
("DICE(VERITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(True)]))]), ValStr("VERVS"), "VERVS\n"),
|
||||||
("DICE(FALSITAS)", None, ValStr("FALSVS"), "FALSVS\n"),
|
("DICE(FALSITAS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Bool(False)]))]), ValStr("FALSVS"), "FALSVS\n"),
|
||||||
("DICE(NVLLVS)", None, ValStr("NVLLVS"), "NVLLVS\n"),
|
("DICE(NVLLVS)", Program([], [ExpressionStatement(BuiltIn("DICE", [Nullus()]))]), ValStr("NVLLVS"), "NVLLVS\n"),
|
||||||
('DICE([(I, II)])', None, 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("")', None, ValStr(""), "\n"),
|
('DICE("")', Program([], [ExpressionStatement(BuiltIn("DICE", [String("")]))]), ValStr(""), "\n"),
|
||||||
# arithmetic result printed as numeral
|
# arithmetic result printed as numeral
|
||||||
("DICE(II + III)", None, 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)', None, ValStr("x VERVS"), "x VERVS\n"),
|
('DICE("x", VERITAS)', Program([], [ExpressionStatement(BuiltIn("DICE", [String("x"), Bool(True)]))]), ValStr("x VERVS"), "x VERVS\n"),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestDiceTypes(unittest.TestCase):
|
class TestDiceTypes(unittest.TestCase):
|
||||||
@@ -385,17 +529,34 @@ class TestDiceTypes(unittest.TestCase):
|
|||||||
|
|
||||||
truthiness_tests = [
|
truthiness_tests = [
|
||||||
# nonzero int is truthy
|
# nonzero int is truthy
|
||||||
("SI I TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
("SI I TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [SiStatement(Numeral("I"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(1)),
|
||||||
# zero int is falsy
|
# zero int is falsy
|
||||||
("DESIGNA z VT I - I\nSI z TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
("DESIGNA z VT I - I\nSI z TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("z"), BinOp(Numeral("I"), Numeral("I"), "SYMBOL_MINUS")),
|
||||||
|
SiStatement(ID("z"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]),
|
||||||
|
ExpressionStatement(ID("r")),
|
||||||
|
]),
|
||||||
|
ValInt(2)),
|
||||||
# non-empty list is truthy
|
# non-empty list is truthy
|
||||||
("SI [(I)] TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
("SI [(I)] TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [SiStatement(DataArray([Numeral("I")]), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(1)),
|
||||||
# empty list is falsy
|
# empty list is falsy
|
||||||
("SI [()] TVNC { DESIGNA r VT II } ALVID { DESIGNA r VT I }\nr", None, ValInt(1)),
|
("SI [()] TVNC { DESIGNA r VT II } ALVID { DESIGNA r VT I }\nr",
|
||||||
|
Program([], [SiStatement(DataArray([]), [Designa(ID("r"), Numeral("II"))], [Designa(ID("r"), Numeral("I"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(1)),
|
||||||
# DVM exits when condition becomes truthy
|
# DVM exits when condition becomes truthy
|
||||||
(
|
(
|
||||||
"DESIGNA x VT I\nDVM x PLVS III FACE {\nDESIGNA x VT x + I\n}\nx",
|
"DESIGNA x VT I\nDVM x PLVS III FACE {\nDESIGNA x VT x + I\n}\nx",
|
||||||
None, ValInt(4),
|
Program([], [
|
||||||
|
Designa(ID("x"), Numeral("I")),
|
||||||
|
DumStatement(BinOp(ID("x"), Numeral("III"), "KEYWORD_PLVS"), [Designa(ID("x"), BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS"))]),
|
||||||
|
ExpressionStatement(ID("x")),
|
||||||
|
]),
|
||||||
|
ValInt(4),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -408,11 +569,11 @@ class TestTruthiness(unittest.TestCase):
|
|||||||
# --- Arithmetic: edge cases ---
|
# --- Arithmetic: edge cases ---
|
||||||
|
|
||||||
arithmetic_edge_tests = [
|
arithmetic_edge_tests = [
|
||||||
("I - I", None, ValInt(0)), # result zero
|
("I - I", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("I"), "SYMBOL_MINUS"))]), ValInt(0)), # result zero
|
||||||
("I - V", None, ValInt(-4)), # negative result
|
("I - V", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("V"), "SYMBOL_MINUS"))]), ValInt(-4)), # negative result
|
||||||
("I / V", None, ValInt(0)), # integer division → 0
|
("I / V", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("V"), "SYMBOL_DIVIDE"))]), ValInt(0)), # integer division → 0
|
||||||
("M * M", None, ValInt(1000000)), # large intermediate (not displayed)
|
("M * M", Program([], [ExpressionStatement(BinOp(Numeral("M"), Numeral("M"), "SYMBOL_TIMES"))]), ValInt(1000000)), # large intermediate (not displayed)
|
||||||
("(I + II) * (IV - I)", None, ValInt(9)), # nested parens
|
("(I + II) * (IV - I)", Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("II"), "SYMBOL_PLUS"), BinOp(Numeral("IV"), Numeral("I"), "SYMBOL_MINUS"), "SYMBOL_TIMES"))]), ValInt(9)), # nested parens
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestArithmeticEdge(unittest.TestCase):
|
class TestArithmeticEdge(unittest.TestCase):
|
||||||
@@ -425,18 +586,22 @@ class TestArithmeticEdge(unittest.TestCase):
|
|||||||
|
|
||||||
comparison_tests = [
|
comparison_tests = [
|
||||||
# EST on strings
|
# EST on strings
|
||||||
('\"hello\" EST \"hello\"', None, ValBool(True)),
|
('\"hello\" EST \"hello\"', Program([], [ExpressionStatement(BinOp(String("hello"), String("hello"), "KEYWORD_EST"))]), ValBool(True)),
|
||||||
('\"hello\" EST \"world\"', None, ValBool(False)),
|
('\"hello\" EST \"world\"', Program([], [ExpressionStatement(BinOp(String("hello"), String("world"), "KEYWORD_EST"))]), ValBool(False)),
|
||||||
# chain comparisons as conditions
|
# chain comparisons as conditions
|
||||||
("SI III PLVS II TVNC { DESIGNA r VT I }\nr", None, ValInt(1)),
|
("SI III PLVS II TVNC { DESIGNA r VT I }\nr",
|
||||||
("SI II PLVS III TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
Program([], [SiStatement(BinOp(Numeral("III"), Numeral("II"), "KEYWORD_PLVS"), [Designa(ID("r"), Numeral("I"))], None), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(1)),
|
||||||
|
("SI II PLVS III TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [SiStatement(BinOp(Numeral("II"), Numeral("III"), "KEYWORD_PLVS"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(2)),
|
||||||
# result of comparison is ValBool
|
# result of comparison is ValBool
|
||||||
("I EST I", None, ValBool(True)),
|
("I EST I", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("I"), "KEYWORD_EST"))]), ValBool(True)),
|
||||||
("I EST II", None, ValBool(False)),
|
("I EST II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_EST"))]), ValBool(False)),
|
||||||
("I MINVS II", None, ValBool(True)),
|
("I MINVS II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_MINVS"))]), ValBool(True)),
|
||||||
("II MINVS I", None, ValBool(False)),
|
("II MINVS I", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("I"), "KEYWORD_MINVS"))]), ValBool(False)),
|
||||||
("II PLVS I", None, ValBool(True)),
|
("II PLVS I", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("I"), "KEYWORD_PLVS"))]), ValBool(True)),
|
||||||
("I PLVS II", None, ValBool(False)),
|
("I PLVS II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_PLVS"))]), ValBool(False)),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestComparisons(unittest.TestCase):
|
class TestComparisons(unittest.TestCase):
|
||||||
@@ -449,38 +614,72 @@ class TestComparisons(unittest.TestCase):
|
|||||||
|
|
||||||
function_edge_tests = [
|
function_edge_tests = [
|
||||||
# no explicit REDI → returns ValNul
|
# no explicit REDI → returns ValNul
|
||||||
("DEFINI f () VT { I }\nINVOCA f ()", None, ValNul()),
|
("DEFINI f () VT { I }\nINVOCA f ()",
|
||||||
|
Program([], [Defini(ID("f"), [], [ExpressionStatement(Numeral("I"))]), ExpressionStatement(Invoca(ID("f"), []))]),
|
||||||
|
ValNul()),
|
||||||
# REDI multiple values → ValList
|
# REDI multiple values → ValList
|
||||||
(
|
(
|
||||||
"DEFINI pair (a, b) VT { REDI (a, b) }\nINVOCA pair (I, II)",
|
"DEFINI pair (a, b) VT { REDI (a, b) }\nINVOCA pair (I, II)",
|
||||||
None, ValList([ValInt(1), ValInt(2)]),
|
Program([], [
|
||||||
|
Defini(ID("pair"), [ID("a"), ID("b")], [Redi([ID("a"), ID("b")])]),
|
||||||
|
ExpressionStatement(Invoca(ID("pair"), [Numeral("I"), Numeral("II")])),
|
||||||
|
]),
|
||||||
|
ValList([ValInt(1), ValInt(2)]),
|
||||||
),
|
),
|
||||||
# function doesn't mutate outer vtable
|
# function doesn't mutate outer vtable
|
||||||
(
|
(
|
||||||
"DESIGNA x VT I\nDEFINI f () VT { DESIGNA x VT V\nREDI (x) }\nINVOCA f ()\nx",
|
"DESIGNA x VT I\nDEFINI f () VT { DESIGNA x VT V\nREDI (x) }\nINVOCA f ()\nx",
|
||||||
None, ValInt(1),
|
Program([], [
|
||||||
|
Designa(ID("x"), Numeral("I")),
|
||||||
|
Defini(ID("f"), [], [Designa(ID("x"), Numeral("V")), Redi([ID("x")])]),
|
||||||
|
ExpressionStatement(Invoca(ID("f"), [])),
|
||||||
|
ExpressionStatement(ID("x")),
|
||||||
|
]),
|
||||||
|
ValInt(1),
|
||||||
),
|
),
|
||||||
# function can read outer vtable (closure-like)
|
# function can read outer vtable (closure-like)
|
||||||
(
|
(
|
||||||
"DESIGNA x VT VII\nDEFINI f () VT { REDI (x) }\nINVOCA f ()",
|
"DESIGNA x VT VII\nDEFINI f () VT { REDI (x) }\nINVOCA f ()",
|
||||||
None, ValInt(7),
|
Program([], [
|
||||||
|
Designa(ID("x"), Numeral("VII")),
|
||||||
|
Defini(ID("f"), [], [Redi([ID("x")])]),
|
||||||
|
ExpressionStatement(Invoca(ID("f"), [])),
|
||||||
|
]),
|
||||||
|
ValInt(7),
|
||||||
),
|
),
|
||||||
# function defined after use is still a parse error (definition must precede call at runtime)
|
# 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)
|
# (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",
|
||||||
None, ValInt(1),
|
Program([], [
|
||||||
|
Designa(ID("n"), Numeral("I")),
|
||||||
|
Defini(ID("f"), [ID("n")], [Redi([BinOp(ID("n"), Numeral("II"), "SYMBOL_TIMES")])]),
|
||||||
|
ExpressionStatement(Invoca(ID("f"), [Numeral("X")])),
|
||||||
|
ExpressionStatement(ID("n")),
|
||||||
|
]),
|
||||||
|
ValInt(1),
|
||||||
),
|
),
|
||||||
# function aliasing: assign f to g, invoke via g
|
# function aliasing: assign f to g, invoke via g
|
||||||
(
|
(
|
||||||
"DEFINI f (n) VT { REDI (n * II) }\nDESIGNA g VT f\nINVOCA g (V)",
|
"DEFINI f (n) VT { REDI (n * II) }\nDESIGNA g VT f\nINVOCA g (V)",
|
||||||
None, ValInt(10),
|
Program([], [
|
||||||
|
Defini(ID("f"), [ID("n")], [Redi([BinOp(ID("n"), Numeral("II"), "SYMBOL_TIMES")])]),
|
||||||
|
Designa(ID("g"), ID("f")),
|
||||||
|
ExpressionStatement(Invoca(ID("g"), [Numeral("V")])),
|
||||||
|
]),
|
||||||
|
ValInt(10),
|
||||||
),
|
),
|
||||||
# alias is independent: redefining f doesn't affect g
|
# alias is independent: redefining f doesn't affect g
|
||||||
(
|
(
|
||||||
"DEFINI f (n) VT { REDI (n * II) }\nDESIGNA g VT f\nDEFINI f (n) VT { REDI (n * III) }\nINVOCA g (V)",
|
"DEFINI f (n) VT { REDI (n * II) }\nDESIGNA g VT f\nDEFINI f (n) VT { REDI (n * III) }\nINVOCA g (V)",
|
||||||
None, ValInt(10),
|
Program([], [
|
||||||
|
Defini(ID("f"), [ID("n")], [Redi([BinOp(ID("n"), Numeral("II"), "SYMBOL_TIMES")])]),
|
||||||
|
Designa(ID("g"), ID("f")),
|
||||||
|
Defini(ID("f"), [ID("n")], [Redi([BinOp(ID("n"), Numeral("III"), "SYMBOL_TIMES")])]),
|
||||||
|
ExpressionStatement(Invoca(ID("g"), [Numeral("V")])),
|
||||||
|
]),
|
||||||
|
ValInt(10),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -494,20 +693,61 @@ class TestFunctionEdge(unittest.TestCase):
|
|||||||
|
|
||||||
loop_edge_tests = [
|
loop_edge_tests = [
|
||||||
# range(3, 3) is empty — body never runs, program returns ValNul
|
# range(3, 3) is empty — body never runs, program returns ValNul
|
||||||
("DONICVM i VT III VSQVE III FACE { DICE(i) }", None, ValNul(), ""),
|
("DONICVM i VT III VSQVE III FACE { DICE(i) }",
|
||||||
|
Program([], [PerStatement(DataRangeArray(Numeral("III"), Numeral("III")), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
||||||
|
ValNul(), ""),
|
||||||
# empty array — body never runs
|
# empty array — body never runs
|
||||||
("PER i IN [()] FACE { DICE(i) }", None, ValNul(), ""),
|
("PER i IN [()] FACE { DICE(i) }",
|
||||||
|
Program([], [PerStatement(DataArray([]), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
||||||
|
ValNul(), ""),
|
||||||
# PER breaks on element 2 — last assigned i is 2
|
# PER breaks on element 2 — last assigned i is 2
|
||||||
("PER i IN [(I, II, III)] FACE { SI i EST II TVNC { ERVMPE } }\ni", None, ValInt(2), ""),
|
("PER i IN [(I, II, III)] FACE { SI i EST II TVNC { ERVMPE } }\ni",
|
||||||
|
Program([], [
|
||||||
|
PerStatement(
|
||||||
|
DataArray([Numeral("I"), Numeral("II"), Numeral("III")]),
|
||||||
|
ID("i"),
|
||||||
|
[SiStatement(BinOp(ID("i"), Numeral("II"), "KEYWORD_EST"), [Erumpe()], None)],
|
||||||
|
),
|
||||||
|
ExpressionStatement(ID("i")),
|
||||||
|
]),
|
||||||
|
ValInt(2), ""),
|
||||||
# nested DVM: inner always breaks; outer runs until btr==3
|
# nested DVM: inner always breaks; outer runs until btr==3
|
||||||
("DESIGNA btr VT I\nDVM btr EST III FACE {\nDVM FALSITAS FACE {\nERVMPE\n}\nDESIGNA btr VT btr + I\n}\nbtr", None, ValInt(3), ""),
|
("DESIGNA btr VT I\nDVM btr EST III FACE {\nDVM FALSITAS FACE {\nERVMPE\n}\nDESIGNA btr VT btr + I\n}\nbtr",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("btr"), Numeral("I")),
|
||||||
|
DumStatement(
|
||||||
|
BinOp(ID("btr"), Numeral("III"), "KEYWORD_EST"),
|
||||||
|
[DumStatement(Bool(False), [Erumpe()]), Designa(ID("btr"), BinOp(ID("btr"), Numeral("I"), "SYMBOL_PLUS"))],
|
||||||
|
),
|
||||||
|
ExpressionStatement(ID("btr")),
|
||||||
|
]),
|
||||||
|
ValInt(3), ""),
|
||||||
# nested PER: inner always breaks on first element; outer completes both iterations
|
# nested PER: inner always breaks on first element; outer completes both iterations
|
||||||
# cnt starts at 1, increments twice → 3
|
# cnt starts at 1, increments twice → 3
|
||||||
("DESIGNA cnt VT I\nPER i IN [(I, II)] FACE {\nPER k IN [(I, II)] FACE {\nERVMPE\n}\nDESIGNA cnt VT cnt + I\n}\ncnt", None, ValInt(3), ""),
|
("DESIGNA cnt VT I\nPER i IN [(I, II)] FACE {\nPER k IN [(I, II)] FACE {\nERVMPE\n}\nDESIGNA cnt VT cnt + I\n}\ncnt",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("cnt"), Numeral("I")),
|
||||||
|
PerStatement(
|
||||||
|
DataArray([Numeral("I"), Numeral("II")]),
|
||||||
|
ID("i"),
|
||||||
|
[PerStatement(DataArray([Numeral("I"), Numeral("II")]), ID("k"), [Erumpe()]),
|
||||||
|
Designa(ID("cnt"), BinOp(ID("cnt"), Numeral("I"), "SYMBOL_PLUS"))],
|
||||||
|
),
|
||||||
|
ExpressionStatement(ID("cnt")),
|
||||||
|
]),
|
||||||
|
ValInt(3), ""),
|
||||||
# DVM condition true from start — body never runs
|
# DVM condition true from start — body never runs
|
||||||
("DESIGNA x VT I\nDVM VERITAS FACE {\nDESIGNA x VT x + I\n}\nx", None, ValInt(1), ""),
|
("DESIGNA x VT I\nDVM VERITAS FACE {\nDESIGNA x VT x + I\n}\nx",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("x"), Numeral("I")),
|
||||||
|
DumStatement(Bool(True), [Designa(ID("x"), BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS"))]),
|
||||||
|
ExpressionStatement(ID("x")),
|
||||||
|
]),
|
||||||
|
ValInt(1), ""),
|
||||||
# single iteration: [I VSQVE II] = [1]
|
# single iteration: [I VSQVE II] = [1]
|
||||||
("DONICVM i VT I VSQVE II FACE { DICE(i) }", None, ValStr("I"), "I\n"),
|
("DONICVM i VT I VSQVE II FACE { DICE(i) }",
|
||||||
|
Program([], [PerStatement(DataRangeArray(Numeral("I"), Numeral("II")), ID("i"), [ExpressionStatement(BuiltIn("DICE", [ID("i")]))])]),
|
||||||
|
ValStr("I"), "I\n"),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestLoopEdge(unittest.TestCase):
|
class TestLoopEdge(unittest.TestCase):
|
||||||
@@ -567,11 +807,17 @@ class TestValues(unittest.TestCase):
|
|||||||
|
|
||||||
magnvm_tests = [
|
magnvm_tests = [
|
||||||
# M+M+M+M = 4000; MAGNVM allows display as "MV_"
|
# M+M+M+M = 4000; MAGNVM allows display as "MV_"
|
||||||
("CVM MAGNVM\nDICE(M + M + M + M)", None, ValStr("MV_"), "MV_\n"),
|
("CVM MAGNVM\nDICE(M + M + M + M)",
|
||||||
|
Program([ModuleCall("MAGNVM")], [ExpressionStatement(BuiltIn("DICE", [BinOp(BinOp(BinOp(Numeral("M"), Numeral("M"), "SYMBOL_PLUS"), Numeral("M"), "SYMBOL_PLUS"), Numeral("M"), "SYMBOL_PLUS")]))]),
|
||||||
|
ValStr("MV_"), "MV_\n"),
|
||||||
# I_ = 1000 with MAGNVM (same value as M, but written with thousands operator)
|
# I_ = 1000 with MAGNVM (same value as M, but written with thousands operator)
|
||||||
("CVM MAGNVM\nI_", None, ValInt(1000), ""),
|
("CVM MAGNVM\nI_",
|
||||||
|
Program([ModuleCall("MAGNVM")], [ExpressionStatement(Numeral("I_"))]),
|
||||||
|
ValInt(1000), ""),
|
||||||
# I_ + I_ = 2000; displayed as MM with MAGNVM
|
# I_ + I_ = 2000; displayed as MM with MAGNVM
|
||||||
("CVM MAGNVM\nDICE(I_ + I_)", None, ValStr("MM"), "MM\n"),
|
("CVM MAGNVM\nDICE(I_ + I_)",
|
||||||
|
Program([ModuleCall("MAGNVM")], [ExpressionStatement(BuiltIn("DICE", [BinOp(Numeral("I_"), Numeral("I_"), "SYMBOL_PLUS")]))]),
|
||||||
|
ValStr("MM"), "MM\n"),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestMAGNVM(unittest.TestCase):
|
class TestMAGNVM(unittest.TestCase):
|
||||||
@@ -583,20 +829,28 @@ class TestMAGNVM(unittest.TestCase):
|
|||||||
# --- ET and AVT (boolean and/or) ---
|
# --- ET and AVT (boolean and/or) ---
|
||||||
|
|
||||||
et_avt_tests = [
|
et_avt_tests = [
|
||||||
("VERITAS ET VERITAS", None, ValBool(True)),
|
("VERITAS ET VERITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(True), "KEYWORD_ET"))]), ValBool(True)),
|
||||||
("VERITAS ET FALSITAS", None, ValBool(False)),
|
("VERITAS ET FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(False), "KEYWORD_ET"))]), ValBool(False)),
|
||||||
("FALSITAS ET VERITAS", None, ValBool(False)),
|
("FALSITAS ET VERITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(True), "KEYWORD_ET"))]), ValBool(False)),
|
||||||
("FALSITAS ET FALSITAS", None, ValBool(False)),
|
("FALSITAS ET FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(False), "KEYWORD_ET"))]), ValBool(False)),
|
||||||
("VERITAS AVT VERITAS", None, ValBool(True)),
|
("VERITAS AVT VERITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(True), "KEYWORD_AVT"))]), ValBool(True)),
|
||||||
("VERITAS AVT FALSITAS", None, ValBool(True)),
|
("VERITAS AVT FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(False), "KEYWORD_AVT"))]), ValBool(True)),
|
||||||
("FALSITAS AVT VERITAS", None, ValBool(True)),
|
("FALSITAS AVT VERITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(True), "KEYWORD_AVT"))]), ValBool(True)),
|
||||||
("FALSITAS AVT FALSITAS", None, ValBool(False)),
|
("FALSITAS AVT FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(False), "KEYWORD_AVT"))]), ValBool(False)),
|
||||||
# short-circuit behaviour: combined with comparisons
|
# short-circuit behaviour: combined with comparisons
|
||||||
("(I EST I) ET (II EST II)", None, ValBool(True)),
|
("(I EST I) ET (II EST II)",
|
||||||
("(I EST II) AVT (II EST II)", None, ValBool(True)),
|
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("I"), "KEYWORD_EST"), BinOp(Numeral("II"), Numeral("II"), "KEYWORD_EST"), "KEYWORD_ET"))]),
|
||||||
|
ValBool(True)),
|
||||||
|
("(I EST II) AVT (II EST II)",
|
||||||
|
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_EST"), BinOp(Numeral("II"), Numeral("II"), "KEYWORD_EST"), "KEYWORD_AVT"))]),
|
||||||
|
ValBool(True)),
|
||||||
# used as SI condition
|
# used as SI condition
|
||||||
("SI VERITAS ET VERITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
("SI VERITAS ET VERITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
("SI FALSITAS AVT FALSITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
Program([], [SiStatement(BinOp(Bool(True), Bool(True), "KEYWORD_ET"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(1)),
|
||||||
|
("SI FALSITAS AVT FALSITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||||
|
Program([], [SiStatement(BinOp(Bool(False), Bool(False), "KEYWORD_AVT"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(2)),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestEtAvt(unittest.TestCase):
|
class TestEtAvt(unittest.TestCase):
|
||||||
@@ -610,13 +864,15 @@ class TestEtAvt(unittest.TestCase):
|
|||||||
|
|
||||||
array_index_tests = [
|
array_index_tests = [
|
||||||
# basic indexing
|
# basic indexing
|
||||||
("[(I, II, III)][I]", None, ValInt(1)), # first element
|
("[(I, II, III)][I]", Program([], [ExpressionStatement(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I")))]), ValInt(1)), # first element
|
||||||
("[(I, II, III)][II]", None, ValInt(2)), # second element
|
("[(I, II, III)][II]", Program([], [ExpressionStatement(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("II")))]), ValInt(2)), # second element
|
||||||
("[(I, II, III)][III]", None, ValInt(3)), # third element
|
("[(I, II, III)][III]", Program([], [ExpressionStatement(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("III")))]), ValInt(3)), # third element
|
||||||
# index into a variable
|
# index into a variable
|
||||||
("DESIGNA a VT [(X, XX, XXX)]\na[II]", None, ValInt(20)), # second element
|
("DESIGNA a VT [(X, XX, XXX)]\na[II]",
|
||||||
|
Program([], [Designa(ID("a"), DataArray([Numeral("X"), Numeral("XX"), Numeral("XXX")])), ExpressionStatement(ArrayIndex(ID("a"), Numeral("II")))]),
|
||||||
|
ValInt(20)), # second element
|
||||||
# index into range array
|
# index into range array
|
||||||
("[I VSQVE V][II]", None, 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]
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestArrayIndex(unittest.TestCase):
|
class TestArrayIndex(unittest.TestCase):
|
||||||
@@ -629,27 +885,33 @@ class TestArrayIndex(unittest.TestCase):
|
|||||||
|
|
||||||
comment_tests = [
|
comment_tests = [
|
||||||
# trailing line comment
|
# trailing line comment
|
||||||
('DICE("hello") // this is ignored', None, ValStr("hello"), "hello\n"),
|
('DICE("hello") // this is ignored', Program([], [ExpressionStatement(BuiltIn("DICE", [String("hello")]))]), ValStr("hello"), "hello\n"),
|
||||||
# line comment on its own line before code
|
# line comment on its own line before code
|
||||||
('// ignored\nDICE("hi")', None, ValStr("hi"), "hi\n"),
|
('// ignored\nDICE("hi")', Program([], [ExpressionStatement(BuiltIn("DICE", [String("hi")]))]), ValStr("hi"), "hi\n"),
|
||||||
# inline block comment
|
# inline block comment
|
||||||
('DICE(/* ignored */ "hi")', None, ValStr("hi"), "hi\n"),
|
('DICE(/* ignored */ "hi")', Program([], [ExpressionStatement(BuiltIn("DICE", [String("hi")]))]), ValStr("hi"), "hi\n"),
|
||||||
# block comment spanning multiple lines
|
# block comment spanning multiple lines
|
||||||
('/* line one\nline two */\nDICE("hi")', None, ValStr("hi"), "hi\n"),
|
('/* line one\nline two */\nDICE("hi")', Program([], [ExpressionStatement(BuiltIn("DICE", [String("hi")]))]), ValStr("hi"), "hi\n"),
|
||||||
# block comment mid-expression
|
# block comment mid-expression
|
||||||
("II /* ignored */ + III", None, ValInt(5)),
|
("II /* ignored */ + III", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS"))]), ValInt(5)),
|
||||||
# line comment after expression (no output)
|
# line comment after expression (no output)
|
||||||
("II + III // ignored", None, ValInt(5)),
|
("II + III // ignored", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS"))]), ValInt(5)),
|
||||||
# division still works (/ token not confused with //)
|
# division still works (/ token not confused with //)
|
||||||
("X / II", None, ValInt(5)),
|
("X / II", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("II"), "SYMBOL_DIVIDE"))]), ValInt(5)),
|
||||||
# multiple line comments
|
# multiple line comments
|
||||||
('// first\n// second\nDICE("ok")', None, ValStr("ok"), "ok\n"),
|
('// first\n// second\nDICE("ok")', Program([], [ExpressionStatement(BuiltIn("DICE", [String("ok")]))]), ValStr("ok"), "ok\n"),
|
||||||
# comment-only line between two statements
|
# comment-only line between two statements
|
||||||
('DESIGNA x VT I\n// set y\nDESIGNA y VT II\nx + y', None, ValInt(3)),
|
('DESIGNA x VT I\n// set y\nDESIGNA y VT II\nx + y',
|
||||||
|
Program([], [Designa(ID("x"), Numeral("I")), Designa(ID("y"), Numeral("II")), ExpressionStatement(BinOp(ID("x"), ID("y"), "SYMBOL_PLUS"))]),
|
||||||
|
ValInt(3)),
|
||||||
# blank line between two statements (double newline)
|
# blank line between two statements (double newline)
|
||||||
('DESIGNA x VT I\n\nDESIGNA y VT II\nx + y', None, ValInt(3)),
|
('DESIGNA x VT I\n\nDESIGNA y VT II\nx + y',
|
||||||
|
Program([], [Designa(ID("x"), Numeral("I")), Designa(ID("y"), Numeral("II")), ExpressionStatement(BinOp(ID("x"), ID("y"), "SYMBOL_PLUS"))]),
|
||||||
|
ValInt(3)),
|
||||||
# multiple comment-only lines between statements
|
# multiple comment-only lines between statements
|
||||||
('DESIGNA x VT I\n// one\n// two\nDESIGNA y VT III\nx + y', None, ValInt(4)),
|
('DESIGNA x VT I\n// one\n// two\nDESIGNA y VT III\nx + y',
|
||||||
|
Program([], [Designa(ID("x"), Numeral("I")), Designa(ID("y"), Numeral("III")), ExpressionStatement(BinOp(ID("x"), ID("y"), "SYMBOL_PLUS"))]),
|
||||||
|
ValInt(4)),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestComments(unittest.TestCase):
|
class TestComments(unittest.TestCase):
|
||||||
@@ -662,39 +924,118 @@ class TestComments(unittest.TestCase):
|
|||||||
|
|
||||||
scope_tests = [
|
scope_tests = [
|
||||||
# SI: variable assigned in true branch persists in outer scope
|
# SI: variable assigned in true branch persists in outer scope
|
||||||
("SI VERITAS TVNC { DESIGNA r VT X }\nr", None, ValInt(10)),
|
("SI VERITAS TVNC { DESIGNA r VT X }\nr",
|
||||||
|
Program([], [SiStatement(Bool(True), [Designa(ID("r"), Numeral("X"))], None), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(10)),
|
||||||
# SI: variable assigned in ALVID branch persists in outer scope
|
# SI: variable assigned in ALVID branch persists in outer scope
|
||||||
("SI FALSITAS TVNC { DESIGNA r VT X } ALVID { DESIGNA r VT V }\nr", None, ValInt(5)),
|
("SI FALSITAS TVNC { DESIGNA r VT X } ALVID { DESIGNA r VT V }\nr",
|
||||||
|
Program([], [SiStatement(Bool(False), [Designa(ID("r"), Numeral("X"))], [Designa(ID("r"), Numeral("V"))]), ExpressionStatement(ID("r"))]),
|
||||||
|
ValInt(5)),
|
||||||
# DVM: variable assigned in body persists after loop exits
|
# DVM: variable assigned in body persists after loop exits
|
||||||
# x goes 1→2→3→4→5; r tracks x each iteration; loop exits when x==5
|
# x goes 1→2→3→4→5; r tracks x each iteration; loop exits when x==5
|
||||||
("DESIGNA x VT I\nDVM x EST V FACE { DESIGNA x VT x + I\nDESIGNA r VT x }\nr", None, ValInt(5)),
|
("DESIGNA x VT I\nDVM x EST V FACE { DESIGNA x VT x + I\nDESIGNA r VT x }\nr",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("x"), Numeral("I")),
|
||||||
|
DumStatement(BinOp(ID("x"), Numeral("V"), "KEYWORD_EST"), [
|
||||||
|
Designa(ID("x"), BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")),
|
||||||
|
Designa(ID("r"), ID("x")),
|
||||||
|
]),
|
||||||
|
ExpressionStatement(ID("r")),
|
||||||
|
]),
|
||||||
|
ValInt(5)),
|
||||||
# PER: loop variable holds last array element after loop (no ERVMPE)
|
# PER: loop variable holds last array element after loop (no ERVMPE)
|
||||||
("PER i IN [(I, II, III)] FACE { DESIGNA nop VT I }\ni", None, ValInt(3)),
|
("PER i IN [(I, II, III)] FACE { DESIGNA nop VT I }\ni",
|
||||||
|
Program([], [
|
||||||
|
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [Designa(ID("nop"), Numeral("I"))]),
|
||||||
|
ExpressionStatement(ID("i")),
|
||||||
|
]),
|
||||||
|
ValInt(3)),
|
||||||
# PER: reassigning loop var in body doesn't prevent remaining iterations from running
|
# PER: reassigning loop var in body doesn't prevent remaining iterations from running
|
||||||
# cnt increments once per iteration (all 3); C=100 doesn't replace next element assignment
|
# cnt increments once per iteration (all 3); C=100 doesn't replace next element assignment
|
||||||
("DESIGNA cnt VT I\nPER i IN [(I, II, III)] FACE { DESIGNA i VT C\nDESIGNA cnt VT cnt + I }\ncnt", None, ValInt(4)),
|
("DESIGNA cnt VT I\nPER i IN [(I, II, III)] FACE { DESIGNA i VT C\nDESIGNA cnt VT cnt + I }\ncnt",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("cnt"), Numeral("I")),
|
||||||
|
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [
|
||||||
|
Designa(ID("i"), Numeral("C")),
|
||||||
|
Designa(ID("cnt"), BinOp(ID("cnt"), Numeral("I"), "SYMBOL_PLUS")),
|
||||||
|
]),
|
||||||
|
ExpressionStatement(ID("cnt")),
|
||||||
|
]),
|
||||||
|
ValInt(4)),
|
||||||
# PER: loop var after loop reflects the last body assignment, not the last array element
|
# PER: loop var after loop reflects the last body assignment, not the last array element
|
||||||
# body sets i=C=100 on every iteration; after loop ends, i stays at 100
|
# body sets i=C=100 on every iteration; after loop ends, i stays at 100
|
||||||
("PER i IN [(I, II, III)] FACE { DESIGNA i VT C }\ni", None, ValInt(100)),
|
("PER i IN [(I, II, III)] FACE { DESIGNA i VT C }\ni",
|
||||||
|
Program([], [
|
||||||
|
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("i"), [Designa(ID("i"), Numeral("C"))]),
|
||||||
|
ExpressionStatement(ID("i")),
|
||||||
|
]),
|
||||||
|
ValInt(100)),
|
||||||
# DONICVM: counter holds last range value after loop ends
|
# DONICVM: counter holds last range value after loop ends
|
||||||
# [I VSQVE IV] = [1,2,3]; last value assigned by loop is III=3
|
# [I VSQVE IV] = [1,2,3]; last value assigned by loop is III=3
|
||||||
("DONICVM i VT I VSQVE IV FACE { DESIGNA nop VT I }\ni", None, ValInt(3)),
|
("DONICVM i VT I VSQVE IV FACE { DESIGNA nop VT I }\ni",
|
||||||
|
Program([], [
|
||||||
|
PerStatement(DataRangeArray(Numeral("I"), Numeral("IV")), ID("i"), [Designa(ID("nop"), Numeral("I"))]),
|
||||||
|
ExpressionStatement(ID("i")),
|
||||||
|
]),
|
||||||
|
ValInt(3)),
|
||||||
# DONICVM: reassigning counter inside body doesn't reduce the number of iterations
|
# DONICVM: reassigning counter inside body doesn't reduce the number of iterations
|
||||||
# range [I VSQVE IV] evaluated once; i reset each time; cnt still increments 3 times → 4
|
# range [I VSQVE IV] evaluated once; i reset each time; cnt still increments 3 times → 4
|
||||||
("DESIGNA cnt VT I\nDONICVM i VT I VSQVE IV FACE { DESIGNA cnt VT cnt + I\nDESIGNA i VT C }\ncnt", None, ValInt(4)),
|
("DESIGNA cnt VT I\nDONICVM i VT I VSQVE IV FACE { DESIGNA cnt VT cnt + I\nDESIGNA i VT C }\ncnt",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("cnt"), Numeral("I")),
|
||||||
|
PerStatement(DataRangeArray(Numeral("I"), Numeral("IV")), ID("i"), [
|
||||||
|
Designa(ID("cnt"), BinOp(ID("cnt"), Numeral("I"), "SYMBOL_PLUS")),
|
||||||
|
Designa(ID("i"), Numeral("C")),
|
||||||
|
]),
|
||||||
|
ExpressionStatement(ID("cnt")),
|
||||||
|
]),
|
||||||
|
ValInt(4)),
|
||||||
# DONICVM: ERVMPE exits loop early; counter persists at break value
|
# DONICVM: ERVMPE exits loop early; counter persists at break value
|
||||||
("DONICVM i VT I VSQVE X FACE {\nSI i EST III TVNC { ERVMPE }\n}\ni", None, ValInt(3)),
|
("DONICVM i VT I VSQVE X FACE {\nSI i EST III TVNC { ERVMPE }\n}\ni",
|
||||||
|
Program([], [
|
||||||
|
PerStatement(DataRangeArray(Numeral("I"), Numeral("X")), ID("i"), [
|
||||||
|
SiStatement(BinOp(ID("i"), Numeral("III"), "KEYWORD_EST"), [Erumpe()], None),
|
||||||
|
]),
|
||||||
|
ExpressionStatement(ID("i")),
|
||||||
|
]),
|
||||||
|
ValInt(3)),
|
||||||
# Function: modifying parameter inside function does not affect outer variable of same name
|
# Function: modifying parameter inside function does not affect outer variable of same name
|
||||||
# outer n=1; f receives n=5 and modifies its local copy; outer n unchanged
|
# outer n=1; f receives n=5 and modifies its local copy; outer n unchanged
|
||||||
("DESIGNA n VT I\nDEFINI f (n) VT { DESIGNA n VT n + X\nREDI (n) }\nINVOCA f (V)\nn", None, ValInt(1)),
|
("DESIGNA n VT I\nDEFINI f (n) VT { DESIGNA n VT n + X\nREDI (n) }\nINVOCA f (V)\nn",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("n"), Numeral("I")),
|
||||||
|
Defini(ID("f"), [ID("n")], [Designa(ID("n"), BinOp(ID("n"), Numeral("X"), "SYMBOL_PLUS")), Redi([ID("n")])]),
|
||||||
|
ExpressionStatement(Invoca(ID("f"), [Numeral("V")])),
|
||||||
|
ExpressionStatement(ID("n")),
|
||||||
|
]),
|
||||||
|
ValInt(1)),
|
||||||
# Function: mutating outer variable inside function (via DESIGNA) is not visible outside
|
# Function: mutating outer variable inside function (via DESIGNA) is not visible outside
|
||||||
# Invoca creates func_vtable = vtable.copy(); mutations to func_vtable don't propagate back
|
# Invoca creates func_vtable = vtable.copy(); mutations to func_vtable don't propagate back
|
||||||
("DESIGNA x VT I\nDEFINI f () VT { DESIGNA x VT C\nREDI (x) }\nINVOCA f ()\nx", None, ValInt(1)),
|
("DESIGNA x VT I\nDEFINI f () VT { DESIGNA x VT C\nREDI (x) }\nINVOCA f ()\nx",
|
||||||
|
Program([], [
|
||||||
|
Designa(ID("x"), Numeral("I")),
|
||||||
|
Defini(ID("f"), [], [Designa(ID("x"), Numeral("C")), Redi([ID("x")])]),
|
||||||
|
ExpressionStatement(Invoca(ID("f"), [])),
|
||||||
|
ExpressionStatement(ID("x")),
|
||||||
|
]),
|
||||||
|
ValInt(1)),
|
||||||
# Function: two successive calls with same parameter name don't share state
|
# Function: two successive calls with same parameter name don't share state
|
||||||
("DEFINI f (n) VT { REDI (n * II) }\nINVOCA f (III) + INVOCA f (IV)", None, ValInt(14)),
|
("DEFINI f (n) VT { REDI (n * II) }\nINVOCA f (III) + INVOCA f (IV)",
|
||||||
|
Program([], [
|
||||||
|
Defini(ID("f"), [ID("n")], [Redi([BinOp(ID("n"), Numeral("II"), "SYMBOL_TIMES")])]),
|
||||||
|
ExpressionStatement(BinOp(Invoca(ID("f"), [Numeral("III")]), Invoca(ID("f"), [Numeral("IV")]), "SYMBOL_PLUS")),
|
||||||
|
]),
|
||||||
|
ValInt(14)),
|
||||||
# Function: calling f(I) with param named n does not overwrite outer n=II
|
# Function: calling f(I) with param named n does not overwrite outer n=II
|
||||||
# f is defined before n is designated; INVOCA creates a local copy, outer vtable unchanged
|
# f is defined before n is designated; INVOCA creates a local copy, outer vtable unchanged
|
||||||
("DEFINI f (n) VT { REDI (n * II) }\nDESIGNA n VT II\nINVOCA f (I)\nn", None, ValInt(2)),
|
("DEFINI f (n) VT { REDI (n * II) }\nDESIGNA n VT II\nINVOCA f (I)\nn",
|
||||||
|
Program([], [
|
||||||
|
Defini(ID("f"), [ID("n")], [Redi([BinOp(ID("n"), Numeral("II"), "SYMBOL_TIMES")])]),
|
||||||
|
Designa(ID("n"), Numeral("II")),
|
||||||
|
ExpressionStatement(Invoca(ID("f"), [Numeral("I")])),
|
||||||
|
ExpressionStatement(ID("n")),
|
||||||
|
]),
|
||||||
|
ValInt(2)),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestScope(unittest.TestCase):
|
class TestScope(unittest.TestCase):
|
||||||
|
|||||||
Reference in New Issue
Block a user