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 # TODO: Magnum def num_to_int(n): return roman.fromRoman(n) def make_string(n): if isinstance(n, str): return n elif isinstance(n, int): return roman.toRoman(n) elif isinstance(n, list): return f"[{' '.join([make_string(i) for i in n])}]" else: raise Exception(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 DataArray(BaseBox): def __init__(self, content) -> None: self.content = content def __repr__(self) -> str: content_string = rep_join(self.content) return f"Array([{content_string}])" def eval(self, vtable, ftable, modules): content = [i.eval(vtable, ftable, modules) for i in self.content] return content class DataRangeArray(BaseBox): def __init__(self, from_value, to_value) -> None: self.from_value = from_value self.to_value = to_value def __repr__(self) -> str: content_string = rep_join([self.from_value, self.to_value]) return f"RangeArray([{content_string}])" def eval(self, *_): content = list(range(self.from_value.eval(), self.to_value.eval())) return content 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})" def eval(self, vtable, ftable, _): ftable[self.name.name] = ( self.parameters, self.statements ) return vtable, ftable 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})" def eval(self, vtable, ftable, modules): values = [ i.eval(vtable.copy(), ftable.copy(), modules) for i in self.values ] if len(values) == 1: vtable["REDI"] = values[0] else: vtable["REDI"] = values return vtable, ftable 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 "SYMBOL_MINUS": return left - right case "SYMBOL_TIMES": return left * right case "SYMBOL_DIVIDE": # TODO: Fractio return left // right case "KEYWORD_MINUS": return left < right case "KEYWORD_PLUS": return left > right case "KEYWORD_EST": 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 PerStatement(BaseBox): def __init__(self, data_list, variable_name, statements) -> None: self.data_list = data_list self.variable_name = variable_name self.statements = statements def __repr__(self) -> str: test = repr(self.data_list) variable_name = repr(self.variable_name) statements = f"statements([{rep_join(self.statements)}])" dum_string = rep_join([test, variable_name, statements]) return f"Per({dum_string})" def eval(self, vtable, ftable, modules): data_array = self.data_list.eval(vtable, ftable, modules) variable_name = self.variable_name.name for i in data_array: vtable[variable_name] = i 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})" def eval(self, vtable, ftable, modules): parameters = [ i.eval(vtable.copy(), ftable.copy(), modules) for i in self.parameters ] vtable_copy = vtable.copy() function = ftable[self.name.name] for i, parameter in enumerate(function[0]): vtable_copy[parameter.name] = parameters[i] vtable_copy["REDI"] = None for statement in function[1]: statement.eval(vtable_copy, ftable, modules) if vtable_copy["REDI"] is not None: return vtable_copy["REDI"] 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(make_string(i) for i in parameters)) return None case "ERUMPE": vtable["ERUMPE"] = True return None case "FORTIS_NUMERUS": # TODO: Fors 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)