From 9510950fce1b66a1f38c316657b88578b702536f Mon Sep 17 00:00:00 2001
From: Youssef <youssef.sellami@student-cs.fr>
Date: Thu, 20 Mar 2025 13:15:29 +0100
Subject: [PATCH] Types : local variables handling

---
 src/cfg_gen.ml   |  4 ++-
 src/elang_gen.ml | 92 ++++++++++++++++++++++++++----------------------
 src/elang_run.ml | 58 ++++++++++--------------------
 3 files changed, 72 insertions(+), 82 deletions(-)

diff --git a/src/cfg_gen.ml b/src/cfg_gen.ml
index 5831632..f347f98 100644
--- a/src/cfg_gen.ml
+++ b/src/cfg_gen.ml
@@ -74,7 +74,9 @@ let rec cfg_node_of_einstr (next: int) (cfg : (int, cfg_node) Hashtbl.t)
     list_map_res cfg_expr_of_eexpr args >>= fun es ->
     Hashtbl.replace cfg next (Ccall (f, es, succ));
     OK (next, next + 1)
-  | Elang.Ideclare (_, s) -> cfg_node_of_einstr next cfg succ (Elang.Iassign (s, Eint 0))
+  | Elang.Ideclare (_, _) -> 
+    Hashtbl.replace cfg next (Cnop succ);
+    OK (next, next + 1)
 
 (* Some nodes may be unreachable after the CFG is entirely generated. The
    [reachable_nodes n cfg] constructs the set of node identifiers that are
diff --git a/src/elang_gen.ml b/src/elang_gen.ml
index d191bbd..63fe655 100644
--- a/src/elang_gen.ml
+++ b/src/elang_gen.ml
@@ -61,9 +61,13 @@ let rec type_expr (typ_var : (string,typ) Hashtbl.t) (typ_fun : (string, typ lis
     (match Hashtbl.find_option typ_var s with
     | Some t when t != Tvoid -> OK t
     | _ -> Error (Format.sprintf "E: Expression %s type is not defined." s))
-  | Ecall (f, _) -> 
+  | Ecall (f, exprs) -> 
     match Hashtbl.find_option typ_fun f with
-    | Some (_, t) when t != Tvoid -> OK t
+    | Some (arg_types, ret_type) when ret_type != Tvoid ->
+        list_map_res (type_expr typ_var typ_fun) exprs >>= fun types ->
+          if types = arg_types
+            then OK ret_type
+            else Error (Format.sprintf "E: Unvalid argument types in function %s calling." f)
     | _ -> Error "E: Function return type is not defined."
 
 let are_compatible (t1 : typ) (t2 : typ) : bool =
@@ -102,56 +106,60 @@ let rec make_eexpr_of_ast (typ_var : (string,typ) Hashtbl.t) (typ_fun : (string,
   | Error msg -> Error (Format.sprintf "In make_eexpr_of_ast %s:\n%s"
                           (string_of_ast a) msg)
 
-let rec make_einstr_of_ast (typ_var : (string,typ) Hashtbl.t) (typ_fun : (string, typ list * typ) Hashtbl.t) (a: tree) : instr res =
+let rec make_einstr_of_ast (typ_var : (string,typ) Hashtbl.t) (typ_fun : (string, typ list * typ) Hashtbl.t) (a: tree) : (instr * (string,typ) Hashtbl.t)res =
   let res =
     match a with
     (* TODO *)
+    (* typ_var a été ajouté à la valeur de retour de cette fonction
+    pour permettre la gestion des variables locales dans les if et while. *)
     | Node(Tassign, [StringLeaf s; e]) -> 
         make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
         type_expr typ_var typ_fun expr >>= fun te ->
         type_expr typ_var typ_fun (Evar s) >>= fun ts ->
         if are_compatible te ts 
-          then OK (Iassign (s, expr))
+          then OK (Iassign (s, expr), typ_var)
           else Error (Format.sprintf "E: Types %s and %s are not compatible." (string_of_typ ts) (string_of_typ te))
-    | Node(Tif, [e; i1; i2]) -> 
-        make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
-        type_expr typ_var typ_fun expr >>= fun te ->
-        make_einstr_of_ast typ_var typ_fun i1 >>= fun instr1 ->
-        make_einstr_of_ast typ_var typ_fun i2 >>= fun instr2 ->
-        OK (Iif (expr, instr1, instr2))
-    | Node(Twhile, [e; i]) -> 
-        make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
-        type_expr typ_var typ_fun expr >>= fun te ->
-        make_einstr_of_ast typ_var typ_fun i >>= fun instr ->
-        OK (Iwhile (expr, instr))
-    | Node(Tblock, i_list) ->
-        list_map_res (make_einstr_of_ast typ_var typ_fun) i_list >>= fun instr_list -> 
-        OK (Iblock instr_list)
-    | Node(Treturn, [e]) -> 
-        make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
-        type_expr typ_var typ_fun expr >>= fun te ->
-        OK (Ireturn expr)        
-    | Node(Tcall, [StringLeaf f; Node(Targs, args)]) -> 
-        list_map_res (make_eexpr_of_ast typ_var typ_fun) args >>= fun exprs ->
-        list_map_res (type_expr typ_var typ_fun) exprs >>= fun types ->
-        (match Hashtbl.find_option typ_fun f with
-        | None -> Error (Format.sprintf "E: Unknown argument types of function %s." f) 
-        | Some (arg_types, ret_type) -> 
-          if types = arg_types
-            then OK (Icall (f, exprs))
-            else Error (Format.sprintf "E: Unvalid argument types in function %s calling." f))
-    | Node (Tdeclare, [TypeLeaf t; StringLeaf s]) ->
-        if t != Tvoid 
-          then 
-            if Hashtbl.mem typ_var s 
+          | Node(Tif, [e; i1; i2]) -> 
+            make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
+            make_einstr_of_ast typ_var typ_fun i1 >>= fun (instr1, new_typ_var) ->
+            make_einstr_of_ast typ_var typ_fun i2 >>= fun (instr2, new_typ_var) ->
+            OK (Iif (expr, instr1, instr2), typ_var)
+        | Node(Twhile, [e; i]) -> 
+            make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
+            make_einstr_of_ast typ_var typ_fun i >>= fun (instr, new_typ_var) ->
+            OK (Iwhile (expr, instr), typ_var)
+        | Node(Tblock, i_list) ->
+            List.fold_left (fun acc i ->
+              acc >>= fun (cur_i_list, cur_typ_var) ->
+              make_einstr_of_ast cur_typ_var typ_fun i >>= fun (instr, new_typ_var) ->
+              OK(cur_i_list@[instr], new_typ_var)) 
+                (OK([], typ_var)) i_list >>= fun (instr_list, new_typ_var) ->
+                  OK(Iblock(instr_list), new_typ_var)
+        | Node(Treturn, [e]) -> 
+            make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
+            OK (Ireturn expr, typ_var)        
+        | Node(Tcall, [StringLeaf f; Node(Targs, args)]) -> 
+            (list_map_res (make_eexpr_of_ast typ_var typ_fun) args >>= fun exprs ->
+            list_map_res (type_expr typ_var typ_fun) exprs >>= fun types ->
+            (match Hashtbl.find_option typ_fun f with
+            | None -> Error (Format.sprintf "E: Unknown argument types of function %s." f) 
+            | Some (arg_types, ret_type) -> 
+              if types = arg_types
+                then OK (Icall (f, exprs), typ_var)
+                else Error (Format.sprintf "E: Unvalid argument types in function %s calling." f)))
+        | Node (Tdeclare, [TypeLeaf t; StringLeaf s]) ->
+            (if t != Tvoid 
               then 
-                Error (Format.sprintf "E: Variable %s already declared." s)
+                (if Hashtbl.mem typ_var s 
+                  then 
+                    Error (Format.sprintf "E: Variable %s already declared." s)
+                  else 
+                    let new_typ_var = Hashtbl.copy typ_var
+                      in Hashtbl.add new_typ_var s t;
+                      OK (Ideclare (t ,s), new_typ_var))
               else 
-                (Hashtbl.add typ_var s t;
-                OK (Ideclare (t ,s)))
-          else 
-            Error (Format.sprintf "E: Can not declare void variable.")
-    | NullLeaf -> OK (Iblock [])
+                Error (Format.sprintf "E: Can not declare void variable."))
+    | NullLeaf -> OK (Iblock [], typ_var)
     | _ -> Error (Printf.sprintf "Unacceptable ast in make_einstr_of_ast %s"
                     (string_of_ast a))
   in
@@ -174,7 +182,7 @@ let make_fundef_of_ast (typ_fun : (string, typ list * typ) Hashtbl.t) (a: tree)
       let typ_var = Hashtbl.of_list fargs
         in let arg_types = List.map (fun (arg, typ) -> typ) fargs
           in Hashtbl.add typ_fun fname (arg_types, t);
-          make_einstr_of_ast typ_var typ_fun fbody >>= fun fbody ->
+          make_einstr_of_ast typ_var typ_fun fbody >>= fun (fbody, _) ->
           OK (fname, {funargs = fargs; funbody = fbody; funvartyp = typ_var; funrettype = t})
   | _ ->
     Error (Printf.sprintf "make_fundef_of_ast: Expected a Tfundef, got %s."
diff --git a/src/elang_run.ml b/src/elang_run.ml
index 92b77fb..ced1357 100644
--- a/src/elang_run.ml
+++ b/src/elang_run.ml
@@ -4,10 +4,6 @@ open Prog
 open Utils
 open Builtins
 
-let remove_local_vars st local_st =
-   let filtered_env = Hashtbl.filteri (fun k v -> if Hashtbl.mem st.env k then (Printf.printf "Not removing %s\n" k; true) else (Printf.printf "removing %s\n" k; false) ) local_st.env
-      in {local_st with env = filtered_env}
-
 let binop_bool_to_int f x y = if f x y then 1 else 0
 
 (* [eval_binop b x y] évalue l'opération binaire [b] sur les arguments [x]
@@ -38,10 +34,7 @@ let eval_unop (u: unop) : int -> int =
 let rec eval_eexpr oc st (ep: eprog) (e : expr) : (int * int state) res =
    match e with
    | Eint i -> OK (i, st)
-   | Evar s -> 
-      (match Hashtbl.find_option st.env s with
-      | Some i -> OK (i, st)
-      | None -> Error "Variable is not defined")
+   | Evar s -> OK (Hashtbl.find st.env s, st)
    | Ebinop (b, ex, ey) -> 
       eval_eexpr oc st ep ex >>= fun (x, st') ->
       eval_eexpr oc st' ep ey >>= fun (y, st'') ->
@@ -58,15 +51,11 @@ let rec eval_eexpr oc st (ep: eprog) (e : expr) : (int * int state) res =
                (OK([], st)) args >>= fun(int_args, st') -> 
             match find_function ep f with
             | OK found_f -> 
-               (match eval_efun oc st' ep found_f f int_args with
-               | Error msg -> Error msg
-               | OK (None, st'') -> Error (Format.sprintf "E: Function %s doesn't have a return value.\n" f)
-               | OK (Some ret, st'') -> OK (ret, st''))
+               eval_efun oc st' ep found_f f int_args >>= fun (ret_opt, st'') -> 
+                  OK (Option.get ret_opt, st'')
             | Error msg -> 
-               (match do_builtin oc st'.mem f int_args with
-               | Error msg -> Error msg
-               | OK None -> Error (Format.sprintf "E: Function %s doesn't have a return value.\n" f)
-               | OK (Some ret) -> OK (ret, st')))
+               do_builtin oc st'.mem f int_args >>= fun (ret_opt) -> 
+                  OK (Option.get ret_opt, st'))
    | Echar c -> OK (Char.code c, st)
          
 (* [eval_einstr oc st ins] évalue l'instruction [ins] en partant de l'état [st].
@@ -84,32 +73,26 @@ let rec eval_eexpr oc st (ep: eprog) (e : expr) : (int * int state) res =
 and eval_einstr oc (st: int state) (ep: eprog) (ins: instr) :
   (int option * int state) res =
    match ins with
-   | Iassign (s, e) ->
-      if Hashtbl.mem st.env s
-         then    
-            (let replace st s v =
-                  let new_env = Hashtbl.copy st.env 
-                     in Hashtbl.replace new_env s v; 
-                        {st with env = new_env} 
-               in match eval_eexpr oc st ep e with
-               | Error msg -> Error msg
-               | OK (v, st') -> OK (None, replace st' s v))
-         else
-            Error (Format.sprintf "E: Variable %s was not declared." s)
+   | Iassign (s, e) ->   
+      (let replace st s v =
+            let new_env = Hashtbl.copy st.env 
+               in Hashtbl.replace new_env s v; 
+                  {st with env = new_env} 
+         in match eval_eexpr oc st ep e with
+         | Error msg -> Error msg
+         | OK (v, st') -> OK (None, replace st' s v))
    | Iif (e, i1, i2) -> 
-      (eval_eexpr oc st ep e >>= fun (v, st') -> 
+      eval_eexpr oc st ep e >>= fun (v, st') -> 
          if v != 0 
-            then eval_einstr oc st' ep i1 >>= fun (r_opt, st'') -> 
-               OK (r_opt, remove_local_vars st' st'') 
-            else eval_einstr oc st' ep i2 >>= fun (r_opt, st'') -> 
-               OK (r_opt, remove_local_vars st' st''))
+            then eval_einstr oc st' ep i1 
+            else eval_einstr oc st' ep i2
    | Iwhile (e, i) -> 
       (eval_eexpr oc st ep e >>= fun (v, st') ->
          if v != 0 
             then eval_einstr oc st' ep i >>= fun (r_opt, next_st) -> 
                match r_opt with 
-               | None -> eval_einstr oc (remove_local_vars st' next_st) ep (Iwhile (e, i))
-               | Some r -> OK (r_opt, remove_local_vars st' next_st)
+               | None -> eval_einstr oc next_st ep (Iwhile (e, i))
+               | Some r -> OK (r_opt, next_st)
             else OK (None, st'))
    | Iblock i_list -> 
       (match i_list with
@@ -136,10 +119,7 @@ and eval_einstr oc (st: int state) (ep: eprog) (ins: instr) :
             | Error msg -> 
                (do_builtin oc st'.mem f int_args >>= fun _ -> 
                   OK (None, st')))
-   | Ideclare (_, s) -> 
-      let new_env = Hashtbl.copy st.env
-         in Hashtbl.add new_env s 0;
-         OK (None, {st with env = new_env})
+   | Ideclare (_, s) -> OK (None, st)
 
 (* [eval_efun oc st f fname vargs] évalue la fonction [f] (dont le nom est
    [fname]) en partant de l'état [st], avec les arguments [vargs].
-- 
GitLab