-
Erwan Jahier authored
ps : the new test pass because the -ei is also buggy (cf a forthcoming change).
Erwan Jahier authoredps : the new test pass because the -ei is also buggy (cf a forthcoming change).
socExec.ml 16.92 KiB
(* Time-stamp: <modified the 06/06/2013 (at 10:29) by Erwan Jahier> *)
open Soc
open Data
open SocExecValue
let dbg = (Verbose.get_flag "exec")
let (assign_expr : ctx -> var_expr -> var_expr -> ctx) =
fun ctx ve_in ve_out -> (* ve_out := ve_in (in ctx) *)
Verbose.exe ~flag:dbg
(fun () -> print_string ("Assigning "^(SocUtils.string_of_filter ve_out) ^
" to " ^(SocUtils.string_of_filter ve_in) ^ "\n"); flush stdout);
{ ctx with s =
let v = SocExecValue.get_value ctx ve_in in
sadd_partial ctx.s ve_out ctx.cpath v
}
(* [array_index i v] returns the var_expr v[i] *)
let (array_index : int -> var -> var_expr) =
fun i (vn,vt) ->
let vt_elt =
match vt with
| Array(vt_elt,_) -> vt_elt
| _ -> assert false
in
Index(Var(vn,vt),i,vt_elt)
let rec (soc_step : Soc.step_method -> Soc.tbl -> Soc.t -> SocExecValue.ctx
-> SocExecValue.ctx) =
fun step soc_tbl soc ctx ->
let soc_name,_,_ = soc.key in
match step.impl with
| Predef -> (
try
let ctx = SocExecEvalPredef.get soc.key ctx in
ctx
with Not_found -> (* Not a predef op *) print_string (
"*** internal error in "^soc_name^". Is it defined in SocExecEvalPredef?\n");
flush stdout; assert false
)
| Gaol(vl,gaol) -> List.fold_left (do_gao step.lxm soc_tbl) ctx gaol
| Boolred(i,j,k) -> (
(* XXX mettre ce code dans socPredef ? (ou socMetaopPredef)*)
let inputs, outputs = soc.profile in
let b_array = (List.hd inputs) in
let cpt = ref 0 in
for i = 0 to k-1 do
let a_i = array_index i b_array in
let v = SocExecValue.get_value ctx a_i in
if v = B true then incr cpt;
done;
let res = B (!cpt >= i && !cpt <= j) in
let res_var = fst (List.hd outputs) in
let s = sadd ctx.s (res_var::ctx.cpath) res in
{ ctx with s = s }
)
| Condact(node_sk, dft_cst) -> (
let clk = SocExecValue.get_value ctx (Var ("i0",Bool)) in
let vel_in, vel_out = soc.profile in
let vel_in = List.map (fun x -> Var x) (List.tl vel_in) in
let vel_out = List.map (fun x -> Var x) vel_out in
let node_soc = SocUtils.find step.lxm node_sk soc_tbl in
let inst_name =
match soc.instances with
| [] -> let (proc_name,_,_) = node_soc.key in proc_name
| [inst] -> fst inst
| _ -> assert false
in
let path_saved = ctx.cpath in
let ctx = { ctx with cpath=inst_name::ctx.cpath } in
let ctx =
if clk = B true then
let node_step = match node_soc.step with [step] -> step | _ -> assert false in
let ctx = do_step inst_name node_step ctx soc_tbl node_soc vel_in vel_out in
let ctx = { ctx with s = sadd ctx.s ("$first_step"::ctx.cpath) (B false) } in
{ ctx with cpath=path_saved }
else
let first_step = Var ("$first_step",Bool) in
let v = get_value ctx first_step in
if v <> U then
(* We are not on the first step of node_soc; hence we do nothing
and the output will keep their previous value. *)
{ ctx with cpath=path_saved }
else
(* We are on the first step of node_soc;
- we assign the output var to the default values *)
let ctx = { ctx with cpath=path_saved } in
List.fold_left2 assign_expr ctx dft_cst vel_out
in
ctx
)
| Iterator(iter, node_sk, n) ->
let node_soc = SocUtils.find step.lxm node_sk soc_tbl in
let node_step = match node_soc.step with [step] -> step | _ -> assert false in
let iter_inputs,iter_outputs = soc.profile in
let rctx = ref ctx in
let (proc_name,_,_) = node_soc.key in
let inst_name =
match soc.instances with
| [] -> Array.make n proc_name
| _ -> Array.of_list (List.map fst soc.instances)
in
for i = 0 to n-1 do
rctx := { !rctx with cpath = inst_name.(i)::ctx.cpath };
let vel_in, vel_out =
match iter with
| "map" -> (List.map (array_index i) iter_inputs,
List.map (array_index i) iter_outputs)
| "fold" | "red" | "fill" | "fillred" ->
let a_in = Var (List.hd iter_inputs) in
( a_in::(List.map (array_index i) (List.tl iter_inputs)),
a_in::(List.map (array_index i) (List.tl iter_outputs)))
| _ -> assert false (* should not occur *)
in
rctx := do_step inst_name.(i) node_step !rctx soc_tbl node_soc vel_in vel_out;
rctx := { !rctx with cpath = List.tl !rctx.cpath };
done;
if iter <> "map" then (
let a_in = Var (List.hd iter_inputs) in
let a_out = Var (List.hd iter_outputs) in
rctx := assign_expr !rctx a_in a_out); (* a_out=a_n *)
!rctx;
and (do_gao : Lxm.t -> Soc.tbl -> SocExecValue.ctx -> gao -> SocExecValue.ctx) =
fun lxm soc_tbl ctx gao ->
match gao with
| Case(id, id_gao_l) -> (
try
let id_val = get_enum id ctx in
let gaol = List.assoc id_val id_gao_l in
let ctx = List.fold_left (do_gao lxm soc_tbl) ctx gaol in
ctx
with Not_found -> ctx
)
| Call(vel_out, Assign, vel_in) -> (
let ctx =
try List.fold_left2 assign_expr ctx vel_in vel_out
with _ -> assert false
in
ctx
)
| Call(vel_out, Procedure sk, vel_in) -> (
let (proc_name,_,_) = sk in
let path_saved = ctx.cpath in
let ctx = { ctx with cpath = proc_name::ctx.cpath } in
let soc = SocUtils.find lxm sk soc_tbl in
let step = match soc.step with [step] -> step | _ -> assert false in
let ctx = do_step proc_name step ctx soc_tbl soc vel_in vel_out in
{ ctx with cpath = path_saved }
)
| Call(vel_out, Method((inst_name,sk),step_name), vel_in) -> (
let path_saved = ctx.cpath in
let ctx = { ctx with cpath = inst_name::ctx.cpath } in
let soc = SocUtils.find lxm sk soc_tbl in
let step = try List.find (fun sm -> sm.name = step_name) soc.step
with Not_found -> assert false
in
let ctx = do_step inst_name step ctx soc_tbl soc vel_in vel_out in
let ctx = { s = sadd ctx.s ("$first_step"::ctx.cpath) (B false);
cpath = path_saved }
in
ctx
)
and (do_step : Ident.t -> step_method -> SocExecValue.ctx -> Soc.tbl -> Soc.t ->
var_expr list -> var_expr list -> SocExecValue.ctx) =
fun name step ctx soc_tbl soc vel_in vel_out ->
let soc_in_vars, soc_out_vars = soc.profile in
let step_in_vars = filter_params soc soc_in_vars step.idx_ins in
let step_out_vars = filter_params soc soc_out_vars step.idx_outs in
let new_s = substitute_args_and_params vel_in step_in_vars ctx in
let ctx = soc_step step soc_tbl soc { ctx with s=new_s } in
let s_out = substitute_params_and_args step_out_vars vel_out ctx in
{ ctx with s = s_out }
(* get the step params from its soc params *)
and (filter_params : Soc.t -> Soc.var list -> int list -> Soc.var list) =
fun soc el il ->
let local_nth i l =
try List.nth l i
with _ ->
print_string (
"\n*** Cannot get the " ^ (string_of_int (i+1)) ^
"the element of a list of size " ^ (string_of_int (List.length l))^"\n");
flush stdout;
assert false
in
let res = List.map (fun i -> local_nth i el) il in
res
(* exported *)
let rec (expand_profile : bool -> Soc.var list -> Soc.var list) =
fun enum_flag vl ->
let res = List.flatten (List.map (expand_var enum_flag) vl) in
(* fix point. now useless ? *)
if List.length res = List.length vl then res else
expand_profile enum_flag res
and expand_var enum_flag var = match var with
| (vn,(Bool| Int | Real)) -> [var]
| (vn,Enum(n,l)) -> if enum_flag then [vn,Int] else [var]
| (vn,Array(vt,i)) ->
let res = ref [] in
for k=i-1 downto 0 do
res := (vn^"_"^(string_of_int k),vt) :: !res;
done;
(expand_profile enum_flag !res)
| (vn,Struct(name,fl)) -> expand_profile enum_flag (List.map (fun (fn,t) -> vn^"_"^fn,t ) fl)
| (vn,Extern id) ->
print_string "Extern node not yet supported, sorry\n"; flush stdout;
assert false (* finish me! *)
| (vn,Alpha _) -> assert false (* should not occur *)
let (int_to_enum : Data.v -> Soc.ident list -> Data.v) =
fun v el ->
match v with
| I i -> (try E (List.nth el i,i) with _ ->
failwith ("Enum out of the range [0,"^(string_of_int (List.length el))^"]"))
| _ -> assert false (* should not occur *)
let rec (expand_subst: Data.subst -> Data.subst list) =
fun s ->
let rec aux acc (n,v) =
match v with
| U | I _ | F _ | B _ -> (n,v)::acc
| E(_e,i) -> (n,I i)::acc
| S fl ->
let f (fn,fv) = n^"_"^fn, fv in
let fl = List.map f fl in
List.fold_left aux acc fl
| A a ->
let res = ref acc in
for i=0 to (Array.length a)-1 do
let n_i = n^"_"^(string_of_int i) in
res := aux !res (n_i, a.(i));
done;
!res
in
aux [] s
(* A local shortcut to ease the profile def *)
type sl = Data.subst list
(* Reconstruct the flattenned data *)
let (unexpand_profile : sl -> Soc.var list -> sl) =
fun sl vl ->
let rec (aux : sl -> sl -> Soc.var list -> sl * sl)=
fun sl_done sl_todo vl ->
(* Returns the (accumulated) result and the unused subst
(which should be empty at the top-level call) *)
match sl_todo, vl with
| _,[] -> sl_done, sl_todo
| s::sl, (_, (Bool| Int | Real))::vl -> aux (s::sl_done) sl vl
| (id,v)::sl, (_,Enum(n,el))::vl ->
let s = (id, int_to_enum v el) in
aux (s::sl_done) sl vl
| _, (vn, Array(vt,i))::vl -> (
let sl_todo_ref = ref sl_todo in
let sl_done_ref = ref [] in
let a_fake_value = I 42 in
let res = Array.make i a_fake_value in
for k=0 to i-1 do
let (vk_l:Soc.var list) = [("fake_name",vt)] in
let (sl_done_v, sl_todo_v) = aux !sl_done_ref !sl_todo_ref vk_l in
sl_todo_ref:=sl_todo_v;
sl_done_ref:=sl_done_v;
Array.set res k (snd (List.hd !sl_done_ref));
done;
let sl_done = (vn, A res)::sl_done in
aux sl_done !sl_todo_ref vl
)
| _, (vn,Struct(sn,fl))::vl ->
let sl_todo, fl = List.fold_left aux_field (sl_todo,[]) fl in
let sl_done = (vn, S fl)::sl_done in
aux sl_done sl_todo vl
| _, (vn,Extern id)::_ -> assert false (* finish me! *)
| _, (vn,Alpha _ )::_ -> assert false (* should not occur *)
| [],_::_ -> assert false (* should not occur *)
and (aux_field : sl * (ident * Data.v) list -> ident * Data.t -> sl * (ident * Data.v) list ) =
fun (sl_todo, fl) (fn, t) ->
let new_sl_done, sl_todo = aux [] sl_todo [fn,t] in
let (_,v) = List.hd new_sl_done in
sl_todo, (fn,v)::fl
in
let res, remaining = aux [] sl vl in
assert (remaining=[]);
res
(* [add_data_subst vtnl data_s s] add the data_s to s; *)
let (add_data_subst : var list -> Data.subst list -> SocExecValue.substs -> SocExecValue.substs) =
fun vntl_i s ctx_s ->
let s = unexpand_profile s vntl_i in
List.fold_left (fun acc (id,v) -> sadd acc [id] v) ctx_s s
let (read_soc_input : var list -> Data.vntl -> out_channel -> substs -> substs) =
fun vntl_i exp_vntl_i_str oc ctx_s ->
let s:Data.subst list = Rif_base.read stdin (Some oc) exp_vntl_i_str in
add_data_subst vntl_i s ctx_s
let rec (loop_step : Lv6MainArgs.t -> Soc.tbl -> Soc.var list -> Data.vntl -> Data.vntl
-> Soc.t -> SocExecValue.ctx -> int -> out_channel -> unit) =
fun opt soc_tbl vntl_i exp_vntl_i_str exp_vntl_o_str soc ctx step_nb oc ->
Rif_base.write oc ("\n#step " ^ (string_of_int step_nb)^"\n");
let ctx = { ctx with s = read_soc_input vntl_i exp_vntl_i_str oc ctx.s } in
let step = match soc.step with [step] -> step | _ -> assert false in
let ctx = soc_step step soc_tbl soc ctx in
let ctx = { ctx with s = sadd ctx.s ("$first_step"::ctx.cpath) (B false)} in
let s = SocExecValue.filter_top_subst ctx.s in
let s = List.flatten(List.map expand_subst s) in
let f2s = SocUtils.my_string_of_float_precision opt.Lv6MainArgs.precision in
Rif_base.write oc " #outs ";
Rif_base.write_outputs oc f2s exp_vntl_o_str s;
Rif_base.flush oc;
Verbose.exe ~flag:dbg (fun () -> dump_substs ctx.s; flush stdout);
loop_step opt soc_tbl vntl_i exp_vntl_i_str exp_vntl_o_str soc ctx (step_nb+1) oc
let (f : Lv6MainArgs.t -> Soc.tbl -> Soc.key -> unit) =
fun opt soc_tbl sk ->
let soc = try SocMap.find sk soc_tbl with Not_found -> assert false in
let ctx = SocExecValue.create_ctx soc_tbl soc in
let vntl_of_profile = List.map (fun (x,t) -> x,SocUtils.string_of_type_ref t) in
let exp_vntl_i = expand_profile true (fst soc.profile) in
let exp_vntl_o = expand_profile true (snd soc.profile) in
let exp_vntl_i_str = vntl_of_profile exp_vntl_i in
let exp_vntl_o_str = vntl_of_profile exp_vntl_o in
let oc =
if opt.Lv6MainArgs.outfile = "" then stdout else
let rif_file =
try (Filename.chop_extension opt.Lv6MainArgs.outfile) ^ ".rif"
with _ -> opt.Lv6MainArgs.outfile ^ ".rif"
in
open_out rif_file
in
Lv6util.dump_entete oc;
Rif_base.write_interface oc exp_vntl_i_str exp_vntl_o_str None None;
Rif_base.flush oc;
try loop_step opt soc_tbl (fst soc.profile) exp_vntl_i_str exp_vntl_o_str soc ctx 1 oc
with Rif_base.Bye ->
close_out oc
(**************************************************************************************)
(* exported *)
let rec (do_step : Soc.tbl -> Soc.t -> SocExecValue.ctx -> SocExecValue.ctx) =
fun soc_tbl soc ctx ->
let step = match soc.step with [step] -> step | _ -> assert false in
let ctx = soc_step step soc_tbl soc ctx in
let ctx = { ctx with s = sadd ctx.s ("$first_step"::ctx.cpath) (B false) } in
ctx
(* exported *)
let rec (do_step_dbg : Soc.tbl -> Soc.t -> Event.ctx -> SocExecValue.ctx ->
(SocExecValue.ctx -> Event.t) -> Event.t) =
fun soc_tbl soc ectx ctx cont ->
(* XXX un peu exegéré de mettre tout ?*)
(* let (datal:Data.subst list) = SocExecValue.substs_to_data_subst ctx.s in *)
let (datal:Data.subst list) = SocExecValue.filter_top_subst ctx.s in
let (soc_name,_,_) = soc.key in
let ectx = {
ectx with
Event.ctx_name = soc_name;
Event.ctx_depth = ectx.Event.ctx_depth+1;
Event.ctx_data = datal;
Event.ctx_inputs = List.map fst (fst soc.profile);
Event.ctx_outputs = List.map fst (snd soc.profile);
}
in
let cont2 ctx =
let lazy_si = (fun () ->
let soc_step = match soc.step with [step] -> step | _ -> assert false in
let lxm = soc_step.lxm in
[{
Event.str = Lxm.str lxm;
Event.file = Lxm.file lxm ;
Event.line = Lxm.line lxm,Lxm.line lxm;
Event.char = Lxm.cstart lxm, Lxm.cend lxm;
(* Event.stack = if tl=[] then None else Some (to_src_info tl); *)
Event.stack = None; (* XXX stub *)
}])
in
let enb = Event.incr_nb (); Event.get_nb () in
{
Event.step = ectx.Event.ctx_step;
Event.nb = enb;
Event.depth = ectx.Event.ctx_depth;
Event.kind =
Event.Node {
Event.lang = "lustre";
Event.name = soc_name;
Event.port = Event.Exit ("",Expr.True,lazy_si);
Event.inputs = ectx.Event.ctx_inputs;
Event.outputs = ectx.Event.ctx_outputs;
};
Event.data = ectx.Event.ctx_data;
Event.other = "";
Event.next = (fun () -> Event.event_nb := enb; cont ctx);
Event.terminate = ectx.Event.ctx_terminate;
}
in
{
Event.step = ectx.Event.ctx_step;
Event.nb = (Event.incr_nb (); Event.get_nb ());
Event.depth = ectx.Event.ctx_depth;
Event.kind =
Event.Node {
Event.lang = "lustre";
Event.name = soc_name;
Event.port = Event.Call;
Event.inputs = ectx.Event.ctx_inputs;
Event.outputs = ectx.Event.ctx_outputs;
};
Event.data = ectx.Event.ctx_data;
Event.other = "";
Event.next = (fun () ->
let step = match soc.step with [step] -> step | _ -> assert false in
let ctx = soc_step step soc_tbl soc ctx in
let ctx = { ctx with s = sadd ctx.s ("$first_step"::ctx.cpath) (B false) } in
cont2 ctx
);
Event.terminate = ectx.Event.ctx_terminate;
}