🐐 Modulo

This commit is contained in:
2026-04-16 20:34:06 +02:00
parent e2ce25aa24
commit c570d72b02
10 changed files with 122 additions and 7 deletions

View File

@@ -136,6 +136,9 @@ arithmetic_tests = [
("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
@@ -153,7 +156,7 @@ class TestArithmetic(unittest.TestCase):
# --- Precedence and associativity ---
#
# Precedence (lowest → highest):
# AVT < ET < (EST, PLVS, MINVS) < (+ -) < (* /) < UMINUS < INDEX
# AVT < ET < (EST, DISPAR, PLVS, MINVS) < (+ -) < (* / RELIQVVM) < UMINUS < INDEX
precedence_tests = [
# * binds tighter than -: 10 - (2*3) = 4, not (10-2)*3 = 24
@@ -176,6 +179,14 @@ precedence_tests = [
("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"))]),
@@ -208,6 +219,19 @@ precedence_tests = [
("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"))]),
@@ -719,6 +743,15 @@ comparison_tests = [
# NVLLVS coerces to 0 in comparisons
("V PLVS NVLLVS", Program([], [ExpressionStatement(BinOp(Numeral("V"), Nullus(), "KEYWORD_PLVS"))]), ValBool(True)),
("NVLLVS MINVS V", Program([], [ExpressionStatement(BinOp(Nullus(), Numeral("V"), "KEYWORD_MINVS"))]), ValBool(True)),
# DISPAR (not-equal): mirrors EST semantics, negated
("I DISPAR II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_DISPAR"))]), ValBool(True)),
("I DISPAR I", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("I"), "KEYWORD_DISPAR"))]), ValBool(False)),
('"hello" DISPAR "hello"', Program([], [ExpressionStatement(BinOp(String("hello"), String("hello"), "KEYWORD_DISPAR"))]), ValBool(False)),
('"hello" DISPAR "world"', Program([], [ExpressionStatement(BinOp(String("hello"), String("world"), "KEYWORD_DISPAR"))]), ValBool(True)),
("VERITAS DISPAR FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(False), "KEYWORD_DISPAR"))]), ValBool(True)),
("NVLLVS DISPAR NVLLVS", Program([], [ExpressionStatement(BinOp(Nullus(), Nullus(), "KEYWORD_DISPAR"))]), ValBool(False)),
# cross-type: an int and a string are never equal
('I DISPAR "I"', Program([], [ExpressionStatement(BinOp(Numeral("I"), String("I"), "KEYWORD_DISPAR"))]), ValBool(True)),
]
class TestComparisons(unittest.TestCase):
@@ -1431,6 +1464,34 @@ fractio_tests = [
]),
ValFrac(Fraction(5))
),
# Modulo on fractions: 7/2 RELIQVVM 3/2 = 1/2 (7/2 / 3/2 = 7/3, floor=2, 7/2 - 3 = 1/2)
("CVM FRACTIO\nIIIS RELIQVVM IS",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("IIIS"), Fractio("IS"), "KEYWORD_RELIQVVM"))
]),
ValFrac(Fraction(1, 2))
),
# Modulo with mixed operand types: 5/2 RELIQVVM 1 = 1/2
("CVM FRACTIO\nIIS RELIQVVM I",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Fractio("IIS"), Numeral("I"), "KEYWORD_RELIQVVM"))
]),
ValFrac(Fraction(1, 2))
),
# Int operands under FRACTIO still return a fraction: 10 RELIQVVM 3 = 1 (as Fraction)
("CVM FRACTIO\nX RELIQVVM III",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Numeral("X"), Numeral("III"), "KEYWORD_RELIQVVM"))
]),
ValFrac(Fraction(1))
),
# Exact multiple under FRACTIO: 3 RELIQVVM 3/2 = 0
("CVM FRACTIO\nIII RELIQVVM IS",
Program([ModuleCall("FRACTIO")], [
ExpressionStatement(BinOp(Numeral("III"), Fractio("IS"), "KEYWORD_RELIQVVM"))
]),
ValFrac(Fraction(0))
),
# String concatenation with fraction
("CVM FRACTIO\nDICE(IIIS & \"!\")",
Program([ModuleCall("FRACTIO")], [