-
Notifications
You must be signed in to change notification settings - Fork 0
/
interpreter.rkt
339 lines (282 loc) · 15.7 KB
/
interpreter.rkt
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
;0 Interpreter part 1
; Isaac Ng ikn3, Rahul Pokharna rkp43, Sibi Sengottuvel sxs1552
(load "functionParser.scm")
; Function to start interpreting
(define evaluateDoc
(lambda (fileName)
(call/cc
(lambda (return)
(evaluateStatements (parser fileName) initState return initBreak initCont initThrow)))))
; Main functiion, evaluates list of statements fed into it
;Multiple statements
(define evaluateStatements
(lambda (stmts state return break continue throw)
(cond
((null? stmts) state)
((list? (car stmts)) (evaluateStatements (cdr stmts) (evaluateStatement (car stmts) state return break continue throw) return break continue throw))
(else (evaluateStatement stmts state return break continue throw)))))
; Single statement
(define evaluateStatement
(lambda (stmt state return break continue throw)
(cond
((null? stmt) state)
((eq? 'begin (operator stmt)) (evaluateBlock stmt state return break continue throw))
((eq? 'break (operator stmt)) (break state))
((eq? 'if (car stmt)) (evaluateIf stmt state return break continue throw))
((eq? 'while (car stmt)) (call/cc
(lambda (breaknew)
(evaluateWhile stmt state return (lambda (s) (breaknew (removeStateLayer s))) continue throw))))
((eq? 'return (car stmt)) (return (evaluateExpression (returnValue stmt) state return break continue throw)))
((eq? '= (car stmt)) (evaluateAssign stmt state return break continue throw))
((eq? 'var (car stmt)) (evaluateDeclare stmt state return break continue throw))
((eq? 'try (car stmt)) (evaluateTryCatchBlock stmt state return break continue throw))
((eq? 'throw (car stmt)) (throw state (operand1 stmt)))
((eq? 'continue (car stmt)) (continue state))
(else (evaluateExpression stmt state return break continue throw)))))
; add a layer to the state
(define addStateLayer
(lambda (state)
(cons (list '() '()) state)))
; remove a layer from the state
(define removeStateLayer
(lambda (state)
(cdr state)))
; Function for evaluating if statements
(define evaluateIf
(lambda (stmt state return break continue throw)
(if (eq? 'true (evaluateExpression (ifCond stmt) state return break continue throw))
(evaluateStatement (ifTrue stmt) state return break continue throw)
(if (not (null? (falseCheck stmt)))
(evaluateStatement (ifFalse stmt) state return break continue throw)
state))))
; Function to evaluate while loops
(define evaluateWhile
(lambda (stmt state return break continue throw)
(if (eq? 'true (evaluateBool (ifCond stmt) state return break continue throw))
(evaluateWhile stmt (call/cc
(lambda (continuenew)
(evaluateStatement (ifTrue stmt) state return break (lambda (s) (continuenew (removeStateLayer s))) throw))) return break continue throw)
state)))
; Function to evaluate declaration, adding it to the state
(define evaluateDeclare
(lambda (stmt state return break continue throw)
(cond
((null? (assignCheck stmt)) (putInState (variableName stmt) 'error state))
(else (putInState (variableName stmt) (evaluateExpression (assignVal stmt) state return break continue throw) state)))))
; Function to add a value to the state with an associated variable. Throws an error if the variable has not been declared yet
(define evaluateAssign
(lambda (stmt state return break continue throw)
(if (isInState (variableName stmt) state)
(putInState (variableName stmt) (evaluateExpression (variableValue stmt) state return break continue throw) state)
(error 'Undeclared "Using a variable before declaring"))))
; Determines whether a variable is in the state, i.e. if it has been declared and/or assigned
(define isInState
(lambda (name state)
(cond
((null? state) #f)
((null? (variableList state)) #f)
((list? (caar state)) (or (isInState name (car state)) (isInState name (cdr state)))) ; if the state still has layers, go into the layers
((eq? name (car (variableList state))) #t)
(else (isInState name (list (cdr (variableList state)) (cdr (valueList state))))))))
; Puts values into a state, removing any instance of the variable from the list first
(define putInState
(lambda (name val state)
(cond
((isInState name state) (begin (set-box! (getBoxFromState name state) val)) state)
(else (cons (list (cons name (variableList (topLayer state))) (cons (box val) (valueList (topLayer state)))) (cdr state))))))
; Removes all instances of a variable from the state
(define removeFromState
(lambda (name state)
(cond
((null? state) state)
((null? (variableList state)) state)
((list? (caar state)) ( (isInState name (car state)) (isInState name (cdr state)))) ; if the state still has layers, go into the layers
((eq? name (car (variableList state))) (list (cdr (variableList state)) (cdr (valueList state))))
(else (list (cons (car (variableList state)) (variableList (removeFromState name (list (cdr (variableList state)) (cdr (valueList state))))))
(cons (car (valueList state)) (valueList (removeFromState name (list (cdr (variableList state)) (cdr (valueList state)))))))))))
; Gets the value of a variable from the state. If unassigned, throws an error
(define getFromState
(lambda (name state)
(unbox (getBoxFromState name state))))
; Gets the box from the current state
(define getBoxFromState
(lambda (name state)
(cond
((null? state) (error 'badstate "State not found"))
((null? (variableList state)) '())
((and (list? (caar state)) (isInState name (car state)) (getBoxFromState name (car state))))
((and (list? (caar state)) (isInState name (cdr state)) (getBoxFromState name (cdr state))))
((eq? name (car (variableList state))) (car (valueList state)))
(else (getBoxFromState name (list (cdr (variableList state)) (cdr (valueList state))))))))
; Function to determine whether the expression will return a boolean or a number, and returns the literal values, as well as variable values.
; Lots of checks to filter which expression should go to which function
; Mvalue
(define evaluateExpression
(lambda (expr state return break continue throw)
(cond
((eq? 'true expr) 'true)
((eq? 'false expr) 'false)
((number? expr) expr)
((isInState expr state) (getFromState expr state))
((not (list? expr)) (error 'Undeclared "Using a variable before declaring"))
((eq? '== (operator expr)) (evaluateBool expr state return break continue throw))
((eq? '!= (operator expr)) (evaluateBool expr state return break continue throw))
((eq? '< (operator expr)) (evaluateBool expr state return break continue throw))
((eq? '> (operator expr)) (evaluateBool expr state return break continue throw))
((eq? '<= (operator expr)) (evaluateBool expr state return break continue throw))
((eq? '>= (operator expr)) (evaluateBool expr state return break continue throw))
((eq? '&& (operator expr)) (evaluateBool expr state return break continue throw))
((eq? '|| (operator expr)) (evaluateBool expr state return break continue throw))
((eq? '! (operator expr)) (evaluateBool expr state return break continue throw))
((equal? '+ (operator expr)) (evaluateValue expr state return break continue throw))
((equal? '* (operator expr)) (evaluateValue expr state return break continue throw))
((equal? '- (operator expr)) (evaluateValue expr state return break continue throw))
((equal? '/ (operator expr)) (evaluateValue expr state return break continue throw))
((equal? '% (operator expr)) (evaluateValue expr state return break continue throw))
(else (error 'NotExpression "Cannot evaluate the expression")))))
; Function to return true or false given an expression
; Mvalue
(define evaluateBool
(lambda (expr state return break continue throw)
(convertBoolToWord
(cond
((eq? 'true expr) #t)
((eq? 'false expr) #f)
((eq? '== (operator expr)) (eq?
(convertWordToBool (evaluateExpression (operand1 expr) state return break continue throw))
(convertWordToBool (evaluateExpression (operand2 expr) state return break continue throw))))
((eq? '!= (operator expr)) (not (eq?
(convertWordToBool (evaluateExpression (operand1 expr) state return break continue throw))
(convertWordToBool (evaluateExpression (operand2 expr) state return break continue throw)))))
((eq? '< (operator expr)) (< (evaluateExpression (operand1 expr) state return break continue throw)
(evaluateExpression (operand2 expr) state return break continue throw)))
((eq? '> (operator expr)) (> (evaluateExpression (operand1 expr) state return break continue throw)
(evaluateExpression (operand2 expr) state return break continue throw)))
((eq? '<= (operator expr)) (<= (evaluateExpression (operand1 expr) state return break continue throw)
(evaluateExpression (operand2 expr) state return break continue throw)))
((eq? '>= (operator expr)) (>= (evaluateExpression (operand1 expr) state return break continue throw)
(evaluateExpression (operand2 expr) state return break continue throw)))
((eq? '&& (operator expr)) (and (convertWordToBool (evaluateExpression (operand1 expr) state return break continue throw))
(convertWordToBool (evaluateExpression (operand2 expr) state return break continue throw))))
((eq? '|| (operator expr)) (or (convertWordToBool (evaluateExpression (operand1 expr) state return break continue throw))
(convertWordToBool (evaluateExpression (operand2 expr) state return break continue throw))))
((eq? '! (operator expr)) (not (convertWordToBool (evaluateExpression (operand1 expr) state return break continue throw))))
(else (error 'NotBoolean "Cannot evaluate the boolean expression"))))))
; Helper function to assist in conversion between words and boolean values
(define convertBoolToWord
(lambda (bool)
(if bool
'true
'false)))
; Helper function to assist in conversion between boolean values and words
(define convertWordToBool
(lambda (word)
(cond
((eq? 'true word) #t)
((eq? 'false word) #f)
(else word))))
; Function to return the exact value of a function given an expression, returning a numeral value
; Mvalue
(define evaluateValue
(lambda (expr state return break continue throw)
(cond
((number? expr) expr)
((equal? '+ (operator expr)) (+ (evaluateExpression (operand1 expr) state return break continue throw)
(evaluateExpression (operand2 expr) state return break continue throw)))
((equal? '* (operator expr)) (* (evaluateExpression (operand1 expr) state return break continue throw)
(evaluateExpression (operand2 expr) state return break continue throw)))
((and (equal? '- (operator expr)) (null? (existOp2 expr))) (- 0 (evaluateExpression (operand1 expr) state return break continue throw)))
((equal? '- (operator expr)) (- (evaluateExpression (operand1 expr) state return break continue throw)
(evaluateExpression (operand2 expr) state return break continue throw)))
((equal? '/ (operator expr)) (quotient (evaluateExpression (operand1 expr) state return break continue throw)
(evaluateExpression (operand2 expr) state return break continue throw)))
((equal? '% (operator expr)) (remainder (evaluateExpression (operand1 expr) state return break continue throw)
(evaluateExpression (operand2 expr) state return break continue throw)))
(else (error 'badop "Undefined operator")))))
; Evaluate TryCatchFinally
(define evaluateTryCatchBlock
(lambda (stmt state return break continue throw)
(evaluateFinally (finallyBody stmt) (call/cc
(lambda (finish)
(finish (evaluateTryBlock (tryBody stmt) state return break continue (lambda (error_state my_error)
(finish (evaluateCatch (catchBody stmt) error_state my_error return break continue throw)))))))
return break continue throw)))
;evaluate catch block
(define evaluateCatch
(lambda (catchList state error return break continue throw)
(if (null? catchList)
state
(evaluateCatchBlock catchList state error return break continue throw))))
;evaluate finally if it exists
(define evaluateFinally
(lambda (finallyList state return break continue throw)
(if (null? finallyList)
state
(evaluateTryBlock (operand1 finallyList) state return break continue throw))))
;evaluateBlock
(define evaluateBlock
(lambda (stmts state return break continue throw)
(removeStateLayer (evaluateStatements (cdr stmts) (addStateLayer state) return break continue throw))))
; Evaluate the tryblock
(define evaluateTryBlock
(lambda (stmts state return break continue throw)
(removeStateLayer (evaluateStatements stmts (addStateLayer state) return break continue throw))))
; Evaluate the catch block
(define evaluateCatchBlock
(lambda (stmts state error return break continue throw)
(removeStateLayer (evaluateStatements (operand2 stmts) (putInState (exception stmts) error (addStateLayer state)) return break continue throw))))
; Abstraction below
; Defined for use with blocks, removes the 'begin key
(define blockList cdr)
; Defines the initial state
(define initState (list (list '() '())))
; Initial Break
(define initBreak (lambda (s) (error 'badbreak "Break must be in a block")))
; Initial Continuation
(define initCont (lambda (s) (error 'badcont "Continue must be in a loop")))
; Initial Throw
(define initThrow (lambda (s e) (error 'UncaughtException "threw an uncaught exception")))
; if the first item in a list is a variable name
(define variable car)
; Returns the value from the valueList
(define val car)
; returns the operator from an expression
(define operator car)
; returns the first operand from an expression
(define operand1 cadr)
; returns the second operand from an expression
(define operand2 caddr)
;returns the thrid operand
(define operand3 cadddr)
; Determines whether the second operator exists or not
(define existOp2 cddr)
; Gets the if condition of while and if statements
(define ifCond cadr)
; Gets the condition to execute if the condition is true
(define ifTrue caddr)
; Gets the condition to execute if the condition is false
(define ifFalse cadddr)
; Determines whether there is an else statement for an if statement
(define falseCheck cdddr)
; Gets the value to be returned from a return statement
(define returnValue cadr)
; gets the name for a variable, used in assignment and declaration
(define variableName cadr)
; gets the value for a variable, used in assignment
(define variableValue caddr)
; Returns the list of variables from the state
(define variableList car)
; Returns the list of values from the state
(define valueList cadr)
; checks whether there is an assignment after a declaration
(define assignCheck cddr)
; Used in assignment after a delcaration
(define assignVal caddr)
; Used in putInState
(define topLayer car)
;Used for catch
(define exception caadr)
;try-catch abstractions:
(define tryBody cadr)
(define catchBody caddr)
(define finallyBody cadddr)