-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenv_v4.py
79 lines (67 loc) · 3.04 KB
/
env_v4.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
# the EnvironmentManager class keeps a mapping between each variable (aka symbol) in a
# brewin program and the value of that variable - the value that's passed in can be anything you like
# in our implementation we pass in a Value object which holds a type and a value
class EnvironmentManager:
def __init__(self):
# stack of environments, where each environment is a dictionary
# the bottom-most dictionary is the global scope
self.scopes = [{"type": "function", "variables": {}}]
# looks for a symbol starting from the current (top-most) scope down to the global scope
def get(self, symbol):
for scope in reversed(self.scopes):
# if you find the variable
# and you're not in a function looking at a different function's scope
if symbol in scope["variables"] and not (
scope["type"] == "function"
and scope != self.scopes[-1]
and self.scopes[-1]["type"] == "function"
):
return scope["variables"][symbol]
return None
# search all scopes to find where the symbol is defined and update it there
def set(self, symbol, value):
for scope in reversed(self.scopes):
# TODO: may need to update this with the same logic as get
# but this works for now
if symbol in scope["variables"]:
scope["variables"][symbol] = value
return True
return False
# adds a new symbol to the current (top-most) scope, initializing it with `start_val`
def create(self, symbol, start_val):
if symbol not in self.scopes[-1]["variables"]:
self.scopes[-1]["variables"][symbol] = start_val
return True
return False
def copy(self):
copied_manager = EnvironmentManager()
copied_manager.scopes = []
for scope in self.scopes:
variables = {}
for name, variable in scope["variables"].items():
variables[name] = variable
copied_scope = {
"type": scope["type"],
"variables": variables,
}
copied_manager.scopes.append(copied_scope)
return copied_manager
# enters a new scope by adding a new dictionary to the scopes stack
def push_scope(self, type):
self.scopes.append({"type": type, "variables": {}, "evaluated": {}})
# exits the current scope by removing the top-most dictionary from the stack
def pop_scope(self):
if len(self.scopes) > 1:
self.scopes.pop()
else:
raise Exception("Cannot pop global scope")
# prints all scopes for debugging purposes
def print(self):
for i, scope in enumerate(reversed(self.scopes)):
print(f"Scope {len(self.scopes) - i - 1}")
for key, value in scope["variables"].items():
type = scope["type"]
print(
f"Scope {len(self.scopes) - i - 1} | {type} | {key}: {value.print()}"
)
print()