-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathInterpreter.py
141 lines (116 loc) · 3.96 KB
/
Interpreter.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
from AST import *
from Environment import EnvTable, Env, Matrix
from Utils import on, when
class Error(object):
class Break(Exception):
pass
class Continue(Exception):
pass
class MatrixInterpreter:
env_table = EnvTable()
def push_new_env(self):
self.env_table.push_env(Env(self.env_table.actual_env))
def create_fresh_env(self):
self.env_table.push_env(Env(self.env_table.global_env))
def pop_env(self):
self.env_table.pop_env()
@property
def current_env(self):
return self.env_table.actual_env
@on('node')
def eval(self, node):
raise NotImplementedError
def eval_all(self, tree: list[Statement]):
for node in tree:
self.eval(node)
@when(If)
def eval(self, if_: If):
if self.eval(if_.condition):
self.push_new_env()
self.eval(if_.then)
self.pop_env()
elif if_.else_:
self.push_new_env()
self.eval(if_.else_)
self.pop_env()
@when(While)
def eval(self, while_: While):
while self.eval(while_.condition):
try:
self.push_new_env()
self.eval(while_.body)
except Error.Break:
break
except Error.Continue:
continue
finally:
self.pop_env()
@when(For)
def eval(self, for_: For):
self.current_env.create(for_.var.name)
for i in self.eval(for_.range):
self.current_env.update(for_.var.name, i)
try:
self.push_new_env()
self.eval(for_.body)
except Error.Break:
break
except Error.Continue:
continue
finally:
self.pop_env()
@when(Break)
def eval(self, break_: Break):
raise Error.Break
@when(Continue)
def eval(self, continue_: Continue):
raise Error.Continue
@when(SymbolRef)
def eval(self, ref: SymbolRef):
return self.current_env.get_value(ref.name)
@when(MatrixRef)
def eval(self, ref: MatrixRef) -> int | float:
return self.current_env.get_value(ref.matrix.name)[self.eval(ref.row)][self.eval(ref.col)]
@when(VectorRef)
def eval(self, ref: VectorRef) -> int | float:
return self.eval(ref.vector)[self.eval(ref.element)]
@when(Assign)
def eval(self, assign: Assign):
res = self.eval(assign.expr)
if isinstance(assign.var, SymbolRef):
updated = self.current_env.update(assign.var.name, res)
if not updated:
self.current_env.create(assign.var.name, res)
elif isinstance(assign.var, MatrixRef):
matrix: Matrix = self.current_env.get_value(assign.var.matrix.name)
matrix[self.eval(assign.var.row)][self.eval(assign.var.col)] = res
elif isinstance(assign.var, VectorRef):
vector = self.current_env.get_value(assign.var.vector.name)
vector[self.eval(assign.var.element)] = res
else:
raise NotImplementedError
@when(Apply)
def eval(self, apply: Apply):
if isinstance(apply.ref, SymbolRef):
f = self.current_env.get_function(apply.ref.name)
if f is None:
raise NotImplementedError(f"Function {apply.ref.name} not implemented")
return f(*(self.eval(arg) for arg in apply.args))
else:
raise NotImplementedError
@when(Range)
def eval(self, range_: Range) -> range:
start: int = self.eval(range_.start)
stop: int = self.eval(range_.end)
return range(start, stop)
@when(Literal)
def eval(self, literal: Literal):
return literal.value
@when(Return)
def eval(self, return_: Return):
return self.eval(return_)
@when(Block)
def eval(self, block: Block):
self.push_new_env()
self.eval_all(block.statements)
self.pop_env()