-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfim_callable.py
128 lines (93 loc) · 3.33 KB
/
fim_callable.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
import copy
import special_words
from environment import Environment
from fim_exception import FimRuntimeException
class FimCallable:
def arity(self):
pass
def call(self, interpreter, arguments):
pass
class FimFunction(FimCallable):
def __init__(self, declaration, closure):
self.closure = closure
self.declaration = declaration
def __repr__(self):
return f"<function {self.declaration.name}>"
def call(self, interpreter, arguments):
environment = Environment(self.closure)
for i in range(len(self.declaration.params)):
environment.define(self.declaration.params[i].value, arguments[i])
try:
interpreter.execute_compound(self.declaration.body.children,
Environment(environment))
except FimReturn as return_value:
return return_value.value
return None
def arity(self):
return len(self.declaration.params)
def bind(self, instance):
environment = Environment(self.closure)
environment.define(special_words.this, instance)
return FimFunction(self.declaration, environment)
class FimReturn(RuntimeError):
def __init__(self, value):
super().__init__("Return")
self.value = value
class FimClass(FimCallable):
def __init__(self, name, superclass, methods, fields):
self.name = name
self.superclass = superclass
self.methods = methods
self.fields = self.add_superclass_fields(fields)
def __str__(self):
return self.name
def __repr__(self):
return f"<class {self.name}>"
def arity(self):
return 0
def call(self, interpreter, arguments):
instance = FimInstance(self, self.fields)
return instance
def add_superclass_fields(self, fields):
if self.superclass is None:
return fields
fields = copy.deepcopy(fields)
for key, value in self.superclass.fields.items():
if key not in fields:
fields[key] = value
return fields
def find_method(self, name):
if name in self.methods:
return self.methods[name]
if self.superclass is not None:
return self.superclass.find_method(name)
return None
class FimInstance:
def __init__(self, fim_class, fields):
self.fim_class = fim_class
self.fields = copy.copy(fields)
self.fields[special_words.this] = self
def __str__(self):
return f'{self.fim_class.name} instance'
def __repr__(self):
return f'<{self.fim_class.name}: {self.fields}>'
def get(self, token):
if token.value in self.fields:
return self.fields[token.value]
method = self.fim_class.find_method(token.value)
if method is not None:
return method.bind(self)
raise FimRuntimeException(
token,
f'{self.fim_class.name} has no field {token.value}')
def set(self, token, value):
self.fields[token.value] = value
class FimArray:
def __init__(self, elements):
self.elements = elements
def __repr__(self):
return f'<{self.__str__()}>'
def __iter__(self):
return iter(self.elements)
def __str__(self):
return f'{", ".join(map(str, self.elements))}'