-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterpreterv1.py
99 lines (83 loc) · 3.55 KB
/
interpreterv1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from brewparse import parse_program
from element import Element
from intbase import InterpreterBase, ErrorType
class Interpreter(InterpreterBase):
builtin_functions = {"print", "inputi"}
def __init__(self, console_output=True, inp=None, trace_output=False):
super().__init__(console_output, inp)
self.trace_output = trace_output
self.variables = {}
def run(self, program):
program_node = parse_program(program)
functions = program_node.get("functions")
self.function_defs = {function.get("name"): function for function in functions}
main_function = Element("fcall", name="main", args=[])
self.run_function(main_function)
def run_function(self, function):
name = function.get("name")
args = function.get("args")
if name in self.function_defs:
function_def = self.function_defs[name]
for statement in function_def.get("statements"):
self.run_statement(statement)
elif name in self.builtin_functions:
return self.run_builtin(function)
else:
self.error(ErrorType.NAME_ERROR, f"No {name}() function was found")
def run_builtin(self, function):
name = function.get("name")
args = function.get("args")
match name:
case "print":
self.output(
"".join(
str(self.evaluate_expression(arg).get("val")) for arg in args
)
)
case "inputi":
if len(args) == 1:
self.output(self.evaluate_expression(args[0]).get("val"))
elif len(args) > 1:
self.error(
ErrorType.NAME_ERROR,
"No inputi() function found that takes > 1 parameter",
)
return Element("int", val=int(self.get_input()))
def run_statement(self, statement):
match statement.elem_type:
case "=":
self.run_assignment(statement)
case "fcall":
self.run_function(statement)
def run_assignment(self, assignment):
name = assignment.get("name")
expression = assignment.get("expression")
self.variables[name] = self.evaluate_expression(expression)
def evaluate_expression(self, expression):
match expression.elem_type:
case "+" | "-":
return self.evaluate_binary_operation(expression)
case "fcall":
return self.run_function(expression)
case "var":
name = expression.get("name")
if name in self.variables:
return self.variables[name]
else:
self.error(
ErrorType.NAME_ERROR, f"Variable {name} has not been defined"
)
case "int" | "string":
return expression
def evaluate_binary_operation(self, operation):
op1 = self.evaluate_expression(operation.get("op1"))
op2 = self.evaluate_expression(operation.get("op2"))
if op1.elem_type == "string" or op2.elem_type == "string":
self.error(
ErrorType.TYPE_ERROR, "Incompatible types for arithmetic operation"
)
match operation.elem_type:
case "+":
return Element(op1.elem_type, val=op1.get("val") + op2.get("val"))
case "-":
return Element(op1.elem_type, val=op1.get("val") - op2.get("val"))