1
- from .utils .classes import *
2
- from .utils .evals import *
1
+ from jink .utils .classes import *
2
+ from jink .utils .evals import *
3
+
4
+ TYPES = {
5
+ int : 'int' ,
6
+ float : 'float' ,
7
+ str : 'string' ,
8
+ dict : 'obj'
9
+ }
10
+
11
+ # The interpreter environment
12
+ class Environment :
13
+ def __init__ (self , parent = None , s_type = None , debug = False ):
14
+ self ._id = parent ._id + 1 if parent else 0
15
+ self .index = {}
16
+ self .parent = parent
17
+ self .type = s_type
18
+ self .debug = debug
19
+
20
+ # To define builtin methods - only for use on the top level interpreter environment
21
+ def add_builtins (self ):
22
+ self .def_func ('print' , lambda scope , args : print ('\n ' .join ([str (x ) for x in args ]) or 'null' ))
23
+ self .def_func ('string' , lambda scope , args : [str (x or 'null' ) for x in args ][0 ] if len (args ) == 1 else [str (x or 'null' ) for x in args ])
24
+ self .def_func ('input' , lambda scope , args : input (' ' .join (args )))
25
+
26
+ def extend (self , s_type ):
27
+ return Environment (self , s_type )
28
+
29
+ def find_scope (self , name ):
30
+ if self .debug :
31
+ print (f"Searching for { name } in scopes.." )
32
+ scope = self
33
+ while scope :
34
+ if self .debug :
35
+ print (f"Searching { scope ._id } .. found { list (self .index .keys ())} " )
36
+ if name in scope .index :
37
+ return scope
38
+ scope = scope .parent
39
+
40
+ def get_var (self , name ):
41
+ scope = self .find_scope (name )
42
+ if not scope :
43
+ raise Exception (f"{ name } is not defined." )
44
+
45
+ elif name in scope .index :
46
+ return scope .index [name ]
47
+
48
+ raise Exception (f"{ name } is not defined." )
49
+
50
+ # Functions override to update values
51
+ # from parent scopes in local scope during their lifecycle
52
+ def set_var (self , name , value , var_type = None , fn_scoped = False ):
53
+ scope = self .find_scope (name )
54
+
55
+ for py_type , _type in TYPES .items ():
56
+ if isinstance (value , py_type ):
57
+ val_type = _type
58
+
59
+ if fn_scoped :
60
+ self .index [name ] = { 'value' : value , 'type' : val_type , 'var_type' : var_type }
61
+ return value
62
+
63
+ # Assignments
64
+ if scope :
65
+ v = scope .get_var (name )
66
+
67
+ if var_type != None :
68
+ raise Exception (f"{ name } is already defined." )
69
+ elif v ['var_type' ] == 'const' :
70
+ raise Exception (f"Constant { name } is not reassignable." )
71
+
72
+ scope .index [name ]['value' ] = value
73
+ scope .index [name ]['type' ] = val_type
74
+
75
+ # Definitions
76
+ else :
77
+ if not var_type :
78
+ raise Exception (f"Expected let or const, got 'null' for { name } ." )
79
+ self .index [name ] = { 'value' : value , 'type' : val_type , 'var_type' : var_type }
80
+
81
+ return value
82
+
83
+ def def_func (self , name , func ):
84
+ if self .debug :
85
+ print (f"Defining { name } in { self ._id } " )
86
+ self .index [name ] = func
87
+ return func
88
+
89
+ def __str__ (self ):
90
+ return f"{ self .parent or 'null' } ->{ self ._id } :{ list (self .index .keys ())} "
3
91
4
92
class Interpreter :
5
93
def __init__ (self ):
@@ -28,8 +116,10 @@ def evaluate_top(self, expr):
28
116
raise Exception (f"Object '{ expr .name } ' does not contain the property '{ expr .index ['index' ].name } '" )
29
117
else :
30
118
return obj [expr .index ['index' ].name ]
119
+
120
+ # TODO: Object methods, classes.
31
121
elif isinstance (expr .index ['index' ], CallExpression ):
32
- pass
122
+ return self . call_function ( expr . index [ 'index' ])
33
123
34
124
elif isinstance (expr , (StringLiteral , IntegerLiteral , FloatingPointLiteral )):
35
125
return self .unwrap_value (expr )
@@ -40,6 +130,8 @@ def evaluate_top(self, expr):
40
130
elif isinstance (expr , Null ):
41
131
return { 'type' : 'null' , 'value' : 'null' }
42
132
133
+ # TODO Properly evaluate unary operators modifying variables
134
+ # (e.g. pre and post increment ++i and i++)
43
135
elif isinstance (expr , UnaryOperator ):
44
136
value = self .evaluate_top (expr .value )
45
137
return UNOP_EVALS [expr .operator ](self .unwrap_value (value )) or 0
@@ -70,17 +162,15 @@ def evaluate_top(self, expr):
70
162
self .evaluate (expr .body , self .env )
71
163
72
164
elif isinstance (expr , CallExpression ):
73
- scope = self .env .extend ('call' )
74
- func = self .evaluate_top (expr .name )
75
- return func (scope , [self .unwrap_value (self .evaluate_top (arg )) for arg in expr .args ])
165
+ return self .call_function (expr )
76
166
77
167
elif isinstance (expr , Function ):
78
168
return self .make_function (expr )
79
169
80
170
elif isinstance (expr , Return ):
81
- result = self .evaluate_top (expr .expression )
171
+ result = self .evaluate_top (expr .value )
82
172
return { 'type' : 'return' , 'value' : self .unwrap_value (result ) }
83
-
173
+
84
174
elif isinstance (expr , dict ):
85
175
return expr
86
176
@@ -95,6 +185,12 @@ def evaluate_condition(self, cond):
95
185
elif cond ['type' ] != 'bool' :
96
186
return 'true'
97
187
188
+ # Call a function in a new scope
189
+ def call_function (self , expr ):
190
+ scope = self .env .extend (f"call_{ expr .name .name } " )
191
+ func = self .evaluate_top (expr .name )
192
+ return func (scope , [self .unwrap_value (self .evaluate_top (arg )) for arg in expr .args ])
193
+
98
194
# Make a function
99
195
def make_function (self , func ):
100
196
def function (scope , args ):
@@ -104,21 +200,14 @@ def function(scope, args):
104
200
if len (args ) > len (params ):
105
201
raise Exception (f"Function '{ func .name } ' takes { len (params )} arguments but { len (args )} were given." )
106
202
107
- # Apply arguments to this call's scope, otherwise use function defaults if any
203
+ # Apply arguments to this call's scope
204
+ # If argument doesn't exist use function default if it exists
108
205
i = 0
109
206
110
207
for p in params :
111
208
default = None
112
209
113
- if isinstance (p , Assignment ):
114
- default = p .value or 'null'
115
- name = p .ident .name
116
- _type = p .type
117
- class Object (): pass
118
- p = Object ()
119
- setattr (p , 'name' , name )
120
- setattr (p , 'type' , _type )
121
- elif p .default :
210
+ if p .default :
122
211
default = self .unwrap_value (p .default )
123
212
124
213
if len (args ) > i :
@@ -128,9 +217,9 @@ class Object(): pass
128
217
129
218
if value != None :
130
219
try :
131
- scope .set_var (p .name , value , p .type )
132
- except :
133
- raise Exception (f"Improper function parameter or call argument at function '{ func .name } '." )
220
+ scope .set_var (p .name , value , p .type , fn_scoped = True )
221
+ except Exception as e :
222
+ raise Exception (f"{ e } \n Exception: Improper function parameter or call argument at function '{ func .name } '." )
134
223
i += 1
135
224
136
225
# Ensure returning of the correct value
0 commit comments