451 lines
20 KiB
Python
451 lines
20 KiB
Python
from tests._helpers import (
|
|
unittest, parameterized, Fraction, time,
|
|
run_test, run_compiler_error_test,
|
|
ArrayIndex, ArraySlice, Bool, BinOp, BuiltIn, DataArray, DataDict, DataRangeArray,
|
|
Defini, Continva, Designa, DesignaDestructure, DesignaIndex, DumStatement,
|
|
Erumpe, ExpressionStatement, Fvnctio, ID, InterpolatedString, Invoca,
|
|
ModuleCall, Nullus, Numeral, PerStatement, Program, Redi, SiStatement,
|
|
String, TemptaStatement, UnaryMinus, UnaryNot, Fractio, frac_to_fraction,
|
|
fraction_to_frac, num_to_int, int_to_num, make_string,
|
|
ValInt, ValStr, ValBool, ValList, ValDict, ValNul, ValFunc, ValFrac,
|
|
CentvrionError, _RUNTIME_C, _cent_rng,
|
|
Lexer, Parser, compile_program,
|
|
os, subprocess, tempfile, StringIO, patch,
|
|
)
|
|
|
|
|
|
# --- Output ---
|
|
|
|
output_tests = [
|
|
("DIC(\"hello\")", Program([], [ExpressionStatement(BuiltIn("DIC", [String("hello")]))]), ValStr("hello"), "hello\n"),
|
|
("DIC(\"world\")", Program([], [ExpressionStatement(BuiltIn("DIC", [String("world")]))]), ValStr("world"), "world\n"),
|
|
("DIC(III)", Program([], [ExpressionStatement(BuiltIn("DIC", [Numeral("III")]))]), ValStr("III"), "III\n"),
|
|
("DIC(X)", Program([], [ExpressionStatement(BuiltIn("DIC", [Numeral("X")]))]), ValStr("X"), "X\n"),
|
|
("DIC(MMXXV)", Program([], [ExpressionStatement(BuiltIn("DIC", [Numeral("MMXXV")]))]), ValStr("MMXXV"), "MMXXV\n"),
|
|
("DIC('hello')", Program([], [ExpressionStatement(BuiltIn("DIC", [String("hello")]))]), ValStr("hello"), "hello\n"),
|
|
("DIC('world')", Program([], [ExpressionStatement(BuiltIn("DIC", [String("world")]))]), ValStr("world"), "world\n"),
|
|
("DIC(\"a\", \"b\")", Program([], [ExpressionStatement(BuiltIn("DIC", [String("a"), String("b")]))]), ValStr("a b"), "a b\n"),
|
|
("DIC(\"line one\")\nDIC(\"line two\")", Program([], [ExpressionStatement(BuiltIn("DIC", [String("line one")])), ExpressionStatement(BuiltIn("DIC", [String("line two")]))]), ValStr("line two"), "line one\nline two\n"),
|
|
("DIC(DIC(II))", Program([], [ExpressionStatement(BuiltIn("DIC", [BuiltIn("DIC", [Numeral("II")])]))]), ValStr("II"), "II\nII\n"),
|
|
("EVERRE()", Program([], [ExpressionStatement(BuiltIn("EVERRE", []))]), ValNul(), "\033[2J\033[H"),
|
|
]
|
|
|
|
class TestOutput(unittest.TestCase):
|
|
@parameterized.expand(output_tests)
|
|
def test_output(self, source, nodes, value, output):
|
|
run_test(self, source, nodes, value, output)
|
|
|
|
# --- Arithmetic ---
|
|
|
|
arithmetic_tests = [
|
|
("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
|
|
("X RELIQVVM III", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("III"), "KEYWORD_RELIQVVM"))]), ValInt(1)), # 10 % 3 = 1
|
|
("IX RELIQVVM III", Program([], [ExpressionStatement(BinOp(Numeral("IX"), Numeral("III"), "KEYWORD_RELIQVVM"))]), ValInt(0)), # exact divisor
|
|
("VII RELIQVVM X", Program([], [ExpressionStatement(BinOp(Numeral("VII"), Numeral("X"), "KEYWORD_RELIQVVM"))]), ValInt(7)), # dividend < divisor
|
|
("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
|
|
("CVM SVBNVLLA\n- III", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(UnaryMinus(Numeral("III")))]), ValInt(-3)), # unary negation
|
|
("CVM SVBNVLLA\n- (II + III)", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(UnaryMinus(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS")))]), ValInt(-5)), # unary negation of expression
|
|
("CVM SVBNVLLA\n- - II", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(UnaryMinus(UnaryMinus(Numeral("II"))))]), ValInt(2)), # double negation
|
|
("CVM SVBNVLLA\nIII + - II", Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(Numeral("III"), UnaryMinus(Numeral("II")), "SYMBOL_PLUS"))]), ValInt(1)), # unary in binary context
|
|
]
|
|
|
|
class TestArithmetic(unittest.TestCase):
|
|
@parameterized.expand(arithmetic_tests)
|
|
def test_arithmetic(self, source, nodes, value):
|
|
run_test(self, source, nodes, value)
|
|
|
|
# --- Precedence and associativity ---
|
|
#
|
|
# Precedence (lowest → highest):
|
|
# AVT < ET < (EST, DISPAR, PLVS, MINVS) < (+ -) < (* / RELIQVVM) < 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)),
|
|
# + binds tighter than DISPAR: (2+3)!=5 = False, not 2+(3!=5) = type error
|
|
("II + III DISPAR V",
|
|
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS"), Numeral("V"), "KEYWORD_DISPAR"))]),
|
|
ValBool(False)),
|
|
# DISPAR binds tighter than ET: (1!=2) AND (2!=2) = True AND False = False
|
|
("I DISPAR II ET II DISPAR II",
|
|
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_DISPAR"), BinOp(Numeral("II"), Numeral("II"), "KEYWORD_DISPAR"), "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)
|
|
("CVM SVBNVLLA\n- II * III",
|
|
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(UnaryMinus(Numeral("II")), Numeral("III"), "SYMBOL_TIMES"))]),
|
|
ValInt(-6)),
|
|
# UMINUS binds tighter than +: (-2)+3 = 1, not -(2+3) = -5
|
|
("CVM SVBNVLLA\n- II + III",
|
|
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(UnaryMinus(Numeral("II")), Numeral("III"), "SYMBOL_PLUS"))]),
|
|
ValInt(1)),
|
|
# INDEX binds tighter than UMINUS: -(arr[I]) = -1
|
|
("CVM SVBNVLLA\n- [I, II, III][I]",
|
|
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(UnaryMinus(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I"))))]),
|
|
ValInt(-1)),
|
|
# INDEX binds tighter than NON: NON (arr[I]) = NON VERITAS = False
|
|
("NON [VERITAS, FALSITAS][I]",
|
|
Program([], [ExpressionStatement(UnaryNot(ArrayIndex(DataArray([Bool(True), Bool(False)]), Numeral("I"))))]),
|
|
ValBool(False)),
|
|
# 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)),
|
|
# RELIQVVM same precedence as *, /; left-associative: (17 % 5) % 2 = 0
|
|
("XVII RELIQVVM V RELIQVVM II",
|
|
Program([], [ExpressionStatement(
|
|
BinOp(BinOp(Numeral("XVII"), Numeral("V"), "KEYWORD_RELIQVVM"),
|
|
Numeral("II"), "KEYWORD_RELIQVVM"))]),
|
|
ValInt(0)),
|
|
# RELIQVVM binds tighter than +: 2 + (7 % 3) = 3, not (2+7) % 3 = 0
|
|
("II + VII RELIQVVM III",
|
|
Program([], [ExpressionStatement(
|
|
BinOp(Numeral("II"),
|
|
BinOp(Numeral("VII"), Numeral("III"), "KEYWORD_RELIQVVM"),
|
|
"SYMBOL_PLUS"))]),
|
|
ValInt(3)),
|
|
# 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",
|
|
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)),
|
|
# Compound assignment — AVGE (+=)
|
|
("DESIGNA x VT V\nx AVGE III\nx",
|
|
Program([], [Designa(ID("x"), Numeral("V")),
|
|
Designa(ID("x"), BinOp(ID("x"), Numeral("III"), "SYMBOL_PLUS")),
|
|
ExpressionStatement(ID("x"))]),
|
|
ValInt(8)),
|
|
# Compound assignment — MINVE (-=)
|
|
("DESIGNA x VT X\nx MINVE III\nx",
|
|
Program([], [Designa(ID("x"), Numeral("X")),
|
|
Designa(ID("x"), BinOp(ID("x"), Numeral("III"), "SYMBOL_MINUS")),
|
|
ExpressionStatement(ID("x"))]),
|
|
ValInt(7)),
|
|
# AVGE with complex expression
|
|
("DESIGNA x VT I\nx AVGE II + III\nx",
|
|
Program([], [Designa(ID("x"), Numeral("I")),
|
|
Designa(ID("x"), BinOp(ID("x"), BinOp(Numeral("II"), Numeral("III"), "SYMBOL_PLUS"), "SYMBOL_PLUS")),
|
|
ExpressionStatement(ID("x"))]),
|
|
ValInt(6)),
|
|
# AVGE inside a loop (DONICVM range is inclusive: I VSQVE III = [1, 2, 3])
|
|
("DESIGNA s VT NVLLVS\nDONICVM i VT I VSQVE III FAC {\ns AVGE i\n}\ns",
|
|
Program([], [Designa(ID("s"), Nullus()),
|
|
PerStatement(DataRangeArray(Numeral("I"), Numeral("III")), ID("i"),
|
|
[Designa(ID("s"), BinOp(ID("s"), ID("i"), "SYMBOL_PLUS"))]),
|
|
ExpressionStatement(ID("s"))]),
|
|
ValInt(6)),
|
|
# Compound assignment — MVLTIPLICA (*=)
|
|
("DESIGNA x VT III\nx MVLTIPLICA II\nx",
|
|
Program([], [Designa(ID("x"), Numeral("III")),
|
|
Designa(ID("x"), BinOp(ID("x"), Numeral("II"), "SYMBOL_TIMES")),
|
|
ExpressionStatement(ID("x"))]),
|
|
ValInt(6)),
|
|
# Compound assignment — DIVIDE (/=)
|
|
("DESIGNA x VT XII\nx DIVIDE III\nx",
|
|
Program([], [Designa(ID("x"), Numeral("XII")),
|
|
Designa(ID("x"), BinOp(ID("x"), Numeral("III"), "SYMBOL_DIVIDE")),
|
|
ExpressionStatement(ID("x"))]),
|
|
ValInt(4)),
|
|
# MVLTIPLICA with complex RHS — whole expression is captured before the op
|
|
("DESIGNA x VT II\nx MVLTIPLICA II + I\nx",
|
|
Program([], [Designa(ID("x"), Numeral("II")),
|
|
Designa(ID("x"), BinOp(ID("x"), BinOp(Numeral("II"), Numeral("I"), "SYMBOL_PLUS"), "SYMBOL_TIMES")),
|
|
ExpressionStatement(ID("x"))]),
|
|
ValInt(6)),
|
|
# DIVIDE with complex RHS
|
|
("DESIGNA x VT XX\nx DIVIDE II + II\nx",
|
|
Program([], [Designa(ID("x"), Numeral("XX")),
|
|
Designa(ID("x"), BinOp(ID("x"), BinOp(Numeral("II"), Numeral("II"), "SYMBOL_PLUS"), "SYMBOL_DIVIDE")),
|
|
ExpressionStatement(ID("x"))]),
|
|
ValInt(5)),
|
|
]
|
|
|
|
class TestAssignment(unittest.TestCase):
|
|
@parameterized.expand(assignment_tests)
|
|
def test_assignment(self, source, nodes, value):
|
|
run_test(self, source, nodes, value)
|
|
|
|
# --- Destructuring ---
|
|
|
|
destructuring_tests = [
|
|
# basic: unpack multi-return function
|
|
(
|
|
"DEFINI pair (a, b) VT { REDI (a, b) }\nDESIGNA x, y VT INVOCA pair (III, VII)\nx + y",
|
|
Program([], [
|
|
Defini(ID("pair"), [ID("a"), ID("b")], [Redi([ID("a"), ID("b")])]),
|
|
DesignaDestructure([ID("x"), ID("y")], Invoca(ID("pair"), [Numeral("III"), Numeral("VII")])),
|
|
ExpressionStatement(BinOp(ID("x"), ID("y"), "SYMBOL_PLUS")),
|
|
]),
|
|
ValInt(10),
|
|
),
|
|
# unpack array literal
|
|
(
|
|
"DESIGNA a, b VT [I, II]\na + b",
|
|
Program([], [
|
|
DesignaDestructure([ID("a"), ID("b")], DataArray([Numeral("I"), Numeral("II")])),
|
|
ExpressionStatement(BinOp(ID("a"), ID("b"), "SYMBOL_PLUS")),
|
|
]),
|
|
ValInt(3),
|
|
),
|
|
# three variables
|
|
(
|
|
"DESIGNA a, b, c VT [X, XX, XXX]\na + b + c",
|
|
Program([], [
|
|
DesignaDestructure([ID("a"), ID("b"), ID("c")], DataArray([Numeral("X"), Numeral("XX"), Numeral("XXX")])),
|
|
ExpressionStatement(BinOp(BinOp(ID("a"), ID("b"), "SYMBOL_PLUS"), ID("c"), "SYMBOL_PLUS")),
|
|
]),
|
|
ValInt(60),
|
|
),
|
|
# destructure into individual use
|
|
(
|
|
"DEFINI pair (a, b) VT { REDI (a, b) }\nDESIGNA x, y VT INVOCA pair (V, II)\nDIC(x)\nDIC(y)",
|
|
Program([], [
|
|
Defini(ID("pair"), [ID("a"), ID("b")], [Redi([ID("a"), ID("b")])]),
|
|
DesignaDestructure([ID("x"), ID("y")], Invoca(ID("pair"), [Numeral("V"), Numeral("II")])),
|
|
ExpressionStatement(BuiltIn("DIC", [ID("x")])),
|
|
ExpressionStatement(BuiltIn("DIC", [ID("y")])),
|
|
]),
|
|
ValStr("II"),
|
|
"V\nII\n",
|
|
),
|
|
]
|
|
|
|
class TestDestructuring(unittest.TestCase):
|
|
@parameterized.expand(destructuring_tests)
|
|
def test_destructuring(self, source, nodes, value, output=""):
|
|
run_test(self, source, nodes, value, output)
|
|
|
|
# --- Functions ---
|
|
|
|
function_tests = [
|
|
(
|
|
"DEFINI bis (n) VT { REDI (n * II) }\nINVOCA bis (III)",
|
|
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)",
|
|
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) } ALIVD { REDI (INVOCA fib (n - I) + INVOCA fib (n - II)) }\n}\nINVOCA fib (VII)",
|
|
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),
|
|
),
|
|
]
|
|
|
|
class TestFunctions(unittest.TestCase):
|
|
@parameterized.expand(function_tests)
|
|
def test_functions(self, source, nodes, value):
|
|
run_test(self, source, nodes, value)
|
|
|
|
# --- Function edge cases ---
|
|
|
|
function_edge_tests = [
|
|
# no explicit REDI → returns 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)",
|
|
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",
|
|
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 ()",
|
|
Program([], [
|
|
Designa(ID("x"), Numeral("VII")),
|
|
Defini(ID("f"), [], [Redi([ID("x")])]),
|
|
ExpressionStatement(Invoca(ID("f"), [])),
|
|
]),
|
|
ValInt(7),
|
|
),
|
|
# parameter shadows outer variable inside function
|
|
(
|
|
"DESIGNA n VT I\nDEFINI f (n) VT { REDI (n * II) }\nINVOCA f (X)\nn",
|
|
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)",
|
|
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)",
|
|
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),
|
|
),
|
|
# REDI inside SI exits function, skips remaining statements in block
|
|
(
|
|
"DEFINI f () VT {\nSI VERITAS TVNC {\nREDI (I)\nREDI (II)\n}\n}\nINVOCA f ()",
|
|
Program([],[
|
|
Defini(ID("f"), [], [SiStatement(Bool(True),[Redi([Numeral("I")]),Redi([Numeral("II")])],None)]),
|
|
ExpressionStatement(Invoca(ID("f"),[]))
|
|
]),
|
|
ValInt(1),
|
|
),
|
|
# REDI inside DVM exits loop and function
|
|
(
|
|
"DEFINI f () VT {\nDESIGNA x VT I\nDVM FALSITAS FAC {\nREDI (x)\n}\n}\nINVOCA f ()",
|
|
Program([],[
|
|
Defini(ID("f"), [], [
|
|
Designa(ID("x"), Numeral("I")),
|
|
DumStatement(Bool(False), [Redi([ID("x")])])
|
|
]),
|
|
ExpressionStatement(Invoca(ID("f"),[]))
|
|
]),
|
|
ValInt(1),
|
|
),
|
|
# REDI inside PER exits loop and function
|
|
(
|
|
"DEFINI f () VT {\nPER x IN [I, II, III] FAC {\nSI x EST II TVNC {\nREDI (x)\n}\n}\n}\nINVOCA f ()",
|
|
Program([],[
|
|
Defini(ID("f"), [], [
|
|
PerStatement(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), ID("x"), [
|
|
SiStatement(BinOp(ID("x"), Numeral("II"), "KEYWORD_EST"), [
|
|
Redi([ID("x")])
|
|
], None)
|
|
])
|
|
]),
|
|
ExpressionStatement(Invoca(ID("f"),[]))
|
|
]),
|
|
ValInt(2),
|
|
),
|
|
# REDI inside nested loops exits all loops and function
|
|
(
|
|
"DEFINI f () VT {\nDESIGNA x VT I\nDVM FALSITAS FAC {\nDVM FALSITAS FAC {\nREDI (x)\n}\n}\n}\nINVOCA f ()",
|
|
Program([],[
|
|
Defini(ID("f"), [], [
|
|
Designa(ID("x"), Numeral("I")),
|
|
DumStatement(Bool(False), [
|
|
DumStatement(Bool(False), [
|
|
Redi([ID("x")])
|
|
])
|
|
])
|
|
]),
|
|
ExpressionStatement(Invoca(ID("f"),[]))
|
|
]),
|
|
ValInt(1),
|
|
),
|
|
]
|
|
|
|
class TestFunctionEdge(unittest.TestCase):
|
|
@parameterized.expand(function_edge_tests)
|
|
def test_function_edge(self, source, nodes, value):
|
|
run_test(self, source, nodes, value)
|