🐐 __eq__ and precendence rules
This commit is contained in:
@@ -130,6 +130,9 @@ class ExpressionStatement(Node):
|
||||
def __init__(self, expression) -> 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__()
|
||||
|
||||
@@ -141,6 +144,9 @@ class DataArray(Node):
|
||||
def __init__(self, content) -> None:
|
||||
self.content = content
|
||||
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other) and self.content == other.content
|
||||
|
||||
def __repr__(self) -> str:
|
||||
content_string = rep_join(self.content)
|
||||
return f"Array([{content_string}])"
|
||||
@@ -158,6 +164,9 @@ class DataRangeArray(Node):
|
||||
self.from_value = from_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:
|
||||
content_string = rep_join([self.from_value, self.to_value])
|
||||
return f"RangeArray([{content_string}])"
|
||||
@@ -172,6 +181,9 @@ class String(Node):
|
||||
def __init__(self, value) -> None:
|
||||
self.value = value
|
||||
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other) and self.value == other.value
|
||||
|
||||
def __repr__(self):
|
||||
return f"String({self.value})"
|
||||
|
||||
@@ -183,6 +195,9 @@ class Numeral(Node):
|
||||
def __init__(self, value) -> None:
|
||||
self.value = value
|
||||
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other) and self.value == other.value
|
||||
|
||||
def __repr__(self):
|
||||
return f"Numeral({self.value})"
|
||||
|
||||
@@ -194,6 +209,9 @@ class Bool(Node):
|
||||
def __init__(self, value) -> None:
|
||||
self.value = value
|
||||
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other) and self.value == other.value
|
||||
|
||||
def __repr__(self):
|
||||
return f"Bool({self.value})"
|
||||
|
||||
@@ -205,6 +223,9 @@ class ModuleCall(BaseBox):
|
||||
def __init__(self, module_name) -> None:
|
||||
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:
|
||||
return f"{self.module_name}"
|
||||
|
||||
@@ -213,6 +234,9 @@ class ID(Node):
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other) and self.name == other.name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"ID({self.name})"
|
||||
|
||||
@@ -225,6 +249,9 @@ class Designa(Node):
|
||||
self.id = variable
|
||||
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:
|
||||
id_string = repr(self.id).replace('\n', '\n ')
|
||||
value_string = repr(self.value).replace('\n', '\n ')
|
||||
@@ -242,6 +269,9 @@ class Defini(Node):
|
||||
self.parameters = parameters
|
||||
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:
|
||||
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
||||
statements_string = f"statements([{rep_join(self.statements)}])"
|
||||
@@ -259,6 +289,9 @@ class Redi(Node):
|
||||
def __init__(self, values) -> None:
|
||||
self.values = values
|
||||
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other) and self.values == other.values
|
||||
|
||||
def __repr__(self) -> str:
|
||||
values_string = f"[{rep_join(self.values)}]"
|
||||
return f"Redi({values_string})"
|
||||
@@ -276,6 +309,9 @@ class Redi(Node):
|
||||
|
||||
|
||||
class Erumpe(Node):
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "Erumpe()"
|
||||
|
||||
@@ -285,6 +321,9 @@ class Erumpe(Node):
|
||||
|
||||
|
||||
class Nullus(Node):
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "Nullus()"
|
||||
|
||||
@@ -298,6 +337,9 @@ class BinOp(Node):
|
||||
self.right = right
|
||||
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:
|
||||
binop_string = rep_join([self.left, self.right, self.op])
|
||||
return f"BinOp({binop_string})"
|
||||
@@ -334,6 +376,9 @@ class UnaryMinus(Node):
|
||||
def __init__(self, expr):
|
||||
self.expr = expr
|
||||
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other) and self.expr == other.expr
|
||||
|
||||
def __repr__(self):
|
||||
return f"UnaryMinus({self.expr!r})"
|
||||
|
||||
@@ -347,6 +392,9 @@ class ArrayIndex(Node):
|
||||
self.array = array
|
||||
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:
|
||||
return f"ArrayIndex({self.array!r}, {self.index!r})"
|
||||
|
||||
@@ -366,6 +414,9 @@ class SiStatement(Node):
|
||||
self.statements = statements
|
||||
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:
|
||||
test = repr(self.test)
|
||||
statements = f"statements([{rep_join(self.statements)}])"
|
||||
@@ -390,6 +441,9 @@ class DumStatement(Node):
|
||||
self.test = test
|
||||
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:
|
||||
test = repr(self.test)
|
||||
statements = f"statements([{rep_join(self.statements)}])"
|
||||
@@ -418,6 +472,9 @@ class PerStatement(Node):
|
||||
self.variable_name = variable_name
|
||||
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:
|
||||
test = repr(self.data_list)
|
||||
variable_name = repr(self.variable_name)
|
||||
@@ -447,6 +504,9 @@ class Invoca(Node):
|
||||
self.name = name
|
||||
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:
|
||||
parameters_string = f"parameters([{rep_join(self.parameters)}])"
|
||||
invoca_string = rep_join([self.name, parameters_string])
|
||||
@@ -475,6 +535,9 @@ class BuiltIn(Node):
|
||||
self.builtin = builtin
|
||||
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:
|
||||
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
||||
builtin_string = rep_join([self.builtin, parameter_string])
|
||||
@@ -521,6 +584,9 @@ class Program(BaseBox):
|
||||
self.modules = module_calls
|
||||
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:
|
||||
modules_string = f"modules([{rep_join(self.modules)}])"
|
||||
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)
|
||||
|
||||
##########################
|
||||
####### Parser Test ###### (commented out — no __eq__ on AST nodes yet)
|
||||
####### Parser Test ######
|
||||
##########################
|
||||
# self.assertEqual(
|
||||
# program,
|
||||
# target_nodes,
|
||||
# f"Parser test:\n{program}\n{target_nodes}"
|
||||
# )
|
||||
if target_nodes is not None:
|
||||
self.assertEqual(
|
||||
program,
|
||||
target_nodes,
|
||||
f"Parser test:\n{program}\n{target_nodes}"
|
||||
)
|
||||
|
||||
##########################
|
||||
#### Interpreter Test ####
|
||||
@@ -77,16 +78,16 @@ def run_test(self, source, target_nodes, target_value, target_output="", input_l
|
||||
# --- Output ---
|
||||
|
||||
output_tests = [
|
||||
("DICE(\"hello\")", None, ValStr("hello"), "hello\n"),
|
||||
("DICE(\"world\")", None, ValStr("world"), "world\n"),
|
||||
("DICE(III)", None, ValStr("III"), "III\n"),
|
||||
("DICE(X)", None, ValStr("X"), "X\n"),
|
||||
("DICE(MMXXV)", None, ValStr("MMXXV"), "MMXXV\n"),
|
||||
("DICE('hello')", None, ValStr("hello"), "hello\n"),
|
||||
("DICE('world')", None, ValStr("world"), "world\n"),
|
||||
("DICE(\"a\", \"b\")", None, ValStr("a b"), "a b\n"),
|
||||
("DICE(\"line one\")\nDICE(\"line two\")", None, ValStr("line two"), "line one\nline two\n"),
|
||||
("DICE(DICE(II))", None, ValStr("II"), "II\nII\n"),
|
||||
("DICE(\"hello\")", Program([], [ExpressionStatement(BuiltIn("DICE", [String("hello")]))]), ValStr("hello"), "hello\n"),
|
||||
("DICE(\"world\")", Program([], [ExpressionStatement(BuiltIn("DICE", [String("world")]))]), ValStr("world"), "world\n"),
|
||||
("DICE(III)", Program([], [ExpressionStatement(BuiltIn("DICE", [Numeral("III")]))]), ValStr("III"), "III\n"),
|
||||
("DICE(X)", Program([], [ExpressionStatement(BuiltIn("DICE", [Numeral("X")]))]), ValStr("X"), "X\n"),
|
||||
("DICE(MMXXV)", Program([], [ExpressionStatement(BuiltIn("DICE", [Numeral("MMXXV")]))]), ValStr("MMXXV"), "MMXXV\n"),
|
||||
("DICE('hello')", Program([], [ExpressionStatement(BuiltIn("DICE", [String("hello")]))]), ValStr("hello"), "hello\n"),
|
||||
("DICE('world')", Program([], [ExpressionStatement(BuiltIn("DICE", [String("world")]))]), ValStr("world"), "world\n"),
|
||||
("DICE(\"a\", \"b\")", Program([], [ExpressionStatement(BuiltIn("DICE", [String("a"), String("b")]))]), ValStr("a b"), "a b\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))", Program([], [ExpressionStatement(BuiltIn("DICE", [BuiltIn("DICE", [Numeral("II")])]))]), ValStr("II"), "II\nII\n"),
|
||||
]
|
||||
|
||||
class TestOutput(unittest.TestCase):
|
||||
@@ -98,17 +99,17 @@ class TestOutput(unittest.TestCase):
|
||||
# --- Arithmetic ---
|
||||
|
||||
arithmetic_tests = [
|
||||
("I + I", None, ValInt(2)),
|
||||
("X - III", None, ValInt(7)),
|
||||
("III * IV", None, ValInt(12)),
|
||||
("X / II", None, ValInt(5)),
|
||||
("X / III", None, ValInt(3)), # integer division: 10 // 3 = 3
|
||||
("II + III * IV", None, ValInt(14)), # precedence: 2 + (3*4) = 14
|
||||
("(II + III) * IV", None, ValInt(20)), # parens: (2+3)*4 = 20
|
||||
("- III", None, ValInt(-3)), # unary negation
|
||||
("- (II + III)", None, ValInt(-5)), # unary negation of expression
|
||||
("- - II", None, ValInt(2)), # double negation
|
||||
("III + - II", None, ValInt(1)), # unary in binary context
|
||||
("I + I", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("I"), "SYMBOL_PLUS"))]), ValInt(2)),
|
||||
("X - III", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("III"), "SYMBOL_MINUS"))]), ValInt(7)),
|
||||
("III * IV", Program([], [ExpressionStatement(BinOp(Numeral("III"), Numeral("IV"), "SYMBOL_TIMES"))]), ValInt(12)),
|
||||
("X / II", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("II"), "SYMBOL_DIVIDE"))]), ValInt(5)),
|
||||
("X / III", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("III"), "SYMBOL_DIVIDE"))]), ValInt(3)), # integer division: 10 // 3 = 3
|
||||
("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", Program([], [ExpressionStatement(BinOp(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS"), Numeral("IV"), "SYMBOL_TIMES"))]), ValInt(20)), # parens: (2+3)*4 = 20
|
||||
("- III", Program([], [ExpressionStatement(UnaryMinus(Numeral("III")))]), ValInt(-3)), # unary negation
|
||||
("- (II + III)", Program([], [ExpressionStatement(UnaryMinus(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS")))]), ValInt(-5)), # unary negation of expression
|
||||
("- - II", Program([], [ExpressionStatement(UnaryMinus(UnaryMinus(Numeral("II"))))]), ValInt(2)), # double negation
|
||||
("III + - II", Program([], [ExpressionStatement(BinOp(Numeral("III"), UnaryMinus(Numeral("II")), "SYMBOL_PLUS"))]), ValInt(1)), # unary in binary context
|
||||
]
|
||||
|
||||
class TestArithmetic(unittest.TestCase):
|
||||
@@ -117,14 +118,93 @@ class TestArithmetic(unittest.TestCase):
|
||||
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_tests = [
|
||||
("DESIGNA x VT III\nx", None, ValInt(3)),
|
||||
("DESIGNA msg VT \"hello\"\nmsg", None, ValStr("hello")),
|
||||
("DESIGNA msg VT 'hello'\nmsg", None, ValStr("hello")),
|
||||
("DESIGNA a VT V\nDESIGNA b VT X\na + b", None, ValInt(15)),
|
||||
("DESIGNA x VT II\nDESIGNA x VT x + I\nx", None, ValInt(3)),
|
||||
("DESIGNA x VT III\nx",
|
||||
Program([], [Designa(ID("x"), Numeral("III")), ExpressionStatement(ID("x"))]),
|
||||
ValInt(3)),
|
||||
("DESIGNA msg VT \"hello\"\nmsg",
|
||||
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):
|
||||
@@ -137,37 +217,79 @@ class TestAssignment(unittest.TestCase):
|
||||
|
||||
control_tests = [
|
||||
# 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 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 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 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 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 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 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 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
|
||||
(
|
||||
"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
|
||||
(
|
||||
"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)
|
||||
("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 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 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):
|
||||
@@ -181,16 +303,38 @@ class TestControl(unittest.TestCase):
|
||||
function_tests = [
|
||||
(
|
||||
"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)",
|
||||
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)
|
||||
(
|
||||
"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 ---
|
||||
|
||||
builtin_tests = [
|
||||
("AVDI_NVMERVS()", None, ValInt(3), "", ["III"]),
|
||||
("AVDI_NVMERVS()", None, ValInt(10), "", ["X"]),
|
||||
("CVM FORS\nFORTIS_NVMERVS(I, X)", None, ValInt(3)),
|
||||
("AVDI()", None, ValStr("hello"), "", ["hello"]),
|
||||
("LONGITVDO([(I, II, III)])", None, ValInt(3)),
|
||||
("CVM FORS\nFORTIS_ELECTIONIS([(I, II, III)])", None, ValInt(1)),
|
||||
("AVDI_NVMERVS()", Program([], [ExpressionStatement(BuiltIn("AVDI_NVMERVS", []))]), ValInt(3), "", ["III"]),
|
||||
("AVDI_NVMERVS()", Program([], [ExpressionStatement(BuiltIn("AVDI_NVMERVS", []))]), ValInt(10), "", ["X"]),
|
||||
("CVM FORS\nFORTIS_NVMERVS(I, X)", Program([ModuleCall("FORS")], [ExpressionStatement(BuiltIn("FORTIS_NVMERVS", [Numeral("I"), Numeral("X")]))]), ValInt(3)),
|
||||
("AVDI()", Program([], [ExpressionStatement(BuiltIn("AVDI", []))]), ValStr("hello"), "", ["hello"]),
|
||||
("LONGITVDO([(I, II, III)])", Program([], [ExpressionStatement(BuiltIn("LONGITVDO", [DataArray([Numeral("I"), Numeral("II"), Numeral("III")])]))]), ValInt(3)),
|
||||
("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):
|
||||
@@ -364,15 +508,15 @@ class TestMakeString(unittest.TestCase):
|
||||
# --- DICE with non-integer types ---
|
||||
|
||||
dice_type_tests = [
|
||||
("DICE(VERITAS)", None, ValStr("VERVS"), "VERVS\n"),
|
||||
("DICE(FALSITAS)", None, ValStr("FALSVS"), "FALSVS\n"),
|
||||
("DICE(NVLLVS)", None, ValStr("NVLLVS"), "NVLLVS\n"),
|
||||
('DICE([(I, II)])', None, ValStr("[I II]"), "[I II]\n"),
|
||||
('DICE("")', None, ValStr(""), "\n"),
|
||||
("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(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)", 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
|
||||
('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):
|
||||
@@ -385,17 +529,34 @@ class TestDiceTypes(unittest.TestCase):
|
||||
|
||||
truthiness_tests = [
|
||||
# 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
|
||||
("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
|
||||
("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
|
||||
("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
|
||||
(
|
||||
"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_tests = [
|
||||
("I - I", None, ValInt(0)), # result zero
|
||||
("I - V", None, ValInt(-4)), # negative result
|
||||
("I / V", None, ValInt(0)), # integer division → 0
|
||||
("M * M", None, ValInt(1000000)), # large intermediate (not displayed)
|
||||
("(I + II) * (IV - I)", None, ValInt(9)), # nested parens
|
||||
("I - I", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("I"), "SYMBOL_MINUS"))]), ValInt(0)), # result zero
|
||||
("I - V", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("V"), "SYMBOL_MINUS"))]), ValInt(-4)), # negative result
|
||||
("I / V", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("V"), "SYMBOL_DIVIDE"))]), ValInt(0)), # integer division → 0
|
||||
("M * M", Program([], [ExpressionStatement(BinOp(Numeral("M"), Numeral("M"), "SYMBOL_TIMES"))]), ValInt(1000000)), # large intermediate (not displayed)
|
||||
("(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):
|
||||
@@ -425,18 +586,22 @@ class TestArithmeticEdge(unittest.TestCase):
|
||||
|
||||
comparison_tests = [
|
||||
# EST on strings
|
||||
('\"hello\" EST \"hello\"', None, ValBool(True)),
|
||||
('\"hello\" EST \"world\"', None, ValBool(False)),
|
||||
('\"hello\" EST \"hello\"', Program([], [ExpressionStatement(BinOp(String("hello"), String("hello"), "KEYWORD_EST"))]), ValBool(True)),
|
||||
('\"hello\" EST \"world\"', Program([], [ExpressionStatement(BinOp(String("hello"), String("world"), "KEYWORD_EST"))]), ValBool(False)),
|
||||
# chain comparisons as conditions
|
||||
("SI III PLVS II TVNC { DESIGNA r VT I }\nr", None, ValInt(1)),
|
||||
("SI II PLVS III TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
||||
("SI III PLVS II TVNC { DESIGNA r VT I }\nr",
|
||||
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
|
||||
("I EST I", None, ValBool(True)),
|
||||
("I EST II", None, ValBool(False)),
|
||||
("I MINVS II", None, ValBool(True)),
|
||||
("II MINVS I", None, ValBool(False)),
|
||||
("II PLVS I", None, ValBool(True)),
|
||||
("I PLVS II", None, ValBool(False)),
|
||||
("I EST I", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("I"), "KEYWORD_EST"))]), ValBool(True)),
|
||||
("I EST II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_EST"))]), ValBool(False)),
|
||||
("I MINVS II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_MINVS"))]), ValBool(True)),
|
||||
("II MINVS I", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("I"), "KEYWORD_MINVS"))]), ValBool(False)),
|
||||
("II PLVS I", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("I"), "KEYWORD_PLVS"))]), ValBool(True)),
|
||||
("I PLVS II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_PLVS"))]), ValBool(False)),
|
||||
]
|
||||
|
||||
class TestComparisons(unittest.TestCase):
|
||||
@@ -449,38 +614,72 @@ class TestComparisons(unittest.TestCase):
|
||||
|
||||
function_edge_tests = [
|
||||
# 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
|
||||
(
|
||||
"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
|
||||
(
|
||||
"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)
|
||||
(
|
||||
"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)
|
||||
# (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",
|
||||
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
|
||||
(
|
||||
"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
|
||||
(
|
||||
"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 = [
|
||||
# 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
|
||||
("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 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
|
||||
("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
|
||||
# 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
|
||||
("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]
|
||||
("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):
|
||||
@@ -567,11 +807,17 @@ class TestValues(unittest.TestCase):
|
||||
|
||||
magnvm_tests = [
|
||||
# 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)
|
||||
("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
|
||||
("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):
|
||||
@@ -583,20 +829,28 @@ class TestMAGNVM(unittest.TestCase):
|
||||
# --- ET and AVT (boolean and/or) ---
|
||||
|
||||
et_avt_tests = [
|
||||
("VERITAS ET VERITAS", None, ValBool(True)),
|
||||
("VERITAS ET FALSITAS", None, ValBool(False)),
|
||||
("FALSITAS ET VERITAS", None, ValBool(False)),
|
||||
("FALSITAS ET FALSITAS", None, ValBool(False)),
|
||||
("VERITAS AVT VERITAS", None, ValBool(True)),
|
||||
("VERITAS AVT FALSITAS", None, ValBool(True)),
|
||||
("FALSITAS AVT VERITAS", None, ValBool(True)),
|
||||
("FALSITAS AVT FALSITAS", None, ValBool(False)),
|
||||
("VERITAS ET VERITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(True), "KEYWORD_ET"))]), ValBool(True)),
|
||||
("VERITAS ET FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(False), "KEYWORD_ET"))]), ValBool(False)),
|
||||
("FALSITAS ET VERITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(True), "KEYWORD_ET"))]), ValBool(False)),
|
||||
("FALSITAS ET FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(False), "KEYWORD_ET"))]), ValBool(False)),
|
||||
("VERITAS AVT VERITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(True), "KEYWORD_AVT"))]), ValBool(True)),
|
||||
("VERITAS AVT FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(False), "KEYWORD_AVT"))]), ValBool(True)),
|
||||
("FALSITAS AVT VERITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(True), "KEYWORD_AVT"))]), ValBool(True)),
|
||||
("FALSITAS AVT FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(False), "KEYWORD_AVT"))]), ValBool(False)),
|
||||
# short-circuit behaviour: combined with comparisons
|
||||
("(I EST I) ET (II EST II)", None, ValBool(True)),
|
||||
("(I EST II) AVT (II EST II)", None, ValBool(True)),
|
||||
("(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)),
|
||||
("(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
|
||||
("SI VERITAS ET VERITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
||||
("SI FALSITAS AVT FALSITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
||||
("SI VERITAS ET VERITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr",
|
||||
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):
|
||||
@@ -610,13 +864,15 @@ class TestEtAvt(unittest.TestCase):
|
||||
|
||||
array_index_tests = [
|
||||
# basic indexing
|
||||
("[(I, II, III)][I]", None, ValInt(1)), # first element
|
||||
("[(I, II, III)][II]", None, ValInt(2)), # second element
|
||||
("[(I, II, III)][III]", None, ValInt(3)), # third 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]", Program([], [ExpressionStatement(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("II")))]), ValInt(2)), # second 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
|
||||
("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
|
||||
("[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):
|
||||
@@ -629,27 +885,33 @@ class TestArrayIndex(unittest.TestCase):
|
||||
|
||||
comment_tests = [
|
||||
# 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
|
||||
('// ignored\nDICE("hi")', None, ValStr("hi"), "hi\n"),
|
||||
('// ignored\nDICE("hi")', Program([], [ExpressionStatement(BuiltIn("DICE", [String("hi")]))]), ValStr("hi"), "hi\n"),
|
||||
# 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
|
||||
('/* 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
|
||||
("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)
|
||||
("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 //)
|
||||
("X / II", None, ValInt(5)),
|
||||
("X / II", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("II"), "SYMBOL_DIVIDE"))]), ValInt(5)),
|
||||
# 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
|
||||
('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)
|
||||
('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
|
||||
('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):
|
||||
@@ -662,39 +924,118 @@ class TestComments(unittest.TestCase):
|
||||
|
||||
scope_tests = [
|
||||
# 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 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
|
||||
# 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 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
|
||||
# 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
|
||||
# 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
|
||||
# [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
|
||||
# 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 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
|
||||
# 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
|
||||
# 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
|
||||
("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
|
||||
# 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):
|
||||
|
||||
Reference in New Issue
Block a user