273 lines
7.7 KiB
Python
273 lines
7.7 KiB
Python
import random
|
|
import roman
|
|
|
|
from rply.token import BaseBox
|
|
|
|
NUMERALS = [
|
|
("I", 1),
|
|
("V", 5),
|
|
("X", 10),
|
|
("L", 50),
|
|
("C", 100),
|
|
("D", 500),
|
|
("M", 1000)
|
|
]
|
|
|
|
def rep_join(l):
|
|
format_string = ',\n'.join(
|
|
[repr(i) if not isinstance(i, str) else i for i in l]
|
|
).replace('\n', '\n ')
|
|
|
|
if format_string != "":
|
|
format_string = f"\n {format_string}\n"
|
|
|
|
return format_string
|
|
|
|
def num_to_int(n):
|
|
return roman.fromRoman(n)
|
|
|
|
class ExpressionStatement(BaseBox):
|
|
def __init__(self, expression) -> None:
|
|
self.expression = expression
|
|
|
|
def __repr__(self) -> str:
|
|
return self.expression.__repr__()
|
|
|
|
def eval(self, vtable, ftable, modules):
|
|
self.expression.eval(vtable.copy(), ftable.copy(), modules)
|
|
return vtable, ftable
|
|
|
|
class String(BaseBox):
|
|
def __init__(self, value) -> None:
|
|
self.value = value
|
|
|
|
def __repr__(self):
|
|
return f"String({self.value})"
|
|
|
|
def eval(self, *_):
|
|
return self.value
|
|
|
|
class Numeral(BaseBox):
|
|
def __init__(self, value) -> None:
|
|
self.value = value
|
|
|
|
def __repr__(self):
|
|
return f"Numeral({self.value})"
|
|
|
|
def eval(self, *_):
|
|
return num_to_int(self.value)
|
|
|
|
class Bool(BaseBox):
|
|
def __init__(self, value) -> None:
|
|
self.value = value
|
|
|
|
def __repr__(self):
|
|
return f"Bool({self.value})"
|
|
|
|
def eval(self, *_):
|
|
return self.value
|
|
|
|
class ModuleCall(BaseBox):
|
|
def __init__(self, module_name) -> None:
|
|
self.module_name = module_name
|
|
|
|
def __repr__(self) -> str:
|
|
return f"{self.module_name}"
|
|
|
|
class ID(BaseBox):
|
|
def __init__(self, name: str) -> None:
|
|
self.name = name
|
|
|
|
def __repr__(self) -> str:
|
|
return f"ID({self.name})"
|
|
|
|
def eval(self, vtable, *_):
|
|
return vtable[self.name]
|
|
|
|
class Designa(BaseBox):
|
|
def __init__(self, variable: ID, value) -> None:
|
|
self.id = variable
|
|
self.value = value
|
|
|
|
def __repr__(self) -> str:
|
|
id_string = repr(self.id).replace('\n', '\n ')
|
|
value_string = repr(self.value).replace('\n', '\n ')
|
|
return f"Designa(\n {id_string},\n {value_string}\n)"
|
|
|
|
def eval(self, vtable, ftable, modules):
|
|
vtable[self.id.name] = self.value.eval(
|
|
vtable.copy(), ftable.copy(), modules
|
|
)
|
|
return vtable, ftable
|
|
|
|
class Defini(BaseBox):
|
|
def __init__(self, name, parameters, statements) -> None:
|
|
self.name = name
|
|
self.parameters = parameters
|
|
self.statements = statements
|
|
|
|
def __repr__(self) -> str:
|
|
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
|
statements_string = f"statements([{rep_join(self.statements)}])"
|
|
def_string = rep_join(
|
|
[f"{repr(self.name)}", parameter_string, statements_string]
|
|
)
|
|
return f"Defini({def_string})"
|
|
|
|
class Redi(BaseBox):
|
|
def __init__(self, values) -> None:
|
|
self.values = values
|
|
|
|
def __repr__(self) -> str:
|
|
values_string = f"[{rep_join(self.values)}]"
|
|
return f"Redi({values_string})"
|
|
|
|
class Erumpe(BaseBox):
|
|
def __repr__(self) -> str:
|
|
return "Erumpe()"
|
|
|
|
def eval(self, vtable, ftable, _):
|
|
vtable["ERUMPE"] = True
|
|
return vtable, ftable
|
|
|
|
class Nullus(BaseBox):
|
|
def __repr__(self) -> str:
|
|
return "Nullus()"
|
|
|
|
def eval(self, *_):
|
|
return 0
|
|
|
|
class BinOp(BaseBox):
|
|
def __init__(self, left, right, op) -> None:
|
|
self.left = left
|
|
self.right = right
|
|
self.op = op
|
|
|
|
def __repr__(self) -> str:
|
|
binop_string = rep_join([self.left, self.right, self.op])
|
|
return f"BinOp({binop_string})"
|
|
|
|
def eval(self, vtable, ftable, modules):
|
|
left = self.left.eval(vtable.copy(), ftable.copy(), modules)
|
|
right = self.right.eval(vtable.copy(), ftable.copy(), modules)
|
|
match self.op:
|
|
case "SYMBOL_PLUS":
|
|
return left + right
|
|
case "KEYWORD_MINUS":
|
|
return left < right
|
|
case "KEYWORD_PLUS":
|
|
return left > right
|
|
case _:
|
|
raise Exception(self.op)
|
|
|
|
class SiStatement(BaseBox):
|
|
def __init__(self, test, statements, else_part) -> None:
|
|
self.test = test
|
|
self.statements = statements
|
|
self.else_part = else_part
|
|
|
|
def __repr__(self) -> str:
|
|
test = repr(self.test)
|
|
statements = f"statements([{rep_join(self.statements)}])"
|
|
else_part = f"statements([{rep_join(self.else_part)}])"
|
|
si_string = rep_join([test, statements, else_part])
|
|
return f"Si({si_string})"
|
|
|
|
def eval(self, vtable, ftable, modules):
|
|
if self.test.eval(vtable, ftable, modules):
|
|
for statement in self.statements:
|
|
vtable, ftable = statement.eval(
|
|
vtable, ftable, modules
|
|
)
|
|
else:
|
|
for statement in self.else_part:
|
|
vtable, ftable = statement.eval(
|
|
vtable, ftable, modules
|
|
)
|
|
|
|
return vtable, ftable
|
|
|
|
class DumStatement(BaseBox):
|
|
def __init__(self, test, statements) -> None:
|
|
self.test = test
|
|
self.statements = statements
|
|
|
|
def __repr__(self) -> str:
|
|
test = repr(self.test)
|
|
statements = f"statements([{rep_join(self.statements)}])"
|
|
dum_string = rep_join([test, statements])
|
|
return f"Dum({dum_string})"
|
|
|
|
def eval(self, vtable, ftable, modules):
|
|
while not self.test.eval(vtable, ftable, modules):
|
|
for statement in self.statements:
|
|
vtable, ftable = statement.eval(
|
|
vtable, ftable, modules
|
|
)
|
|
if vtable["ERUMPE"]:
|
|
break
|
|
|
|
if vtable["ERUMPE"]:
|
|
vtable["ERUMPE"] = False
|
|
break
|
|
|
|
return vtable, ftable
|
|
|
|
class Invoca(BaseBox):
|
|
def __init__(self, name, parameters) -> None:
|
|
self.name = name
|
|
self.parameters = parameters
|
|
|
|
def __repr__(self) -> str:
|
|
parameters_string = f"parameters([{rep_join(self.parameters)}])"
|
|
invoca_string = rep_join([self.name, parameters_string])
|
|
return f"Invoca({invoca_string})"
|
|
|
|
class BuiltIn(BaseBox):
|
|
def __init__(self, builtin, parameters) -> None:
|
|
self.builtin = builtin
|
|
self.parameters = parameters
|
|
|
|
def __repr__(self) -> str:
|
|
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
|
builtin_string = rep_join([self.builtin, parameter_string])
|
|
return f"Builtin({builtin_string})"
|
|
|
|
def eval(self, vtable, ftable, modules):
|
|
parameters = [
|
|
i.eval(vtable.copy(), ftable.copy(), modules)
|
|
for i in self.parameters
|
|
]
|
|
|
|
match self.builtin:
|
|
case "AUDI_NUMERUS":
|
|
return num_to_int(input())
|
|
case "DICE":
|
|
print(' '.join(parameters))
|
|
return None
|
|
case "ERUMPE":
|
|
vtable["ERUMPE"] = True
|
|
return None
|
|
case "FORTIS_NUMERUS":
|
|
return random.randint(parameters[0], parameters[1])
|
|
case _:
|
|
raise Exception(self.builtin)
|
|
|
|
class Program(BaseBox):
|
|
def __init__(self, module_calls: list[ModuleCall], statements) -> None:
|
|
self.modules = module_calls
|
|
self.statements = statements
|
|
|
|
def __repr__(self) -> str:
|
|
modules_string = f"modules([{rep_join(self.modules)}])"
|
|
statements_string = f"statements([{rep_join(self.statements)}])"
|
|
return f"{modules_string},\n{statements_string}"
|
|
|
|
def eval(self):
|
|
vtable = {"ERUMPE": False}
|
|
ftable = {}
|
|
modules = [module.module_name for module in self.modules]
|
|
|
|
for statement in self.statements:
|
|
vtable, ftable = statement.eval(vtable, ftable, modules)
|