Skip to content
Snippets Groups Projects
l2lWhenOnId.ml 7.15 KiB
Newer Older
(** Time-stamp: <modified the 07/06/2016 (at 13:30) by Erwan Jahier> *)

open Lxm
open Lic
open AstPredef
 
let dbg =  (Lv6Verbose.get_flag "woi")

(********************************************************************************)
(** The functions below accumulate 
   (1) the assertions
   (2) the new equations 
   (3) the fresh variables
*)

type clock_tbl = ((Lv6Id.long * Lv6Id.t), Lic.var_info) Hashtbl.t (* Map.t ? *)
type acc = 
      Lic.var_info list           (* new local vars *)
    * Lic.eq_info srcflagged list (* equations *)
    * Lic.val_exp srcflagged list (* assertions *)
    * clock_tbl


let rec update_clock : clock_tbl -> clock -> clock = 
  fun clk_tbl clk -> 
  match clk with
  | BaseLic | ClockVar _ -> clk
  | On((cc,cv,ct),sclk) ->
     let sclk = update_clock clk_tbl sclk in
     try 
       let nv = Hashtbl.find clk_tbl (cc,cv) in
       On((("Lustre","true"),nv.var_name_eff, Bool_type_eff), sclk)
     with Not_found -> 
       On((cc,cv,ct),sclk)

 let update_var_info : clock_tbl -> var_info -> var_info = 
   fun tbl vi -> 
    let (id, clk) = vi.var_clock_eff in
    { vi with var_clock_eff = id, update_clock tbl clk }
           
 let rec update_left : clock_tbl -> left -> left = 
   fun tbl l -> 
   match l with
   | LeftVarLic(vi,lxm) -> LeftVarLic(update_var_info tbl vi,lxm)
   | LeftFieldLic(l,id,t) -> LeftFieldLic(update_left tbl l,id,t)
   | LeftArrayLic(l,i,t) -> LeftArrayLic(update_left tbl l,i,t)
   | LeftSliceLic(l,si,t) -> LeftSliceLic(update_left tbl l,si,t)


 let new_var (cc,cv) type_eff clock_eff clk_tbl = 
   try Hashtbl.find clk_tbl (cc,cv) 
   with Not_found -> 
     let str = (snd cc) ^ "_" ^ cv in
     let id = Lv6Id.of_string (FreshName.local_var str) in 
     let var =
       { 
         var_name_eff   = id;
         var_nature_eff = AstCore.VarLocal;
         var_number_eff = -1;
         var_type_eff   = type_eff;
         var_clock_eff  = id,clock_eff;
       } 
     in
     Hashtbl.add clk_tbl (cc,cv) var;
     var



(********************************************************************************)
(* The one that perform the real work, namely:

- invent a fresh var name NV
- replace 'when Idle(st)' by 'when NV'
- generate the equation defining NV (NV=(Idle=st);)
*)

let (gen_ident : Lxm.t -> Lv6Id.long -> Lv6Id.t -> type_ -> Lic.clock -> acc -> 
                 Lic.by_pos_op srcflagged * acc ) =
  fun lxm cc cv ct clk (vl,eql,al,tbl) -> (* On(Idle, st, enum_t)  *)
  let nv = new_var (cc,cv) Bool_type_eff clk tbl in

  let ve1 = {
    ve_typ = [ct];
    ve_clk = [clk]; 
    ve_core = CallByPosLic(Lxm.flagit (Lic.CONST_REF cc) lxm,[])		
  }
  in
  let ve2 = {
    ve_typ = [ct];
    ve_clk = [clk]; 
    ve_core = CallByPosLic(Lxm.flagit (Lic.VAR_REF cv) lxm,[])		
  }
  in 
  let ve = (* Idle=st *){
    ve_typ = [Bool_type_eff];
    ve_clk = [clk]; 
    ve_core = 
      CallByPosLic({it=Lic.PREDEF_CALL({it=(("Lustre","eq"),[]);src=lxm});src=lxm}, 
                   [ve1;ve2])
  }
  in
  let new_eq = (* NV=(Idle=st) *) {src=lxm;it=[LeftVarLic (nv, lxm)], ve} in
  let true_cc = "Lustre","true" in
  let op = WHEN (On((true_cc, nv.var_name_eff, Bool_type_eff),clk)) in
  Lxm.flagit op lxm,  (nv::vl,new_eq::eql,al,tbl)

(********************************************************************************)
(* All the remaining are admnistrative functions *)
   
let rec (do_eq : LicPrg.t -> Lic.eq_info srcflagged -> acc -> acc) =
  fun licprg { src = lxm_eq ; it = (left_list, ve) } acc -> 
    let ve, (nv,neqs,nass,tbl) = do_val_exp licprg ve acc in
    let left_list = List.map (update_left tbl) left_list in
    nv, { src = lxm_eq ; it = (left_list, ve) }::neqs, nass,tbl
      
and (do_val_exp: LicPrg.t -> val_exp -> acc -> val_exp * acc) =
  fun licprg ve acc ->
    let ve_core, acc =
      match ve.ve_core with
        | Merge(ce,cl) -> (
          let cl,acc = 
            List.fold_left
              (fun (ncl,acc) (c, ve) -> 
                let ve, acc = do_val_exp licprg ve acc in
          in
          Merge(ce,cl),acc
        )
        | CallByNameLic(op, fl) -> (
          let fl,acc = List.fold_left
            (fun (nfl,acc) (id,ve) -> 
              let nf, acc = do_val_exp licprg ve acc in
              ((id,nf)::nfl), acc
            ) 
            ([],acc) 
            fl 
          in
          CallByNameLic(op, fl), acc
        )
        | CallByPosLic (op, vel) -> (
          let vel, acc = List.fold_left
            (fun (vel,acc) ve -> 
              let ve, acc = do_val_exp licprg ve acc in
              (ve::vel), acc
            )
            ([],acc) 
            (List.rev vel)
          in          
	       match op.it with
          | WHEN (On((_,_,Bool_type_eff),_)) -> (* nothing to do in this case *)
             CallByPosLic(op, vel), acc
          | WHEN (On((cc,cv,ct),clk)) -> 
             let op, acc = gen_ident op.src cc cv ct clk acc in
             CallByPosLic(op, vel), acc
          | _ -> CallByPosLic(op, vel), acc
	     )
    in 
    { ve with ve_core = ve_core },acc

and (do_val_exp_flag:  LicPrg.t -> val_exp srcflagged -> acc -> 
     val_exp srcflagged * acc) =
  fun licprg ve_f acc -> 
    let ve, acc = do_val_exp licprg ve_f.it acc in
    { ve_f with it = ve }, acc

and (do_node : LicPrg.t -> Lic.node_exp -> Lic.node_exp) =
  fun licprg n -> 
  let tbl = Hashtbl.create 0 in
  let aux licprg n =
    match n.def_eff with
      | ExternLic | MetaOpLic | AbstractLic _ -> n
      | BodyLic b ->
        let acc = List.fold_left 
          (fun acc eq -> do_eq licprg eq acc) 
          (List.rev b.eqs_eff)
        in
        let acc = List.fold_left 
          (fun acc ve -> 
            let ve,(nv,neq,nass,tbl) = do_val_exp_flag licprg ve acc in
            (nv,neq,ve::nass,tbl)
        let (nv,neqs,nass,tbl) = acc in
        let nlocs = match n.loclist_eff with
          | None -> nv (* SNO, but eats no bread *)
          | Some v -> List.rev_append nv v
        in
        let update_var_info = update_var_info tbl in
        { n with 
          def_eff = BodyLic  { 
            eqs_eff = neqs; 
            asserts_eff = nass;
          };
          inlist_eff  = List.map update_var_info n.inlist_eff;
          outlist_eff = List.map update_var_info n.outlist_eff;
          loclist_eff = Some (List.map update_var_info nlocs);
  in
  let n = aux licprg n in
  let n = aux licprg n in (* do it twice to make sure they are all substituted *)
  n

(* exported *)
let rec (doit : LicPrg.t -> LicPrg.t) =
  fun inprg -> 
    let outprg = LicPrg.empty in
  (** types and constants do not change *)
    let outprg = LicPrg.fold_types  LicPrg.add_type  inprg outprg in
    let outprg = LicPrg.fold_consts LicPrg.add_const inprg outprg in
  (** transform nodes *)
    let rec (doit_node : Lic.node_key -> Lic.node_exp -> LicPrg.t -> LicPrg.t) = 
      fun nk ne outprg -> 
        Lv6Verbose.exe ~flag:dbg (fun() -> Printf.printf "#DBG: L2lWhenOnId '%s'\n"
            (Lic.string_of_node_key nk));
        let ne = do_node inprg ne in
        LicPrg.add_node nk ne outprg
    in
    let outprg = LicPrg.fold_nodes doit_node inprg outprg in
    outprg