🐐 SVBNVLLA implementation
This commit is contained in:
@@ -54,7 +54,11 @@ def single_num_to_int(i, m):
|
|||||||
else:
|
else:
|
||||||
return NUMERALS[i]
|
return NUMERALS[i]
|
||||||
|
|
||||||
def num_to_int(n, m):
|
def num_to_int(n, m, s=False):
|
||||||
|
if n.startswith("-"):
|
||||||
|
if not s:
|
||||||
|
raise ValueError("Cannot use negative numbers without 'SVBNVLLA' module")
|
||||||
|
return -num_to_int(n[1:], m, s)
|
||||||
chars = re.findall(r"[IVXLCDM]_*", n)
|
chars = re.findall(r"[IVXLCDM]_*", n)
|
||||||
if ''.join(chars) != n:
|
if ''.join(chars) != n:
|
||||||
raise ValueError("Invalid numeral", n)
|
raise ValueError("Invalid numeral", n)
|
||||||
@@ -85,19 +89,23 @@ def num_to_int(n, m):
|
|||||||
|
|
||||||
return sum(nums)
|
return sum(nums)
|
||||||
|
|
||||||
def int_to_num(n, m):
|
def int_to_num(n, m, s=False):
|
||||||
|
if n < 0:
|
||||||
|
if not s:
|
||||||
|
raise ValueError("Cannot display negative numbers without 'SVBNVLLA' module")
|
||||||
|
return "-" + int_to_num(-n, m, s)
|
||||||
if n > 3999:
|
if n > 3999:
|
||||||
if not m:
|
if not m:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Cannot display numbers above 3999 without 'MAGNVM' module"
|
"Cannot display numbers above 3999 without 'MAGNVM' module"
|
||||||
)
|
)
|
||||||
thousands_chars = re.findall(r"[IVXLCDM]_*", int_to_num(n//1000, m))
|
thousands_chars = re.findall(r"[IVXLCDM]_*", int_to_num(n//1000, m, s))
|
||||||
thousands = ''.join([
|
thousands = ''.join([
|
||||||
"M" if i == "I" else i+"_"
|
"M" if i == "I" else i+"_"
|
||||||
for i in thousands_chars
|
for i in thousands_chars
|
||||||
])
|
])
|
||||||
|
|
||||||
return thousands + int_to_num(n % 1000, m)
|
return thousands + int_to_num(n % 1000, m, s)
|
||||||
else:
|
else:
|
||||||
nums = []
|
nums = []
|
||||||
while n > 0:
|
while n > 0:
|
||||||
@@ -109,17 +117,17 @@ def int_to_num(n, m):
|
|||||||
|
|
||||||
return ''.join(nums)
|
return ''.join(nums)
|
||||||
|
|
||||||
def make_string(val, magnvm=False):
|
def make_string(val, magnvm=False, svbnvlla=False):
|
||||||
if isinstance(val, ValStr):
|
if isinstance(val, ValStr):
|
||||||
return val.value()
|
return val.value()
|
||||||
elif isinstance(val, ValInt):
|
elif isinstance(val, ValInt):
|
||||||
return int_to_num(val.value(), magnvm)
|
return int_to_num(val.value(), magnvm, svbnvlla)
|
||||||
elif isinstance(val, ValBool):
|
elif isinstance(val, ValBool):
|
||||||
return "VERVS" if val.value() else "FALSVS"
|
return "VERVS" if val.value() else "FALSVS"
|
||||||
elif isinstance(val, ValNul):
|
elif isinstance(val, ValNul):
|
||||||
return "NVLLVS"
|
return "NVLLVS"
|
||||||
elif isinstance(val, ValList):
|
elif isinstance(val, ValList):
|
||||||
inner = ' '.join(make_string(i, magnvm) for i in val.value())
|
inner = ' '.join(make_string(i, magnvm, svbnvlla) for i in val.value())
|
||||||
return f"[{inner}]"
|
return f"[{inner}]"
|
||||||
else:
|
else:
|
||||||
raise TypeError(f"Cannot display {val!r}")
|
raise TypeError(f"Cannot display {val!r}")
|
||||||
@@ -225,7 +233,7 @@ class Numeral(Node):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
def _eval(self, vtable):
|
def _eval(self, vtable):
|
||||||
return vtable, ValInt(num_to_int(self.value, "MAGNVM" in vtable["#modules"]))
|
return vtable, ValInt(num_to_int(self.value, "MAGNVM" in vtable["#modules"], "SVBNVLLA" in vtable["#modules"]))
|
||||||
|
|
||||||
|
|
||||||
class Bool(Node):
|
class Bool(Node):
|
||||||
@@ -439,6 +447,8 @@ class UnaryMinus(Node):
|
|||||||
return f"(- {self.expr.print()})"
|
return f"(- {self.expr.print()})"
|
||||||
|
|
||||||
def _eval(self, vtable):
|
def _eval(self, vtable):
|
||||||
|
if "SVBNVLLA" not in vtable["#modules"]:
|
||||||
|
raise ValueError("Cannot use unary minus without 'SVBNVLLA' module")
|
||||||
vtable, val = self.expr.eval(vtable)
|
vtable, val = self.expr.eval(vtable)
|
||||||
return vtable, ValInt(-val.value())
|
return vtable, ValInt(-val.value())
|
||||||
|
|
||||||
@@ -629,15 +639,16 @@ class BuiltIn(Node):
|
|||||||
def _eval(self, vtable):
|
def _eval(self, vtable):
|
||||||
params = [p.eval(vtable)[1] for p in self.parameters]
|
params = [p.eval(vtable)[1] for p in self.parameters]
|
||||||
magnvm = "MAGNVM" in vtable["#modules"]
|
magnvm = "MAGNVM" in vtable["#modules"]
|
||||||
|
svbnvlla = "SVBNVLLA" in vtable["#modules"]
|
||||||
|
|
||||||
match self.builtin:
|
match self.builtin:
|
||||||
case "AVDI_NVMERVS":
|
case "AVDI_NVMERVS":
|
||||||
return vtable, ValInt(num_to_int(input(), magnvm))
|
return vtable, ValInt(num_to_int(input(), magnvm, svbnvlla))
|
||||||
case "AVDI":
|
case "AVDI":
|
||||||
return vtable, ValStr(input())
|
return vtable, ValStr(input())
|
||||||
case "DICE":
|
case "DICE":
|
||||||
print_string = ' '.join(
|
print_string = ' '.join(
|
||||||
make_string(i, magnvm) for i in params
|
make_string(i, magnvm, svbnvlla) for i in params
|
||||||
)
|
)
|
||||||
print(print_string)
|
print(print_string)
|
||||||
return vtable, ValStr(print_string)
|
return vtable, ValStr(print_string)
|
||||||
|
|||||||
31
tests.py
31
tests.py
@@ -106,10 +106,10 @@ arithmetic_tests = [
|
|||||||
("X / III", Program([], [ExpressionStatement(BinOp(Numeral("X"), Numeral("III"), "SYMBOL_DIVIDE"))]), 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", 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(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
|
("(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
|
("CVM SVBNVLLA\n- III", Program([ModuleCall("SVBNVLLA")], [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
|
("CVM SVBNVLLA\n- (II + III)", Program([ModuleCall("SVBNVLLA")], [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
|
("CVM SVBNVLLA\n- - II", Program([ModuleCall("SVBNVLLA")], [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
|
("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):
|
class TestArithmetic(unittest.TestCase):
|
||||||
@@ -149,16 +149,16 @@ precedence_tests = [
|
|||||||
Program([], [ExpressionStatement(BinOp(Bool(True), BinOp(Bool(False), Bool(False), "KEYWORD_ET"), "KEYWORD_AVT"))]),
|
Program([], [ExpressionStatement(BinOp(Bool(True), BinOp(Bool(False), Bool(False), "KEYWORD_ET"), "KEYWORD_AVT"))]),
|
||||||
ValBool(True)),
|
ValBool(True)),
|
||||||
# UMINUS binds tighter than *: (-2)*3 = -6, not -(2*3) = -6 (same value, different tree)
|
# UMINUS binds tighter than *: (-2)*3 = -6, not -(2*3) = -6 (same value, different tree)
|
||||||
("- II * III",
|
("CVM SVBNVLLA\n- II * III",
|
||||||
Program([], [ExpressionStatement(BinOp(UnaryMinus(Numeral("II")), Numeral("III"), "SYMBOL_TIMES"))]),
|
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(UnaryMinus(Numeral("II")), Numeral("III"), "SYMBOL_TIMES"))]),
|
||||||
ValInt(-6)),
|
ValInt(-6)),
|
||||||
# UMINUS binds tighter than +: (-2)+3 = 1, not -(2+3) = -5
|
# UMINUS binds tighter than +: (-2)+3 = 1, not -(2+3) = -5
|
||||||
("- II + III",
|
("CVM SVBNVLLA\n- II + III",
|
||||||
Program([], [ExpressionStatement(BinOp(UnaryMinus(Numeral("II")), Numeral("III"), "SYMBOL_PLUS"))]),
|
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BinOp(UnaryMinus(Numeral("II")), Numeral("III"), "SYMBOL_PLUS"))]),
|
||||||
ValInt(1)),
|
ValInt(1)),
|
||||||
# INDEX binds tighter than UMINUS: -(arr[I]) = -1
|
# INDEX binds tighter than UMINUS: -(arr[I]) = -1
|
||||||
("- [I, II, III][I]",
|
("CVM SVBNVLLA\n- [I, II, III][I]",
|
||||||
Program([], [ExpressionStatement(UnaryMinus(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I"))))]),
|
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(UnaryMinus(ArrayIndex(DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), Numeral("I"))))]),
|
||||||
ValInt(-1)),
|
ValInt(-1)),
|
||||||
# INDEX binds tighter than +: (arr[II]) + X = 2 + 10 = 12
|
# INDEX binds tighter than +: (arr[II]) + X = 2 + 10 = 12
|
||||||
("[I, II, III][II] + X",
|
("[I, II, III][II] + X",
|
||||||
@@ -376,7 +376,8 @@ error_tests = [
|
|||||||
("DEFINI f () VT { REDI(I) }\nINVOCA f (I)", TypeError), # args to zero-param function
|
("DEFINI f () VT { REDI(I) }\nINVOCA f (I)", TypeError), # args to zero-param function
|
||||||
("SI NVLLVS TVNC { DESIGNA r VT I }", TypeError), # NVLLVS cannot be used as boolean
|
("SI NVLLVS TVNC { DESIGNA r VT I }", TypeError), # NVLLVS cannot be used as boolean
|
||||||
("[I, II][III]", IndexError), # index too high
|
("[I, II][III]", IndexError), # index too high
|
||||||
("[I, II][-I]", IndexError), # negative index
|
("CVM SVBNVLLA\n[I, II][-I]", IndexError), # negative index
|
||||||
|
("[I, II][-I]", ValueError), # negative value
|
||||||
]
|
]
|
||||||
|
|
||||||
class TestErrors(unittest.TestCase):
|
class TestErrors(unittest.TestCase):
|
||||||
@@ -455,6 +456,14 @@ class TestNumerals(unittest.TestCase):
|
|||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
num_to_int("IM", False)
|
num_to_int("IM", False)
|
||||||
|
|
||||||
|
def test_negative_without_svbnvlla_raises(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
num_to_int("-IV", False)
|
||||||
|
|
||||||
|
def test_negative_with_svbnvlla(self):
|
||||||
|
self.assertEqual(num_to_int("-IV", False, True), -4)
|
||||||
|
self.assertEqual(num_to_int("-XLII", False, True), -42)
|
||||||
|
|
||||||
# int_to_num: valid cases
|
# int_to_num: valid cases
|
||||||
def test_int_to_num(self):
|
def test_int_to_num(self):
|
||||||
for n, s in [(1,"I"),(4,"IV"),(9,"IX"),(40,"XL"),(42,"XLII"),(3999,"MMMCMXCIX")]:
|
for n, s in [(1,"I"),(4,"IV"),(9,"IX"),(40,"XL"),(42,"XLII"),(3999,"MMMCMXCIX")]:
|
||||||
|
|||||||
Reference in New Issue
Block a user