Skip to content

Commit 9ef7843

Browse files
authored
Add files via upload
1 parent 55f33b2 commit 9ef7843

File tree

1 file changed

+352
-0
lines changed

1 file changed

+352
-0
lines changed

interp (9) (1).ml

+352
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
open Ast
2+
open Ds
3+
4+
(* params * body * super * fields *)
5+
type method_decl = string list*Ast.expr*string*string list
6+
7+
type method_env = (string*method_decl) list
8+
9+
type class_decl = string*string list*method_env
10+
11+
type class_env = ((string*class_decl) list)
12+
13+
(* Global holding the store *)
14+
let g_store = Store.empty_store 20 (NumVal 0)
15+
16+
(* Global holding class declarations *)
17+
let g_class_env : class_env ref = ref []
18+
19+
20+
(* Helper functions for SOOL *)
21+
22+
(*
23+
* Return all visible fields from class c_name
24+
* Note: Should produce an error if the super class does not exist, this is pending
25+
*)
26+
let rec get_fields cs c_name class_decls =
27+
match class_decls with
28+
| [] -> []
29+
| Class (name,super,fields,_methods)::_ when name=c_name ->
30+
fields :: get_fields cs super cs
31+
| Class (_,_,_,_)::cs' -> get_fields cs c_name cs'
32+
33+
(*
34+
* Return all visible methods from class c_name
35+
* Note: Should produce an error if the super class does not exist, this is pending
36+
*)
37+
let rec get_methods cs c_name fss = function
38+
| [] -> []
39+
| Class (name,super,_fields,methods)::_ when name=c_name ->
40+
(List.map (fun (Method(n,pars,body))
41+
-> (n,(pars,body,super,List.flatten fss)))
42+
methods) @ get_methods cs super (List.tl fss) cs
43+
| Class (_,_,_,_)::cs' -> get_methods cs c_name fss cs'
44+
45+
(*
46+
* Initialize contents of g_class_env variable
47+
*)
48+
let initialize_class_env cs =
49+
let rec initialize_class_env' cs = function
50+
| [] -> ()
51+
| Class (name,super,fields,methods)::cs' ->
52+
let fss = fields :: get_fields cs super cs
53+
in let ms = (List.map (fun (Method(n,pars,body))
54+
-> (n,(pars,body,super,List.flatten fss)))
55+
methods) @ get_methods cs super (List.tl fss) cs
56+
in
57+
g_class_env := (name,(super,List.flatten fss,ms))::!g_class_env;
58+
initialize_class_env' cs cs'
59+
in g_class_env := [];
60+
initialize_class_env' cs cs
61+
62+
let lookup_class : string -> class_env -> class_decl ea_result = fun c_name c_env ->
63+
if List.mem_assoc c_name c_env
64+
then return @@ List.assoc c_name c_env
65+
else error "lookup_class: not found"
66+
(* try return @@ List.assoc c_name c_env
67+
with Not_found -> error @@ "lookup_class: class "^c_name^" not found" *)
68+
69+
70+
(* *************************************
71+
*****************************************
72+
****************************************** *)
73+
74+
75+
(* let fields_of_class_decl : class_decl -> string list ea_result = function
76+
| (_, fields, _) -> return fields
77+
| _ -> error "Error: expected class_decl" *)
78+
79+
let rec new_env : string list -> env ea_result = fun x ->
80+
return @@ List.fold_left (fun env str ->
81+
(ExtendEnv(str, RefVal(Store.new_ref g_store (NumVal 0)), env))) EmptyEnv x
82+
83+
84+
let slice fs env =
85+
let rec slice' fs acc env =
86+
match fs, env with
87+
| [],_ -> acc
88+
| id::ids, ExtendEnv(id',ev,tail) when id=id' ->
89+
slice' ids (ExtendEnv(id',ev,acc)) tail
90+
| _,_ -> failwith "slice: ids different or lists have different lengths"
91+
in
92+
return (slice' (List.rev fs) EmptyEnv env)
93+
94+
95+
96+
let lookup_method : string -> string -> class_env ->
97+
method_decl option = fun c_name m_name c_env ->
98+
match run @@ lookup_class c_name c_env with
99+
| Ok (_,_,m_env) -> begin
100+
if List.mem_assoc m_name m_env
101+
then Some(List.assoc m_name m_env)
102+
else None
103+
(* try Some(List.assoc m_name m_env)
104+
with Not_found -> None *)
105+
end
106+
| _ -> None
107+
108+
(* Helper function for records *)
109+
let rec addIds fs evs =
110+
match fs,evs with
111+
| [],[] -> []
112+
| (id,_)::t1, v::t2 -> (id,v):: addIds t1 t2
113+
| _,_ -> failwith "error: lists have different sizes"
114+
115+
let rec apply_method : string -> exp_val -> exp_val list ->
116+
method_decl -> exp_val ea_result = fun m_name self args (pars,body,super,fs) ->
117+
let l = Store.new_ref g_store self
118+
and l_args = List.map (fun ev -> RefVal (Store.new_ref g_store ev)) args
119+
in let l' = Store.new_ref g_store (StringVal super)
120+
in
121+
if List.length args<> List.length pars
122+
then error (m_name ^": args and params have different lengths")
123+
else
124+
obj_of_objectVal self >>= fun (_c_name,env) ->
125+
slice fs env >>+
126+
extend_env_list ("_super"::"_self"::pars) ((RefVal l')
127+
::(RefVal l)::l_args) >>+
128+
eval_expr body
129+
and
130+
apply_proc ev1 ev2 =
131+
match ev1 with
132+
| ProcVal(par,body,en) ->
133+
return en >>+
134+
extend_env par (RefVal (Store.new_ref g_store ev2)) >>+
135+
eval_expr body
136+
| _ -> error "apply_proc: Not a procVal"
137+
and
138+
eval_expr : expr -> exp_val ea_result = fun e ->
139+
match e with
140+
| Int(n) -> return @@ NumVal n
141+
| Var(id) ->
142+
apply_env id >>=
143+
int_of_refVal >>= fun l ->
144+
(match Store.deref g_store l with
145+
| None -> error "Index out of bounds"
146+
| Some ev -> return ev)
147+
| Add(e1,e2) ->
148+
eval_expr e1 >>=
149+
int_of_numVal >>= fun n1 ->
150+
eval_expr e2 >>=
151+
int_of_numVal >>= fun n2 ->
152+
return @@ NumVal (n1+n2)
153+
| Sub(e1,e2) ->
154+
eval_expr e1 >>=
155+
int_of_numVal >>= fun n1 ->
156+
eval_expr e2 >>=
157+
int_of_numVal >>= fun n2 ->
158+
return @@ NumVal (n1-n2)
159+
| Mul(e1,e2) ->
160+
eval_expr e1 >>=
161+
int_of_numVal >>= fun n1 ->
162+
eval_expr e2 >>=
163+
int_of_numVal >>= fun n2 ->
164+
return @@ NumVal (n1*n2)
165+
| Div(e1,e2) ->
166+
eval_expr e1 >>=
167+
int_of_numVal >>= fun n1 ->
168+
eval_expr e2 >>=
169+
int_of_numVal >>= fun n2 ->
170+
if n2==0
171+
then error "Division by zero"
172+
else return @@ NumVal (n1/n2)
173+
| Let(v,def,body) ->
174+
eval_expr def >>= fun ev ->
175+
let l = Store.new_ref g_store ev
176+
in extend_env v (RefVal l) >>+
177+
eval_expr body
178+
| ITE(e1,e2,e3) ->
179+
eval_expr e1 >>=
180+
bool_of_boolVal >>= fun b ->
181+
if b
182+
then eval_expr e2
183+
else eval_expr e3
184+
| IsZero(e) ->
185+
eval_expr e >>=
186+
int_of_numVal >>= fun n ->
187+
return @@ BoolVal (n = 0)
188+
| Pair(e1,e2) ->
189+
eval_expr e1 >>= fun ev1 ->
190+
eval_expr e2 >>= fun ev2 ->
191+
return @@ PairVal(ev1,ev2)
192+
| Fst(e) ->
193+
eval_expr e >>=
194+
pair_of_pairVal >>= fun p ->
195+
return @@ fst p
196+
| Snd(e) ->
197+
eval_expr e >>=
198+
pair_of_pairVal >>= fun p ->
199+
return @@ snd p
200+
| Proc(id,e) ->
201+
lookup_env >>= fun en ->
202+
return (ProcVal(id,e,en))
203+
| App(e1,e2) ->
204+
eval_expr e1 >>= fun v1 ->
205+
eval_expr e2 >>= fun v2 ->
206+
apply_proc v1 v2
207+
| Letrec(id,par,e,target) ->
208+
let l = Store.new_ref g_store UnitVal in
209+
extend_env id (RefVal l) >>+
210+
(lookup_env >>= fun env ->
211+
(let[@warning "-8"] Some _ = Store.set_ref g_store l (ProcVal(par,e,env))
212+
in eval_expr target)
213+
)
214+
(* Mutable references operations *)
215+
| Set(id,e) ->
216+
eval_expr e >>= fun ev ->
217+
apply_env id >>=
218+
int_of_refVal >>= fun l ->
219+
(match Store.set_ref g_store l ev with
220+
| None -> error "Index out of bounds"
221+
| Some _ -> return UnitVal)
222+
| BeginEnd([]) ->
223+
return UnitVal
224+
| BeginEnd(es) ->
225+
sequence (List.map eval_expr es) >>= fun vs ->
226+
return (List.hd (List.rev vs))
227+
(* Record operations *)
228+
| Record(fs) ->
229+
sequence (List.map (fun (_, e) -> eval_expr e) fs) >>= fun evs ->
230+
return (RecordVal (addIds fs evs))
231+
| Proj(e,id) ->
232+
eval_expr e >>=
233+
fields_of_recordVal >>= fun fs ->
234+
(match List.assoc_opt id fs with
235+
| None -> error "not found"
236+
| Some ev -> return ev)
237+
238+
(* SOOL operations *)
239+
| NewObject(c_name,es) ->
240+
sequence (List.map eval_expr es) >>= fun args ->
241+
lookup_class c_name !g_class_env >>= fun (_, fields, methods) ->
242+
new_env fields >>= fun en -> begin
243+
try begin
244+
let self = (ObjectVal(c_name,en)) in
245+
let m = (List.assoc "initialize" methods) in
246+
apply_method "initialize" self args m >>= fun _ ->
247+
return self
248+
end
249+
with Not_found -> return @@ ObjectVal(c_name,en)
250+
end
251+
252+
| Send(e,m_name,es) ->
253+
eval_expr e >>= fun s ->
254+
obj_of_objectVal s >>= fun (c_name, _) ->
255+
sequence (List.map eval_expr es) >>= fun args -> begin
256+
match lookup_method c_name m_name !g_class_env with
257+
| None -> error "Method not found"
258+
| Some m -> apply_method m_name s args m
259+
end
260+
| Self ->
261+
eval_expr (Var "_self")
262+
| Super(m_name,es) ->
263+
sequence (List.map eval_expr es) >>= fun args ->
264+
eval_expr (Var "_super") >>=
265+
string_of_stringVal >>= fun c_name ->
266+
eval_expr (Var "_self") >>= fun self ->begin
267+
match lookup_method c_name m_name !g_class_env with
268+
| None -> error "Method not found"
269+
| Some m -> apply_method m_name self args m
270+
end
271+
272+
(* List operations* *)
273+
| List(es) ->
274+
sequence (List.map eval_expr es) >>= fun args ->
275+
return (ListVal args)
276+
| Cons(e1,e2) ->
277+
eval_expr e1 >>= fun ev ->
278+
eval_expr e2 >>=
279+
list_of_listVal >>= fun l ->
280+
return (ListVal (ev::l))
281+
| Hd(e) ->
282+
eval_expr e >>=
283+
list_of_listVal >>= fun l ->
284+
return (List.hd l)
285+
| Tl(e) ->
286+
eval_expr e >>=
287+
list_of_listVal >>= fun l ->
288+
return (ListVal (List.tl l))
289+
| EmptyPred(e) ->
290+
eval_expr e >>=
291+
list_of_listVal >>= fun l ->
292+
return (BoolVal (l=[]))
293+
(* Debug *)
294+
| Debug(_e) ->
295+
string_of_env >>= fun str_env ->
296+
let str_store = Store.string_of_store string_of_expval g_store
297+
in (print_endline (str_env^"\n"^str_store);
298+
error "Reached breakpoint")
299+
| _ -> error ("eval_expr: Not implemented: "^string_of_expr e)
300+
and
301+
eval_prog : prog -> exp_val ea_result = fun (AProg(cs, e)) ->
302+
initialize_class_env cs; (* Step 1 *)
303+
eval_expr e (* Step 2 *)
304+
305+
306+
(* Parse a string into an ast *)
307+
308+
let parse s =
309+
let lexbuf = Lexing.from_string s in
310+
let ast = Parser.prog Lexer.read lexbuf in
311+
ast
312+
313+
let lexer s =
314+
let lexbuf = Lexing.from_string s
315+
in Lexer.read lexbuf
316+
317+
318+
(* Interpret an expression *)
319+
let interp (s:string) : exp_val result =
320+
let c = s |> parse |> eval_prog
321+
in run c
322+
323+
let read_file (filename:string) : string =
324+
let lines = ref [] in
325+
let chan = open_in filename in
326+
try
327+
while true do
328+
lines := input_line chan :: !lines
329+
done;
330+
"" (* never reaches this line *)
331+
with End_of_file ->
332+
close_in chan;
333+
String.concat "" (List.rev !lines)
334+
335+
(* Interpret an expression read from a file with optional extension .rec *)
336+
let interpf (s:string) : exp_val result =
337+
let s = String.trim s (* remove leading and trailing spaces *)
338+
in let file_name = (* allow rec to be optional *)
339+
match String.index_opt s '.' with None -> s^".sool" | _ -> s
340+
in
341+
interp @@ read_file file_name
342+
343+
let interpp () : exp_val result =
344+
interpf "ex1"
345+
346+
347+
let parsef (s:string) : Ast.prog =
348+
let s = String.trim s (* remove leading and trailing spaces *)
349+
in let file_name = (* allow rec to be optional *)
350+
match String.index_opt s '.' with None -> s^".sool" | _ -> s
351+
in
352+
parse @@ read_file file_name

0 commit comments

Comments
 (0)