diff --git a/centvrion/ast_nodes.py b/centvrion/ast_nodes.py index c806803..464086a 100644 --- a/centvrion/ast_nodes.py +++ b/centvrion/ast_nodes.py @@ -31,6 +31,13 @@ def rep_join(l): return format_string +OP_STR = { + "SYMBOL_PLUS": "+", "SYMBOL_MINUS": "-", + "SYMBOL_TIMES": "*", "SYMBOL_DIVIDE": "/", + "KEYWORD_EST": "EST", "KEYWORD_MINVS": "MINVS", + "KEYWORD_PLVS": "PLVS", "KEYWORD_ET": "ET", "KEYWORD_AVT": "AVT", +} + def single_num_to_int(i, m): if i[-1] == "_": if not m: @@ -136,6 +143,9 @@ class ExpressionStatement(Node): def __repr__(self) -> str: return self.expression.__repr__() + def print(self): + return self.expression.print() + def _eval(self, vtable): return self.expression.eval(vtable) @@ -151,6 +161,10 @@ class DataArray(Node): content_string = rep_join(self.content) return f"Array([{content_string}])" + def print(self): + items = ", ".join(i.print() for i in self.content) + return f"[({items})]" + def _eval(self, vtable): vals = [] for item in self.content: @@ -171,6 +185,9 @@ class DataRangeArray(Node): content_string = rep_join([self.from_value, self.to_value]) return f"RangeArray([{content_string}])" + def print(self): + return f"[{self.from_value.print()} VSQVE {self.to_value.print()}]" + def _eval(self, vtable): vtable, from_val = self.from_value.eval(vtable) vtable, to_val = self.to_value.eval(vtable) @@ -187,6 +204,9 @@ class String(Node): def __repr__(self): return f"String({self.value})" + def print(self): + return f'"{self.value}"' + def _eval(self, vtable): return vtable, ValStr(self.value) @@ -201,6 +221,9 @@ class Numeral(Node): def __repr__(self): return f"Numeral({self.value})" + def print(self): + return self.value + def _eval(self, vtable): return vtable, ValInt(num_to_int(self.value, "MAGNVM" in vtable["#modules"])) @@ -215,6 +238,9 @@ class Bool(Node): def __repr__(self): return f"Bool({self.value})" + def print(self): + return "VERITAS" if self.value else "FALSITAS" + def _eval(self, vtable): return vtable, ValBool(self.value) @@ -229,6 +255,9 @@ class ModuleCall(BaseBox): def __repr__(self) -> str: return f"{self.module_name}" + def print(self): + return f"CVM {self.module_name}" + class ID(Node): def __init__(self, name: str) -> None: @@ -240,6 +269,9 @@ class ID(Node): def __repr__(self) -> str: return f"ID({self.name})" + def print(self): + return self.name + def _eval(self, vtable): return vtable, vtable[self.name] @@ -257,6 +289,9 @@ class Designa(Node): value_string = repr(self.value).replace('\n', '\n ') return f"Designa(\n {id_string},\n {value_string}\n)" + def print(self): + return f"DESIGNA {self.id.print()} VT {self.value.print()}" + def _eval(self, vtable): vtable, val = self.value.eval(vtable) vtable[self.id.name] = val @@ -280,6 +315,11 @@ class Defini(Node): ) return f"Defini({def_string})" + def print(self): + params = ", ".join(p.print() for p in self.parameters) + body = "\n".join(s.print() for s in self.statements) + return f"DEFINI {self.name.print()} ({params}) VT {{\n{body}\n}}" + def _eval(self, vtable): vtable[self.name.name] = ValFunc(self.parameters, self.statements) return vtable, ValNul() @@ -296,6 +336,10 @@ class Redi(Node): values_string = f"[{rep_join(self.values)}]" return f"Redi({values_string})" + def print(self): + exprs = ", ".join(v.print() for v in self.values) + return f"REDI ({exprs})" + def _eval(self, vtable): vals = [] for v in self.values: @@ -315,6 +359,9 @@ class Erumpe(Node): def __repr__(self) -> str: return "Erumpe()" + def print(self): + return "ERVMPE" + def _eval(self, vtable): vtable["#break"] = True return vtable, ValNul() @@ -327,6 +374,9 @@ class Nullus(Node): def __repr__(self) -> str: return "Nullus()" + def print(self): + return "NVLLVS" + def _eval(self, vtable): return vtable, ValNul() @@ -344,6 +394,9 @@ class BinOp(Node): binop_string = rep_join([self.left, self.right, self.op]) return f"BinOp({binop_string})" + def print(self): + return f"({self.left.print()} {OP_STR[self.op]} {self.right.print()})" + def _eval(self, vtable): vtable, left = self.left.eval(vtable) vtable, right = self.right.eval(vtable) @@ -382,6 +435,9 @@ class UnaryMinus(Node): def __repr__(self): return f"UnaryMinus({self.expr!r})" + def print(self): + return f"(- {self.expr.print()})" + def _eval(self, vtable): vtable, val = self.expr.eval(vtable) return vtable, ValInt(-val.value()) @@ -398,6 +454,9 @@ class ArrayIndex(Node): def __repr__(self) -> str: return f"ArrayIndex({self.array!r}, {self.index!r})" + def print(self): + return f"{self.array.print()}[{self.index.print()}]" + def _eval(self, vtable): vtable, array = self.array.eval(vtable) vtable, index = self.index.eval(vtable) @@ -424,6 +483,14 @@ class SiStatement(Node): si_string = rep_join([test, statements, else_part]) return f"Si({si_string})" + def print(self): + body = "\n".join(s.print() for s in self.statements) + result = f"SI {self.test.print()} TVNC {{\n{body}\n}}" + if self.else_part: + else_body = "\n".join(s.print() for s in self.else_part) + result += f" ALVID {{\n{else_body}\n}}" + return result + def _eval(self, vtable): vtable, cond = self.test.eval(vtable) last_val = ValNul() @@ -450,6 +517,10 @@ class DumStatement(Node): dum_string = rep_join([test, statements]) return f"Dum({dum_string})" + def print(self): + body = "\n".join(s.print() for s in self.statements) + return f"DVM {self.test.print()} FACE {{\n{body}\n}}" + def _eval(self, vtable): last_val = ValNul() vtable, cond = self.test.eval(vtable) @@ -482,6 +553,10 @@ class PerStatement(Node): dum_string = rep_join([test, variable_name, statements]) return f"Per({dum_string})" + def print(self): + body = "\n".join(s.print() for s in self.statements) + return f"PER {self.variable_name.print()} IN {self.data_list.print()} FACE {{\n{body}\n}}" + def _eval(self, vtable): vtable, array = self.data_list.eval(vtable) variable_name = self.variable_name.name @@ -512,6 +587,10 @@ class Invoca(Node): invoca_string = rep_join([self.name, parameters_string]) return f"Invoca({invoca_string})" + def print(self): + args = ", ".join(p.print() for p in self.parameters) + return f"INVOCA {self.name.print()} ({args})" + def _eval(self, vtable): params = [p.eval(vtable)[1] for p in self.parameters] func = vtable[self.name.name] @@ -543,6 +622,10 @@ class BuiltIn(Node): builtin_string = rep_join([self.builtin, parameter_string]) return f"Builtin({builtin_string})" + def print(self): + args = ", ".join(p.print() for p in self.parameters) + return f"{self.builtin}({args})" + def _eval(self, vtable): params = [p.eval(vtable)[1] for p in self.parameters] magnvm = "MAGNVM" in vtable["#modules"] @@ -592,6 +675,13 @@ class Program(BaseBox): statements_string = f"statements([{rep_join(self.statements)}])" return f"{modules_string},\n{statements_string}" + def print(self): + stmts = "\n".join(s.print() for s in self.statements) + if self.modules: + mods = "\n".join(m.print() for m in self.modules) + return f"{mods}\n\n{stmts}" + return stmts + def eval(self, *_): vtable = { "#break": False, diff --git a/tests.py b/tests.py index 387d562..de38f76 100644 --- a/tests.py +++ b/tests.py @@ -51,19 +51,19 @@ def run_test(self, source, target_nodes, target_value, target_output="", input_l self.assertEqual(captured.getvalue(), target_output, "Output test") ########################## - ###### Printer Test ###### (commented out — no print() on AST nodes yet) + ###### Printer Test ###### ########################## - # try: - # new_text = program.print() - # new_tokens = Lexer().get_lexer().lex(new_text + "\n") - # new_nodes = Parser().parse(new_tokens) - # except Exception as e: - # raise Exception(f"###Printer test###\n{new_text}") from e - # self.assertEqual( - # program, - # new_nodes, - # f"Printer test\n{source}\n{new_text}" - # ) + try: + new_text = program.print() + new_tokens = Lexer().get_lexer().lex(new_text + "\n") + new_nodes = Parser().parse(new_tokens) + except Exception as e: + raise Exception(f"###Printer test###\n{new_text}") from e + self.assertEqual( + program, + new_nodes, + f"Printer test\n{source}\n{new_text}" + ) ########################## ###### Compiler Test #####