From 07c73f3bf81298ab0d087ccdc12a6a25945b98e1 Mon Sep 17 00:00:00 2001 From: Erwan Jahier <jahier@imag.fr> Date: Fri, 30 Jan 2009 16:41:30 +0100 Subject: [PATCH] Fix a bug in the UniqueOutput module; I was missing some double definitions. For example, that kind of set of equations didn't trigger any error: x [1 .. 2][0][0].f1 = z ; x=y; nb : it was working if equations were ordered differently tough... --- src/structExpand.ml.save | 490 --------------------------------------- src/uniqueOutput.ml | 35 ++- 2 files changed, 29 insertions(+), 496 deletions(-) delete mode 100644 src/structExpand.ml.save diff --git a/src/structExpand.ml.save b/src/structExpand.ml.save deleted file mode 100644 index 32b62424..00000000 --- a/src/structExpand.ml.save +++ /dev/null @@ -1,490 +0,0 @@ -(** Time-stamp: <modified the 29/01/2009 (at 16:56) by Erwan Jahier> *) - -(* Replace structures by as many variables as necessary. - Since structures can be recursive, it migth be a lot of new variables... - - - - For instance, a variable - v : Toto { f1 : int ; f2 : int ^ 3 ; f3 : t^2 - - where - type t = T { x:int ; y:int } - - will be expanded into - - _v_f1 : int; - _v_f2 : int ^ 3; - _v_f3_1_x : int; - _v_f3_1_y : int; - _v_f3_2_x : int; - _v_f3_3_y : int; - - - nb : if 't' was a type that does not contain any struct type, we would just - have 3 variables. - - - nb : I needed to be quite clever to program that module, but I'm not... - so it's certainly buggy. - *) - -open Lxm -open Eff -open Predef - -type acc = - Eff.val_exp srcflagged list (* assertions *) - * (Eff.eq_info srcflagged) list (* equations *) - * Eff.var_info list (* new local vars *) - - -(********************************************************************************) - - -(* stuff to create fresh var names. - XXX code dupl. with Split.new_var -*) -let new_var str node_env type_eff clock_eff = - let id = Ident.of_string (Name.new_local_var str) in -(* let id = Ident.of_string (Name.new_local_var "h") in *) - let var = - { - var_name_eff = id; - var_nature_eff = SyntaxTreeCore.VarLocal; - var_number_eff = -1; (* this field is used only for i/o. - Should i rather put something sensible there ? *) - var_type_eff = type_eff; - var_clock_eff = clock_eff; - } - in - Hashtbl.add node_env.lenv_vars id var; - var - -(* returns a new var based on [vi] with type [type_eff]. *) -let clone_var str vi node_env type_eff = - let str = (Ident.to_string vi.var_name_eff) ^ str in -(* let id = Ident.of_string (if str.[0] = '_' then str else "_" ^ str) in *) - let id = Ident.of_string (str) in - let var = - { - var_name_eff = id; - var_nature_eff = vi.var_nature_eff; - var_number_eff = vi.var_number_eff; (* this field is useless: to be removed. *) - var_type_eff = type_eff; - var_clock_eff = vi.var_clock_eff; - } - in -(* Hashtbl.add node_env.lenv_vars id var; *) - var - - -let rec (is_a_basic_type : Eff.type_ -> bool) = - function - | Array_type_eff _ | Struct_type_eff _ -> false - | _ -> true - -let soi = string_of_int - - -(* [expand_var "toto" acc type] - adds in [acc] all the strings corresponding to the set of atomic variables - defined by "toto". For instance, if "toto" is of type "s^2" where s is a structure - with two integer fields f1 and f2, expand var returns : - - ["toto_0_f1",int ; "toto_0_f2",int ;"toto_1_f1",int ; "toto_1_f2",int ] @ acc - - This function is used to expand left val_exp expressions. - -*) -let (expand_var : string -> Eff.type_ -> (string * Eff.type_) list) = - fun prefix teff -> - let rec aux prefix acc teff = - match teff with - | Bool_type_eff - | Int_type_eff - | Real_type_eff - | External_type_eff _ - | Enum_type_eff(_) -> (prefix,teff)::acc - - | Any -> assert false (* should not occur *) - | Overload -> assert false (* should not occur *) - - | Array_type_eff(teff_elt,i) -> - let rec unfold acc cpt = - if cpt = i then acc else - let acc = aux (prefix^"_"^(soi cpt)) acc teff_elt in - unfold acc (cpt+1) - in - unfold acc 0 - | Struct_type_eff(l, fl) -> - List.fold_left - (fun acc (fn, (teff_elt,opt)) -> - aux (prefix^"_"^(Ident.to_string fn)) acc teff_elt) - acc - fl - in - List.rev (aux prefix [] teff) - - -(* XXX code dupl!! j'ai deja ecrit ce genre de chose... Bon. *) -let (index_list_of_slice_info : Eff.slice_info -> int list) = - fun si -> - let sign = if si.se_step > 0 then 1 else -1 in - let rec aux acc cpt = - if cpt > si.se_last*sign then acc else - aux (cpt::acc) (cpt + si.se_step) - in - List.rev (aux [] si.se_first) - -(* - for ex, t of type int^3 is expanded into [t_0,t_1,t_2] - -*) - -type 'a var_tree = A of 'a var_tree list | S of (Ident.t * 'a var_tree) list | L of 'a - -let (expand_left : Eff.local_env -> left -> left list) = - fun nenv left -> - (* First step: recursively traverse the left structure to compute the variable - prefix (e.g., "X.f2[4]" -> "X_f2_4") - - But because of slices, things are not so simple... - The algo is the following: - - when we find a left leave, we generate all the possible names - corresponding to that var, in a data structure (a tree) that reflect - the lustre data structure (array and struct) - - Then, struct or array accesses just remove some branches of that tree - - *) - let rec (gen_var_trees : - Lxm.t -> Eff.var_info -> string -> Eff.type_ -> left var_tree) = - fun lxm vi prefix teff -> match teff with - | Bool_type_eff - | Int_type_eff - | Real_type_eff - | External_type_eff _ - | Enum_type_eff(_) - | Any (* should not occur *) - | Overload (* should not occur *) - -> - let new_left = LeftVarEff (clone_var prefix vi nenv teff, lxm) in - L new_left - - | Array_type_eff(teff_elt,i) -> - let rec unfold acc cpt = - if cpt < 0 then acc else - let prefix = prefix ^ "_" ^ (soi cpt) in - let vt = gen_var_trees lxm vi prefix teff_elt in - unfold (vt::acc) (cpt-1) - in - let lvt = unfold [] (i-1) in - A lvt - - | Struct_type_eff(_, fl) -> - S (List.map - (fun (fn, (steff,_)) -> - let prefix = prefix^"_"^(Ident.to_string fn) in - (fn, gen_var_trees lxm vi prefix steff) - ) - fl) - - in - let rec (var_trees_of_left : left -> left var_tree) = - fun left -> - match left with - | LeftVarEff (vi,lxm) -> - gen_var_trees lxm vi (Ident.to_string vi.var_name_eff) vi.var_type_eff - | LeftFieldEff (l,id,t) -> - (match var_trees_of_left l with - | S fl -> (try List.assoc id fl with _ -> assert false) - | A _ | L _ -> assert false - ) - | LeftArrayEff (l,i,t) -> - (match var_trees_of_left l with - | A array -> List.nth array i - | S _ | L _ -> assert false - ) - | LeftSliceEff (l,si,t) -> - (match var_trees_of_left l with - | A array -> - let index_list = index_list_of_slice_info si in - let l = List.map (fun i -> List.nth array i) index_list in - A l - | S _ | L _ -> assert false - ) - in - let rec (flatten_var_tree : 'a var_tree -> 'a list) = - function - | A array -> List.flatten (List.map flatten_var_tree array) - | S fl -> List.flatten (List.map (fun (id,vt) -> flatten_var_tree vt) fl) - | L str -> [str] - in - - - let vt = var_trees_of_left left in - flatten_var_tree vt - -(********************************************************************************) - -let rec (make_new_loc : Eff.local_env -> Eff.id_solver -> Lxm.t -> acc -> - Eff.val_exp -> acc * string list) = - fun nenv id_solver lxm acc ve -> (* build a new loc that will alias ve *) - let teff = List.hd (EvalType.val_exp_eff ve) in - let ceff = List.hd (EvalClock.get_val_exp_eff ve) in - let nv = new_var "v" nenv teff ceff in - let neq = [LeftVarEff(nv,lxm)], ve in - let neq = flagit neq lxm in - let nvl, (asserts,eqs,locs) = expand_var_info nenv id_solver ([],acc) nv in - let acc = (asserts,eqs, List.rev_append nvl locs) in - expand_eq nenv id_solver acc neq, [Ident.to_string nv.var_name_eff] - -and (step1_val_exp : Eff.local_env -> Eff.id_solver -> Lxm.t -> acc -> Eff.val_exp -> - acc * string list) = - fun nenv id_solver lxm acc ve -> - (* First step: recursively traverse the val_exp structure to compute the variable - prefix (e.g., "X.f2[4]" -> "X_f2_4") *) - let rec aux acc ve prefix = - match ve with - | CallByPosEff (by_pos_op, OperEff vel) -> - let lxm = by_pos_op.src in - let by_pos_op = by_pos_op.it in - (match by_pos_op with - | STRUCT_ACCESS (id,teff) -> - (match vel with - | [ve] -> - let prefix = "_" ^ (Ident.of_string id) ^ prefix in - aux acc ve prefix - | _ -> assert false (* should not occur *) - ) - | ARRAY_ACCES (i,teff) -> - (match vel with - | [ve] -> - let prefix = "_" ^ (soi i) ^ prefix in - aux acc ve prefix - | _ -> assert false (* should not occur *) - ) - | ARRAY_SLICE (si,t) -> - (match vel with - | [ve] -> - (* - Non. Je dois, - - generer tous les elements du tableau - - jeter ceux qui ne sont pas dans la tranche - *) -(* let ve_elt, ve_size = *) -(* match EvalType.val_exp_eff ve with *) -(* | Array_type_eff(t,s) -> t,s *) -(* | _ -> assert false *) -(* in *) - let index_list = index_list_of_slice_info si in - let acc,ll = - List.fold_left - (fun (acc, ll) i -> - let prefix = "_" ^ (soi i) ^ prefix in - let (acc, l) = aux acc ve prefix in - acc, l::ll) - (acc,[]) - index_list - in - let l = List.flatten ll in - acc, l - - | _ -> assert false (* should not occur *) - ) - - | IDENT idref -> - let prefix = (Ident.string_of_idref idref) ^ prefix in - acc, [prefix] - - | WITH(_) | HAT(_) | CONCAT | ARRAY(_) - | Predef _ | CALL _ | MERGE _ | CONST _ - | PRE | ARROW | FBY | CURRENT | WHEN _ | TUPLE - -> - (* Create a new loc var to alias such expressions *) - let acc, nv_str_list = make_new_loc nenv id_solver lxm acc ve in - acc, List.map (fun nv_str -> nv_str ^ prefix) nv_str_list - - ) - | CallByNameEff(by_name_op, fl) -> make_new_loc nenv id_solver lxm acc ve - - in - aux acc ve "" - -and (step2_val_exp : string -> Lxm.t -> Eff.type_ -> acc -> acc * Eff.val_exp list) = - fun prefix lxm teff acc -> - (* compute the expansion from the type using the prefix computed in step1 *) - let name_list = expand_var prefix teff in - let vel = List.map - (fun (str, teff) -> - let idref = Ident.idref_of_string str in - CallByPosEff({src=lxm;it=(IDENT idref)}, OperEff []) - ) - name_list - in - acc, vel - -(********************************************************************************) -and (expand_eq : - Eff.local_env -> Eff.id_solver -> acc -> Eff.eq_info srcflagged -> acc) = - fun nenv id_solver acc eqf -> - let { src = lxm_eq ; it = (left_list, ve) } = eqf in - let left_list = List.flatten (List.map (expand_left nenv) left_list) in - let ve,acc = expand_val_exp nenv id_solver acc ve in - let eqf = { src = lxm_eq ; it = (left_list, ve) } in - let (asserts, eqs, locs) = acc in - (asserts, eqf::eqs, locs) - -and expand_val_exp_list n_env id_solver acc vel = - List.fold_left - (fun (vel,acc) ve -> - let ve,acc = expand_val_exp n_env id_solver acc ve in - ve::vel, acc - ) - ([],acc) (List.rev vel) - -and (expand_val_exp: Eff.local_env -> Eff.id_solver -> acc -> val_exp -> - val_exp * acc) = - fun n_env id_solver acc ve -> - match ve with - | CallByPosEff (by_pos_op, OperEff vel) -> - let lxm = by_pos_op.src in - let by_pos_op = by_pos_op.it in - let by_pos_op, acc, vel = match by_pos_op with - | WITH(ve) -> - let ve, acc = expand_val_exp n_env id_solver acc ve in - let vel,acc = expand_val_exp_list n_env id_solver acc vel in - WITH(ve), acc, vel - | HAT(i,ve) -> - let ve, acc = expand_val_exp n_env id_solver acc ve in - let rec unfold cpt = - if cpt = 0 then [] else ve::(unfold (cpt-1)) - in - TUPLE, acc, unfold i - | CONCAT -> - let vel,acc = expand_val_exp_list n_env id_solver acc vel in - TUPLE, acc, vel - | ARRAY(vel) -> - let vel,acc = expand_val_exp_list n_env id_solver acc vel in - TUPLE, acc, vel - - | STRUCT_ACCESS (_,teff) - | ARRAY_ACCES (_,teff) - | ARRAY_SLICE (_,teff) -> - let acc,prefix_list = step1_val_exp n_env id_solver lxm acc ve in - let acc,vel = - List.fold_left - (fun (acc,vel_acc) prefix -> - let acc, vel = step2_val_exp prefix lxm teff acc in - acc, List.append vel vel_acc - ) - (acc,[]) - prefix_list - in - TUPLE, acc, vel - - | IDENT idref -> - let prefix = Ident.string_of_idref idref in - let teff = (id_solver.id2var idref lxm).var_type_eff in - let acc,vel = step2_val_exp prefix lxm teff acc in - TUPLE, acc, vel - - | Predef _ | CALL _ | MERGE _ | CONST _ - | PRE | ARROW | FBY | CURRENT | WHEN _ | TUPLE - -> - let vel,acc = expand_val_exp_list n_env id_solver acc vel in - by_pos_op, acc, vel - in - CallByPosEff(Lxm.flagit by_pos_op lxm, OperEff vel), acc - - | CallByNameEff(by_name_op, fl) -> - let lxm = by_name_op.src in - let vel,acc = List.fold_left - (fun (vel,acc) (id,ve) -> - let ve,acc = expand_val_exp n_env id_solver acc ve in - ve::vel, acc - ) - ([],acc) - fl - in - CallByPosEff({ src = lxm ; it = TUPLE}, OperEff (List.rev vel)), acc - - - -and (expand_val_exp_flag: Eff.local_env -> Eff.id_solver -> acc -> - val_exp srcflagged -> val_exp srcflagged * acc) = - fun n_env id_solver acc { src = lxm ; it = ve } -> - let ve,acc = expand_val_exp n_env id_solver acc ve in - { src = lxm ; it = ve }, acc - -and (expand_assert: - Eff.local_env -> Eff.id_solver -> acc -> val_exp srcflagged -> acc) = - fun n_env id_solver acc ve -> - let (ve, (asserts, eqs, locs)) = expand_val_exp_flag n_env id_solver acc ve in - (ve::asserts, eqs, locs) - -and (expand_var_info: Eff.local_env -> Eff.id_solver -> var_info list * acc -> - var_info -> var_info list * acc) = - fun nenv id_solver (vil, acc) vi -> - match vi.var_type_eff with - | Struct_type_eff (name, fl) -> - List.fold_left - (fun (vil,acc) (fn, (ft,_)) -> - let new_var = clone_var ("_" ^ Ident.to_string fn) vi nenv ft in - let new_vil, new_acc = expand_var_info nenv id_solver (vil,acc) new_var in - if new_vil = new_var::vil then ( - (* [new_var] type is not made of structure *) - assert (is_a_basic_type ft); - Hashtbl.add nenv.lenv_vars new_var.var_name_eff new_var); - new_vil, new_acc - ) - (vil, acc) - fl - - | Array_type_eff(at,size) -> - let rec aux i (vil,acc) = - if i=size then (vil,acc) else - let new_var = clone_var ("_" ^ soi i) vi nenv at in - let new_vil, new_acc = expand_var_info nenv id_solver (vil,acc) new_var in - if new_vil = new_var::vil then ( - (* [new_var] type is not made of structure *) - assert (is_a_basic_type at); - Hashtbl.add nenv.lenv_vars new_var.var_name_eff new_var); - aux (i+1) (new_vil, new_acc) - in - aux 0 (vil,acc) - - | _ -> vi::vil, acc - - -let (node : Eff.local_env -> Eff.id_solver -> Eff.node_exp -> Eff.node_exp) = - fun n_env is n -> - match n.def_eff with - | ExternEff - | AbstractEff -> n - | BodyEff b -> - let loclist = match n.loclist_eff with None -> [] | Some l -> l in - let inlist = n.inlist_eff in - let outlist = n.outlist_eff in - let acc = ([],[],[]) in - let inlist, acc = List.fold_left (expand_var_info n_env is) ([],acc) inlist in - let outlist, acc = List.fold_left (expand_var_info n_env is) ([],acc) outlist in - let loclist, acc = List.fold_left (expand_var_info n_env is) ([],acc) loclist in - let acc = List.fold_left (expand_eq n_env is) acc b.eqs_eff in - let acc = List.fold_left (expand_assert n_env is) acc b.asserts_eff in - let (asserts,neqs, nv) = acc in - let nb = { - eqs_eff = neqs ; - asserts_eff = asserts - } - in - let res = - { n with - inlist_eff = List.rev inlist; - outlist_eff = List.rev outlist; - loclist_eff = Some (List.rev_append loclist nv); - def_eff = BodyEff nb - } - in - res - diff --git a/src/uniqueOutput.ml b/src/uniqueOutput.ml index bb62da81..6f665dd2 100644 --- a/src/uniqueOutput.ml +++ b/src/uniqueOutput.ml @@ -61,7 +61,7 @@ let id2str = Ident.to_string let int2str = string_of_int (* Returns the list of undefined variables *) -let (vds_to_string : Eff.var_info -> var_def_state -> string list) = +let (vds_to_undefined_vars : string -> var_def_state -> string list) = fun v vds -> let rec aux vds v acc = match vds with | VDS_def -> acc @@ -72,7 +72,21 @@ let (vds_to_string : Eff.var_info -> var_def_state -> string list) = (Array.fold_left (fun (acc,i) vds -> aux vds (v^"["^(int2str i) ^"]") acc, i+1) (acc,0) a) in - aux vds (id2str v.var_name_eff) [] + aux vds v [] + +(* Returns the list of defined variables *) +let (vds_to_defined_vars : string -> var_def_state -> string list) = + fun v vds -> + let rec aux vds v acc = match vds with + | VDS_def -> v::acc + | VDS_undef -> acc + | VDS_struct(fl) -> + List.fold_left (fun acc (id,vds) -> aux vds (v^"."^(id2str id)) acc) acc fl + | VDS_array(a) -> fst + (Array.fold_left + (fun (acc,i) vds -> aux vds (v^"["^(int2str i) ^"]") acc, i+1) (acc,0) a) + in + aux vds v [] (*********************************************************************************) (** This is main function: it computes a new [var_def_state] from an @@ -82,11 +96,20 @@ let (update_var_def_state : var_def_state -> filtered_left -> var_def_state) = let rec (update_vds : string -> var_def_state -> filter list -> var_def_state) = fun v vds filters -> if vds = VDS_def then - let msg = "\n*** Variable " ^ v ^ " is defined twice." in + let msg = "\n*** Variable " ^ v ^ " is already defined." in raise (Compile_error(lxm, msg)) else match filters with - | [] -> VDS_def + | [] -> + let already_def_vars = vds_to_defined_vars v vds in + if already_def_vars <> [] then + let msg = + "\n*** Variable " ^ v ^ " is already partly defined (" ^ + (String.concat "," (already_def_vars)) ^ ")." + in + raise (Compile_error(lxm, msg)) + else + VDS_def | Slice(i,j,k,te)::tail -> update_slice v i j k tail (match vds with | VDS_array(a) -> a @@ -182,11 +205,11 @@ let (check : Eff.node_exp -> Lxm.t -> unit) = let (check_one_var : Lxm.t -> Eff.var_info -> Eff.left list -> unit) = fun lxm v lel -> let ell = List.map left_eff_to_filtered_left lel in - match List.fold_left update_var_def_state VDS_undef ell with + match List.fold_left update_var_def_state VDS_undef (List.rev ell) with | VDS_def -> () | vds -> let msg = "\n*** Undefined variable(s): " ^ - (String.concat ", " (vds_to_string v vds)) + (String.concat ", " (vds_to_undefined_vars (id2str v.var_name_eff) vds)) in raise (Compile_error(lxm, msg)) in -- GitLab