Skip to content
Snippets Groups Projects
ast2lic.ml 25.38 KiB
(* Time-stamp: <modified the 29/08/2019 (at 15:28) by Erwan Jahier> *)


open Lxm
open AstPredef
open AstCore
open Lic
open IdSolver
open Lv6errors
open Lv6Id

(** debug flag: on prend le meme que LicTab ... *)
let dbg = (Lv6Verbose.get_flag "lazyc")

(******************************************************************************)
(* exception Ast2licType_error of string *)

(* exported *)
let rec (of_type: IdSolver.t -> AstCore.type_exp -> Lic.type_) =
  fun env texp ->
    match texp.it with
      | Bool_type_exp -> Bool_type_eff
      | Int_type_exp  -> Int_type_eff
      | Real_type_exp -> Real_type_eff
      | Named_type_exp s -> env.id2type s texp.src
      | Array_type_exp (elt_texp, szexp) ->
        let elt_teff = of_type env elt_texp in
        try
          let sz = EvalConst.eval_array_size env szexp in
          Array_type_eff (elt_teff, sz)
        with EvalConst.EvalArray_error msg -> 
          let lxm = AstCore.lxm_of_val_exp szexp in
          raise (Compile_error(lxm, "can't eval type: "^msg))



let (_add_pack_name : IdSolver.t -> Lxm.t -> Lv6Id.idref -> Lv6Id.idref) =
  fun id_solver lxm cc -> 
    try
      match Lv6Id.pack_of_idref cc with
        | Some _ -> cc
        | None ->
          let id = Lv6Id.of_idref false cc in
          let pn = 
            AstTabSymbol.find_pack_of_const id_solver.global_symbols id lxm 
          in
          Lv6Id.make_idref pn id
    with _ -> cc (* raise en error? *)


(* exported *)
let (of_clock : IdSolver.t -> AstCore.var_info -> Lic.id_clock)=
  fun id_solver v ->
    match v.var_clock with
      | Base -> v.var_name, BaseLic
      | NamedClock({ it=(cc,cv) ; src=lxm }) ->
        let vi = id_solver.id2var cv lxm in
        let _, clk = vi.var_clock_eff in
        let ct = vi.var_type_eff in
        v.var_name, On((cc,cv,ct), clk)

(******************************************************************************)
(* Checks that the left part has the same type as the right one. *)
and (type_check_equation: IdSolver.t -> Lxm.t -> Lic.left list -> 
     Lic.val_exp -> unit) =
  fun id_solver lxm lpl_eff ve_eff -> 
    let lpl_teff = List.map Lic.type_of_left lpl_eff in
    let ve_eff, right_part = EvalType.f id_solver ve_eff in
    if (List.length lpl_teff <> List.length right_part) then
      raise (Compile_error(lxm, 
                           "tuple size error: \n*** the tuple size is\n***\t"^ 
                             (string_of_int (List.length lpl_teff)) ^
                             " for the left-hand-side, and \n***\t" ^ 
                             (string_of_int (List.length right_part)) ^
                             " for the right-hand-side (in " ^
                               (String.concat
                                  "," 
                                  (List.map (LicDump.string_of_leff false) lpl_eff))
                               ^ " = " ^
                             (LicDump.string_of_val_exp_eff false ve_eff) ^ ")\n"   
      ))
    else
      List.iter2
        (fun le re -> 
          if le <> re then
            let msg = "type mismatch: \n***\t'" 
              ^ (Lic.string_of_type le) ^ 
                "' (left-hand-side) \n*** is not compatible with \n***\t'" 
              ^ (Lic.string_of_type re) ^ "' (right-hand-side)"
            in
            raise (Compile_error(lxm, msg))
        )
        lpl_teff
        right_part

(* Checks that the left part has the same clock as the right one. *)
and (clock_check_equation:IdSolver.t -> Lxm.t -> UnifyClock.subst -> 
     Lic.left list -> Lic.id_clock list -> Lic.val_exp -> Lic.val_exp) =
  fun _id_solver _lxm s lpl_eff right_part_clks ve_eff ->
    let lxms = List.map Lic.lxm_of_left lpl_eff in
    EvalClock.check_res lxms s lpl_eff right_part_clks;
    ve_eff

(******************************************************************************)
(* 
ICI : BEQUILLE(S)
on fait un lookup dans la table des operateurs
pour rechercher leurs (ventuels) parametres statiques : 

TRAITER LES MACROS PREDEF :
- ici, on juste besoin de fabriquer les arguments statiques effectifs
   partir des arguments donns et des args attendus.
- on cherche pas  faire rentrer dans le moule, on dlgue 

- 2015/07 -> probleme des node avec param statiques identifies par pack::node 
  c'etait pas prevu du  tout ...
  rajout du champs "all_srcs" dans le id solver qui premet de retrouver
  n'importe quelle info source (un peu extreme comme solution ...) 
*)

(* pour abstraire la nature des params statiques *)
type abstract_static_param =
   | ASP_const of Lv6Id.t
   | ASP_type of Lv6Id.t
   | ASP_node of Lv6Id.t

let do_abstract_static_param x = 
match x.it with
   | StaticParamType id -> ASP_type id
   | StaticParamConst (id,_) -> ASP_const id
   | StaticParamNode (id,_,_,_,_) -> ASP_node id


let get_abstract_static_params
   (srcs: AstTab.t)
   (symbols: AstTabSymbol.t)
   (lxm: Lxm.t)
   (idref: Lv6Id.idref)
: abstract_static_param list =
                     
   Lv6Verbose.exe ~flag:dbg (fun () ->
     Printf.fprintf stderr "#DBG: Ast2lic.get_abstract_static %s\n"
       (Lv6Id.raw_string_of_idref idref)
   ) ;
   match (idref.id_pack, idref.id_id) with
      | (Some "Lustre", "map")
      | (Some "Lustre", "red")
      | (Some "Lustre", "fill")
      | (Some "Lustre", "fillred") -> [ ASP_node "oper"; ASP_const "size" ]
      | (Some "Lustre", "boolred") -> [ ASP_const "min"; ASP_const "max"; ASP_const "size"]
      | (Some "Lustre", "condact") -> [  ASP_node "oper";  ASP_const "dflt" ]
      | (Some pck, nid) -> (
         (* 2015/07 -> nouveau cas, on cherche les params statiques en tapant
            directement dans le source *)
         let packsrc = match AstTab.pack_prov_env srcs pck with
         | Some ps -> ps
         | None -> AstTab.pack_body_env srcs pck
         in
         let spl = match AstTabSymbol.find_node packsrc nid lxm with
         | AstTabSymbol.Local ni -> ni.it.static_params
         | _ -> assert false
         in List.map do_abstract_static_param spl
      )
      | (None, nid) -> (
          (* try *)
            (* let spl = match AstTabSymbol.find_node symbols (Lv6Id.name_of_idref idref) lxm with *)
            let spl = match AstTabSymbol.find_node symbols nid lxm with
            | AstTabSymbol.Local ni -> ni.it.static_params
            | AstTabSymbol.Imported(_imported_node, params) -> params
            in List.map do_abstract_static_param spl
              (*          with Compile_error(_,_)  -> *)
            (* can occur for static node parameters, which cannot
               themselves have static parameters.  A better solution ougth
               to be to add node static parameters in the AstTabSymbol.t
               however (in Lazycompiler.node_check_do most probably). 
      
               OUI MAIS GROS BUG : qu'est-ce-qui se passe si si le
               'static node parameter' porte le meme nom qu'un noeud
               existant dans AstTabSymbol ???
      
               C'est clairement pas la bonne mthode ...
               Voir + bas ...
      
            *)
            (*             [] *)
     ) 


(* exported *)

let rec of_node
    (id_solver : IdSolver.t) (ne: AstCore.node_exp srcflagged) : Lic.node_exp =

  Lv6Verbose.exe ~flag:dbg (fun () ->
      Printf.fprintf stderr "\n\n#DBG: ENTERING Ast2lic.of_node \'";
      AstV6Dump.print_node_exp stderr ne.it;
      Printf.fprintf stderr "'\n\n";

    );
  let lxm = ne.src in
  let (idref, static_args) = ne.it in
  (* pas tres beau : on corrige le idref des predefs ... *)
  let idref = match (idref.id_pack, idref.id_id) with
    | (None, "map")
    | (None, "red")
    | (None, "fill")
    | (None, "fillred")
    | (None, "boolred")
    | (None, "condact") -> {idref with id_pack = Some "Lustre"}
    | _ -> idref
  in
  (* BUG des param statique node avec le meme nom
     qu'un node template global : 
     pis-aller : si static_args = [],
     on a peut-etre affaire  un static param node, donc
     on appelle directement id_solver.id2node et c'est lui
     qui plantera si ce n'est pas le cas et qu'il fallait
     des static_args...
     si static_args <> [], de toute maniere ca ne peut PAS
     etre un static param node
  *)

  (* NOUVELLE VERSION PURE :
     ON ne fait AUCUNE vrif de cohrence de types pour les param statiques,
     on ne vrifie QUE la nature (pour pouvoir rsoudre les args qui sont des idents
     A FAIRE + TARD ? !!
  *)
  let static_args_eff = match static_args with
    | [] -> []
    | _ ->
      let static_params =
        get_abstract_static_params id_solver.all_srcs id_solver.global_symbols lxm idref
      in
      let sp_l = List.length static_params 
      and sa_l = List.length static_args in
      if (sp_l <> sa_l) then
        let msg = "Bad number of (static) arguments: " ^ 
                  (string_of_int sp_l) ^ " expected, and " ^ 
                  (string_of_int sa_l) ^ " provided."
        in
        raise (Compile_error(lxm, msg))
      else
        List.map2 (check_static_arg id_solver) 
          static_params 
          static_args
  in
  let res = id_solver.id2node idref static_args_eff lxm in
  Lv6Verbose.exe ~flag:dbg (fun () ->
      Printf.fprintf stderr "\n#DBG: LEAVING Ast2lic.of_node \'";
      AstV6Dump.print_node_exp stderr ne.it;
      Printf.fprintf stderr "'\n";
      Printf.fprintf stderr "    RESULT:\n%s\n" (Lic.string_of_node_exp res);
    );
  res

and check_static_arg
    (node_id_solver: IdSolver.t)
    (asp: abstract_static_param) 
    (sa: AstCore.static_arg srcflagged) 
  : Lic.static_arg =
  (
    (* 1ere passe :
       on utilise expected juste pour rsoudre la nature,
       on "compile" les args 
    *)
    let nature_error nat =
      let msg = Printf.sprintf "Bad static argument nature, a %s was expected" nat in
      raise (Compile_error(sa.src, msg))
    in
    let res = match (sa.it, asp) with
      (* ident vs type *)
      | (StaticArgLv6Id idref, ASP_type id) ->
        let teff = node_id_solver.id2type idref sa.src in
        TypeStaticArgLic (id, teff)
      (* type_exp vs type *)
      | (StaticArgType te, ASP_type id) ->
        let teff = of_type node_id_solver te in
        TypeStaticArgLic (id, teff)
      (* ident vs const *)
      | (StaticArgLv6Id idref, ASP_const id) ->
        let ceff = node_id_solver.id2const idref sa.src in
        ConstStaticArgLic (id, ceff)
      (* val_exp vs const *)
      | (StaticArgConst ce, ASP_const id) -> (
          let ceff = EvalConst.f node_id_solver ce in
          match ceff with
          | [ceff] -> ConstStaticArgLic (id,ceff)
          | _ -> ConstStaticArgLic (id,Tuple_const_eff ceff)
        )
      (* id vs node *)
      | (StaticArgLv6Id idref, ASP_node id) ->
        let sargs = [] in
        let neff = node_id_solver.id2node idref sargs sa.src in
        NodeStaticArgLic (id, neff.node_key_eff)
      (* node exp vs node *)
      | (StaticArgNode (CALL_n ne), ASP_node id) ->
        let neff = of_node node_id_solver ne in
        NodeStaticArgLic (id, neff.node_key_eff)
      (* node exp vs node *)
      | (StaticArgNode (Predef_n (op)), ASP_node id) ->
        let opeff = LicEvalType.make_node_exp_eff node_id_solver None true op.it sa.src in
        NodeStaticArgLic (id, opeff.node_key_eff)
      | (_, ASP_type  _) -> nature_error "type"
      | (_, ASP_const _) -> nature_error "constant"
      | (_, ASP_node  _) -> nature_error "node"
    in res
  )

(******************************************************************************)


(* exported *)
and (of_eq: IdSolver.t -> AstCore.eq_info srcflagged -> Lic.eq_info srcflagged) =
  fun id_solver eq_info -> 
    let (lpl, ve) = eq_info.it in
    let lpl_eff = List.map (translate_left_part id_solver) lpl in
    let exp_clks = List.map Lic.clock_of_left lpl_eff  in
    let cs = UnifyClock.empty_subst in
    let ve_eff,right_part_clks,cs = translate_val_exp_check id_solver exp_clks cs ve in
    let ve_eff =
      type_check_equation id_solver eq_info.src lpl_eff ve_eff;
      clock_check_equation id_solver eq_info.src cs lpl_eff right_part_clks ve_eff
    in
    flagit (lpl_eff, ve_eff) eq_info.src


and (translate_left_part : IdSolver.t -> AstCore.left_part -> Lic.left) =
  fun id_solver lp_top -> 
    match lp_top with
    | LeftVar id -> 
      let vi_eff = id_solver.id2var id.it id.src in
      LeftVarLic (vi_eff, id.src)
    | LeftField (lp, id) -> (
        let lp_eff = translate_left_part id_solver lp in
        let teff = Lic.type_of_left lp_eff in
        (* check that [lp_eff] is a struct that have a field named [id] *)
        match teff with
        | Struct_type_eff(_, fl) -> (
            try let (teff_field,_) = List.assoc id.it fl in
              LeftFieldLic(lp_eff, id.it, teff_field)
            with Not_found ->
              raise (Compile_error(id.src, "bad field name in structure"))
          )
        | _  -> raise (Compile_error(id.src, "a structure was expected"))
      )
    | LeftArray (lp, vef) -> (
        let lp_eff = translate_left_part id_solver lp in
        let teff = Lic.type_of_left lp_eff in
        let lxm = vef.src in
        match teff with
        | Abstract_type_eff(_,Array_type_eff(teff_elt, _size))
        | Array_type_eff(teff_elt, _size) ->
          let index = EvalConst.eval_array_index id_solver vef.it lxm in
          LeftArrayLic(lp_eff, index, teff_elt)

        | _ -> raise (Compile_error(vef.src, "an array was expected"))
      )
    | LeftSlice (lp, sif) -> (
        let lp_eff = translate_left_part id_solver lp in
        let teff = Lic.type_of_left lp_eff in
        match teff with  
        | Abstract_type_eff(_,Array_type_eff(teff_elt, _size))
        | Array_type_eff(teff_elt, _size) -> 
          let sieff = translate_slice_info id_solver sif.it sif.src in
          let size_slice = sieff.se_width in
          let teff_slice = Array_type_eff(teff_elt, size_slice) in
          LeftSliceLic(lp_eff, sieff, teff_slice)
        | _ -> raise (Compile_error(sif.src, "an array was expected"))
      )


(* Translate and performs the checks *)
and (translate_val_exp_check  : IdSolver.t -> Lic.clock list -> UnifyClock.subst -> 
     AstCore.val_exp -> Lic.val_exp * Lic.id_clock list * UnifyClock.subst) =
  fun id_solver exp_clks s ve ->
    let s,vef = translate_val_exp id_solver s ve in
    let lxm = AstCore.lxm_of_val_exp ve in
    let lxms = List.map (fun _ -> lxm) exp_clks in
    (* let vef, tl   = EvalType.f id_solver vef in *)
    EvalClock.f id_solver s vef lxms exp_clks  


and (translate_val_exp : IdSolver.t -> UnifyClock.subst -> AstCore.val_exp
     -> UnifyClock.subst * Lic.val_exp) =
  fun id_solver s ve ->
    (match ve with
     | CallByPos({it=WITH_n(c,e1,e2);_}, Oper vel) ->
       assert (vel=[]);
       if EvalConst.f id_solver c = [ Bool_const_eff true ] 
       then translate_val_exp id_solver s e1 
       else translate_val_exp id_solver s e2
     | _ -> 
       let s, vef_core, lxm =
         match ve with
         | Merge_n(ve, cl) ->  
           let lxm_ve = ve.src in
           let ve = ve.it in
           let s,ve = translate_val_exp id_solver s ve in
           let s, cl =
             List.fold_left
               (fun (s,cl) (id,ve) -> 
                  let s, ve = translate_val_exp id_solver s ve in
                  let const = id_solver.id2const id.it id.src in
                  s,(flagit const id.src, ve)::cl
               )
               (s, [])
               cl
           in
           s, Lic.Merge(ve, List.rev cl), lxm_ve
         | Merge_bool_n(ve, t, f) ->
           let lxm_ve = ve.src in
           let ve = ve.it in
           let s,ve = translate_val_exp id_solver s ve in
           let s,case_true  = translate_val_exp id_solver s t in
           let s,case_false = translate_val_exp id_solver s f in
           let case_true = (flagit (Bool_const_eff true) lxm_ve, case_true) in
           let case_false = (flagit (Bool_const_eff false) lxm_ve, case_false) in
           s, Lic.Merge(ve, [case_true; case_false]), lxm_ve

         | CallByName(by_name_op, field_list) ->
           let s,fl = List.fold_left 
               (fun (s,fl) f -> 
                  let s,f = translate_field id_solver s f in
                  s,f::fl
               )
               (s,[])
               field_list
           in
           let fl = List.rev fl in
           let s, by_name_op = translate_by_name_op id_solver by_name_op s in
           s, 
           (CallByNameLic(by_name_op, fl)), by_name_op.src

         | CallByPos(by_pos_op, Oper vel) ->
           let s, vel_eff = 
             List.fold_left 
               (fun (s,vel) ve -> 
                  let s, ve = translate_val_exp id_solver s ve in
                  s,ve::vel
               )
               (s,[]) vel 
           in
           let vel_eff = List.rev vel_eff in
           let lxm = by_pos_op.src in
           let by_pos_op = by_pos_op.it in
           let mk_by_pos_op by_pos_op_eff =
             CallByPosLic(flagit by_pos_op_eff lxm, vel_eff)
           in
           let mk_nary_pos_op by_pos_op_eff = 
             (* For nor and diese: internally, nor and diese takes an array of val_exp,
                to make it easier the translation into boolred.

                It is the good spot to do that? what could be a better spot?
             *)
             let array_val_exp =
               let lxm = Lxm.override_name "[ ]" lxm in
               { ve_core = CallByPosLic(flagit Lic.ARRAY lxm, vel_eff);
                 ve_typ = [Array_type_eff(List.hd (List.hd vel_eff).ve_typ,
                                          List.length vel_eff)];
                 ve_clk = (List.hd vel_eff).ve_clk;
                 ve_src =  lxm 
               }
             in
             CallByPosLic(flagit by_pos_op_eff lxm, [array_val_exp])
           in

           let s, vef_core =
             match by_pos_op with
             | WITH_n(_,_,_) -> assert false (* handled at the top of the function *)
             (* put that in another module ? yes, see above.*)
             | Predef_n({it=TRUE_n;_})  -> s,mk_by_pos_op(Lic.CONST (Bool_const_eff true))
             | Predef_n({it=FALSE_n;_}) -> s,mk_by_pos_op(Lic.CONST (Bool_const_eff false))
             | Predef_n({it=RCONST_n r;_}) -> s,mk_by_pos_op(Lic.CONST (Real_const_eff r))
             | Predef_n({it=ICONST_n i;_}) -> s, mk_by_pos_op(Lic.CONST (Int_const_eff i))


             | Predef_n({it=NOR_n;src=lxm}) -> s, mk_nary_pos_op(
                 Lic.PREDEF_CALL (flagit (AstPredef.op_to_long NOR_n,[]) lxm))
             | Predef_n({it=DIESE_n;src=lxm}) -> s, mk_nary_pos_op(
                 Lic.PREDEF_CALL (flagit (AstPredef.op_to_long DIESE_n,[]) lxm))
             | Predef_n(op) -> s, mk_by_pos_op(
                 Lic.PREDEF_CALL (flagit (AstPredef.op_to_long op.it,[]) op.src))
             | CALL_n node_exp_f -> 
               let neff = of_node id_solver node_exp_f in
               let ceff = Lic.CALL (flagit neff.node_key_eff node_exp_f.src) in
               Lv6Verbose.exe ~flag:dbg (fun () ->
                   Printf.fprintf stderr "#DBG: Ast2lic.translate_val_exp CALL_n ";
                   AstV6Dump.print_node_exp stderr node_exp_f.it;
                   Printf.fprintf stderr " gives type: %s\n%!"
                     (Lic.string_of_type_profile (profile_of_node_exp neff))
                 ) ;
               (s, mk_by_pos_op ceff)
             | IDENT_n idref -> (
                 try
                   let var = id_solver.id2var idref.id_id lxm in
                   s, mk_by_pos_op(Lic.VAR_REF var.var_name_eff)
                 with _ ->
                   let s, const = UnifyClock.const_to_val_eff lxm false s
                       (id_solver.id2const idref lxm)
                   in
                   s, const.ve_core
               )
             | CURRENT_n -> s, mk_by_pos_op (Lic.CURRENT None)
             | PRE_n -> s, mk_by_pos_op Lic.PRE

             | ARROW_n -> s, mk_by_pos_op Lic.ARROW

             | FBY_n -> (* XXX temporary crutch: translate "e1 fby e2" into "e2 -> pre(e2)" *)
               (match vel_eff with
                | [e1;e2] -> 
                  let ve_pre = CallByPosLic(flagit Lic.PRE lxm, [e2]) in
                  let ve_pre = { e2 with ve_core=ve_pre } in
                  let lxm = Lxm.override_name "->" lxm in
                  s,CallByPosLic(flagit Lic.ARROW lxm, [e1;ve_pre]) 
                | _ -> assert false
               )
             (*                   | FBY_n ->   s, mk_by_pos_op Lic.FBY *)
             | CONCAT_n -> s, mk_by_pos_op Lic.CONCAT
             | TUPLE_n -> s, mk_by_pos_op Lic.TUPLE
             | ARRAY_n -> s, CallByPosLic(flagit Lic.ARRAY lxm, vel_eff)
             | STRUCT_ACCESS_n fid ->
               s, mk_by_pos_op (Lic.STRUCT_ACCESS (fid))

             | WHEN_n Base -> s, mk_by_pos_op (Lic.WHEN BaseLic)
             | WHEN_n (NamedClock { it = (cc,c) ; src = lxm }) -> 
               let var_info = id_solver.id2var c lxm in
               let _, clk = var_info.var_clock_eff in
               let ct =  var_info.var_type_eff in
               s, mk_by_pos_op (Lic.WHEN (On((cc,c,ct), clk)))

             | ARRAY_ACCES_n ve_index ->
               s, mk_by_pos_op (Lic.ARRAY_ACCES(
                   EvalConst.eval_array_index id_solver ve_index lxm))

             | ARRAY_SLICE_n si ->
               s, mk_by_pos_op (Lic.ARRAY_SLICE(
                   EvalConst.eval_array_slice id_solver si lxm))

             | HAT_n -> (
                 match vel with
                 | [_exp; ve_size] -> 
                   let size_const_eff = EvalConst.f id_solver ve_size in 
                   (match size_const_eff with
                    | [Int_const_eff sz] -> s, mk_by_pos_op (Lic.HAT(int_of_string sz))
                    | _ -> assert false)
                 | _ -> assert false
               )
           in
           s, vef_core, lxm
       in
       let vef = { ve_core=vef_core; ve_typ=[]; ve_clk = []; ve_src = lxm } in
       let vef, _tl = EvalType.f id_solver vef in
       s,vef
    )    


and translate_by_name_op id_solver op s = 
  let to_long idref =
    match Lv6Id.pack_of_idref idref with
    | None -> (* If no pack name is provided, we lookup it in the symbol table *)
      let id = Lv6Id.of_idref false idref in
      let pn = AstTabSymbol.find_pack_of_type id_solver.global_symbols id op.src in
      Lv6Id.make_long pn idref.id_id
    | Some pn -> Lv6Id.make_long pn idref.id_id
  in
  let s, nop =
    match op.it with
    | STRUCT_anonymous_n -> s, STRUCT_anonymous
    | STRUCT_n idref ->     s, STRUCT (to_long idref)
    | STRUCT_WITH_n (idref1, idref2) -> 
      s, STRUCT_with (to_long idref1, idref2.id_id)
  in
  s, flagit nop op.src

and translate_field id_solver s (id, ve) = 
  let s, ve = translate_val_exp id_solver s ve in
  s, (id, ve)

(* XXX autre nom, autre module ? 
   node_of_static_arg : appel QUAND ON SAIT qu'un sarg doit etre un NODE
   const_of_static_arg : appel QUAND ON SAIT qu'un sarg doit etre une CONST

   -> sert pour les macros predefs
   ca fait partie de la definition des iterateurs d'une certaine maniere...
   -> crer 2 modules, Iterator + IteratorSemantics 
*)
and _const_of_static_arg id_solver const_or_const_ident lxm = 
  match const_or_const_ident with
  | StaticArgConst(c) -> (
	   match EvalConst.f id_solver c with
	   | [x] -> x
	   | xl -> 
		  (* EvalConst.f ne fabrique PAS de tuple, on le fait ici *)
		  Tuple_const_eff xl
    )
  | StaticArgLv6Id(id) -> id_solver.id2const id lxm 
  | StaticArgType _
  | StaticArgNode _ -> raise (Compile_error(lxm, "a constant was expected"))



and _node_of_static_arg id_solver node_or_node_ident lxm =
  match node_or_node_ident with
  | StaticArgLv6Id(id) -> 
    let sargs = [] in (* it is an alias: no static arg *)
    id_solver.id2node id sargs lxm 

  | StaticArgNode(CALL_n ne) -> of_node id_solver ne
  | StaticArgNode(Predef_n (op)) ->
    LicEvalType.make_node_exp_eff id_solver None true op.it lxm

  | StaticArgNode(_) -> assert false

  | StaticArgType _ 
  | StaticArgConst _ -> raise (Compile_error(lxm, "a node was expected"))

and (translate_slice_info  : IdSolver.t -> AstCore.slice_info -> 
     Lxm.t -> Lic.slice_info) =
  fun id_solver si lxm ->
    EvalConst.eval_array_slice id_solver si lxm


(**********************************************************************************)
(* exported *)
let (of_assertion : IdSolver.t -> AstCore.val_exp Lxm.srcflagged -> 
      Lic.val_exp Lxm.srcflagged) =
  fun id_solver vef ->
    let s = UnifyClock.empty_subst in
    let exp_clks = [BaseLic] in (* assertions are on the base clock *)
    let val_exp_eff, _ ,s = translate_val_exp_check id_solver exp_clks s vef.it in
    (* Check that the assert is a bool. *)
    let val_exp_eff, evaled_exp = EvalType.f id_solver val_exp_eff in
      List.iter
        (fun ve -> 
           if ve <> Bool_type_eff then
             let msg = "type mismatch: \n\tthe content of the assertion is of type " 
               ^ (Lic.string_of_type ve) 
               ^ " whereas it shoud be a Boolean\n"
             in
               raise (Compile_error(vef.src, msg))
        )
        evaled_exp;
      (* type is ok *)

      (* Clock check the assertion*)
      let _, clock_eff_list, _s = 
        EvalClock.f id_solver s val_exp_eff [vef.src] [BaseLic]
      in
        match clock_eff_list with
          | [_id, BaseLic] 
          | [_id, On(_,BaseLic)]
          | [_id, ClockVar _] -> Lxm.flagit val_exp_eff vef.src
          | [_id, ce] -> 
              let msg = "clock error: assert should be on the base clock, "^
                "but it is on "^ (LicDump.string_of_clock2 ce) ^ "\n"
              in
                raise (Compile_error(vef.src, msg))

          | _ -> assert false
      

(******************************************************************************)
(******************************************************************************)