licTab.ml 54.80 KiB
(* Time-stamp: <modified the 29/08/2019 (at 16:41) by Erwan Jahier> *)
open Lxm
open Lv6errors
open AstCore
open Lic
open IdSolver
(** DEBUG FLAG POUR CE MODULE : *)
let dbg = (Lv6Verbose.get_flag "lazyc")
let finish_me msg = print_string ("\n\tXXX licTab:"^msg^" -> finish me!\n")
let profile_info = Lv6Verbose.profile_info
(******************************************************************************)
(** Returns the ident on which the recursion was detected, plus an execution
stack description.
*)
exception Recursion_error of (Lv6Id.long as 'id) * (string list as 'stack)
exception BadCheckRef_error
let recursion_error (lxm : Lxm.t) (stack : string list) =
let rec string_of_stack = function
| [] -> "nostack"
| s::[] -> s
| s::l -> s^"\n > "^(string_of_stack l)
in
raise ( Compile_error
(lxm, "Recursion loop detected: \n*** " ^(string_of_stack stack)
))
(******************************************************************************)
(* Structure principale *)
type t = {
src_tab : AstTab.t;
(* table des defs *)
types : (Lic.item_key, Lic.type_ Lic.check_flag) Hashtbl.t;
consts : (Lic.item_key, Lic.const Lic.check_flag) Hashtbl.t;
nodes : (Lic.node_key, Lic.node_exp Lic.check_flag) Hashtbl.t;
(* table des prov *)
prov_types : (Lic.item_key, Lic.type_ Lic.check_flag) Hashtbl.t;
prov_consts : (Lic.item_key, Lic.const Lic.check_flag) Hashtbl.t;
prov_nodes : (Lic.node_key, Lic.node_exp Lic.check_flag) Hashtbl.t
}
(******************************************************************************)
(* exported *)
let (create : AstTab.t -> t) =
fun tbl ->
let nodes_tbl = Hashtbl.create 0 in
let prov_nodes_tbl = Hashtbl.create 0 in
(* Iterated operators need to be in this table. Ideally, the lazy
compiler should be able to pull such strings though...
*)
List.iter
(fun op ->
let op_str = AstPredef.op2string op in
let op_eff = LicEvalType.make_simple_node_exp_eff None true op
(Lxm.dummy op_str)
in
let op_key = AstPredef.op_to_long op, [] in
Hashtbl.add nodes_tbl op_key (Lic.Checked op_eff);
Hashtbl.add prov_nodes_tbl op_key (Lic.Checked op_eff)
)
AstPredef.iterable_op;
{
src_tab = tbl;
types = Hashtbl.create 0;
consts = Hashtbl.create 0;
nodes = nodes_tbl;
prov_types = Hashtbl.create 0;
prov_consts = Hashtbl.create 0;
prov_nodes = prov_nodes_tbl;
}
(******************************************************************************)
(** Type checking + constant checking/evaluation
This is performed (lazily) by 10 mutually recursive functions:
checking types
--------------
(1) [type_check env type_name lxm]: type check the type id [type_name]
(2) [type_check_do]: untabulated version of [type_check] (do the real work).
(3) [type_check_interface]: ditto, but for the interface part
(4) [type_check_interface_do]: untabulated version (do the real work)
(5) [solve_type_idref] solves constant reference (w.r.t. short/long ident)
checking constants
------------------
(6) [const_check env const_name lxm]: eval/check the constant [const_name]
(7) [const_check_do] : untabulated version (do the real work)
(8) [const_check_interface]: ditto, but for the interface part
(9) [const_check_interface_do]: untabulated version (do the real work)
(10) [solve_const_idref] solves constant reference (w.r.t. short/long ident)
checking nodes
--------------
(11) [node_check env node_name lxm]: check the node [node_name]
checking a node means checking its interface and checking it equations/asserts.
checking an equation means checking that the type and clock of the
left part is the same as the ones of the rigth part.
(12) [node_check_do] : untabulated version (do the real work)
(13) [node_check_interface]: ditto, but for the interface part
(14) [node_check_interface_do]: untabulated version (do the real work)
(15) [solve_node_idref] solves constant reference (w.r.t. short/long ident)
XXX checking clocks
-------------------
Ditto, but todo!
nb: for x in {type, const, node, clock}, there are several functions
that returns [x_eff]:
- [x_check]
o tabulates its result
o takes an x_key and returns an [x_eff]
o lookups its (syntaxic) definition (x_info) via the symbolTab.t
o calls [Ast2lic.of_X] to translate its sub-terms
- [Ast2lic.of_X]
o takes a [x_exp] (i.e., an expression) and returns an [x_eff]
o compute the effective static args (for nodes)
o calls [solve_x_idref] (via [id_solver]) to translate its sub-terms
- [solve_x_idref]
o takes an idref (plus a Lic.static_arg list for x=node!)
o perform name resolution
o calls [x_check] (loop!)
nb2: the top-level call is [node_check], on a node that necessarily contains
no static parameters.
*)
(* Before starting, let's define a few utilitary functions. *)
(** Intermediary results are put into a table. This tabulation handling
is common to type and constant checking, and is performed by the
2 following functions.
Since [x] is meant to stand for [type], [const], or [node], those 2
functions will lead to the definition of 6 functions:
[type_check], [const_check], [node_check],
[type_check_interface], [const_check_interface], [node_check_interface].
*)
let x_check
(* tab find_x x_check_do lookup_x_eff pack_of_x_key name_of_x_key this x_key lxm = *)
(tab : ('x_key, 'x_eff Lic.check_flag) Hashtbl.t)
(find_x : AstTabSymbol.t -> Lv6Id.t -> Lxm.t ->
('x_info Lxm.srcflagged) AstTabSymbol.elt)
(x_check_do : t -> 'x_key -> Lxm.t -> AstTabSymbol.t -> bool ->
Lv6Id.pack_name -> 'x_info srcflagged -> 'x_eff)
(x_builtin : t -> 'x_key -> Lxm.t -> 'x_eff)
(lookup_x_eff : ('x_key, 'x_eff Lic.check_flag) Hashtbl.t -> 'x_key ->
Lxm.t -> 'x_eff)
(pack_of_x_key : 'x_key -> string )
(name_of_x_key : 'x_key -> string)
(this : t)
(x_key : 'x_key)
(lxm : Lxm.t)
: 'x_eff =
Lv6Verbose.exe ~flag:dbg
(fun () -> Printf.printf "#DBG: licTab.x_check '%s'\n"
(Lxm.details lxm));
try lookup_x_eff tab x_key lxm
with Not_found -> (
let res = try x_builtin this x_key lxm
with Not_found ->
Hashtbl.add tab x_key Lic.Checking;
let (x_pack,xn) = (pack_of_x_key x_key, name_of_x_key x_key) in
let x_pack_symbols = AstTab.pack_body_env this.src_tab x_pack in
let x_def = match find_x x_pack_symbols xn lxm with
| AstTabSymbol.Local x_def -> x_def
| AstTabSymbol.Imported (lid,_) ->
print_string ("*** " ^ (Lv6Id.string_of_long false lid) ^ "???\n" ^
(Lxm.details lxm));
assert false (* should not occur *)
in
x_check_do this x_key lxm x_pack_symbols false x_pack x_def
in
Hashtbl.replace tab x_key (Lic.Checked res);
res
)
let x_check_interface
tab find_x x_check x_check_interface_do x_builtin lookup_x_eff
pack_of_x_key name_of_x_key this x_key lxm =
try lookup_x_eff tab x_key lxm
with Not_found ->
let res = (
try x_builtin this x_key lxm
with Not_found ->
Hashtbl.add tab x_key Lic.Checking;
let (xp,xn) = (pack_of_x_key x_key, name_of_x_key x_key) in
let xp_prov_symbols_opt = AstTab.pack_prov_env this.src_tab xp in
match xp_prov_symbols_opt with
| None ->
(* if [xp] have no provided symbol table, the whole package is exported. *)
x_check this x_key lxm
| Some xp_prov_symbols ->
let x_def = match find_x xp_prov_symbols xn lxm with
| AstTabSymbol.Local x -> x
| AstTabSymbol.Imported _ -> assert false (* should not occur *)
in
x_check_interface_do this x_key lxm xp_prov_symbols xp x_def
) in
Hashtbl.replace tab x_key (Lic.Checked res);
res
(* Returns the tabulated [type] or [const], if it has already been computed;
otherwise, raise [Not_found] otherwise. *)
let lookup_x_eff x_label id_of_x_key x_tab x_key lxm =
match Hashtbl.find x_tab x_key with
| Lic.Checked res -> res
| Lic.Checking ->
raise (Recursion_error (id_of_x_key x_key, [x_label^(Lxm.details lxm)]))
| Lic.Incorrect -> raise (BadCheckRef_error)
let (lookup_type_eff: (Lic.item_key, Lic.type_ Lic.check_flag) Hashtbl.t ->
Lv6Id.long -> Lxm.t -> Lic.type_) =
lookup_x_eff "type ref " (fun k -> k)
let (type_builtin : t -> Lv6Id.long -> Lxm.t -> Lic.type_) =
fun _ _ _ -> raise Not_found
let (lookup_const_eff:(Lic.item_key, Lic.const Lic.check_flag) Hashtbl.t ->
Lv6Id.long -> Lxm.t -> Lic.const) =
lookup_x_eff "const ref " (fun k -> k)
let (const_builtin : t -> Lv6Id.long -> Lxm.t -> Lic.const) =
fun _ _ _ -> raise Not_found
(*
LES NOEUDS (MACROS) BUILD-IN
sont tracks ici pour court-circuiter le node_check normal
(qui ncessite un node_info)
*)
let lookup_node_exp_eff
(tbl: (Lic.node_key, Lic.node_exp Lic.check_flag) Hashtbl.t)
(key: Lic.node_key)
(lxm: Lxm.t)
: Lic.node_exp =
try
let node_exp = lookup_x_eff "node ref " (fun k -> fst k) tbl key lxm in
Lv6Verbose.exe ~flag:dbg (fun () -> Printf.printf
"#DBG: licTab.lookup_node_exp_eff: FOUND node key '%s'\n"
(Lic.string_of_node_key key)
);
node_exp
with Not_found -> (
Lv6Verbose.exe ~flag:dbg (
fun () ->
Printf.fprintf
stderr "#DBG: licTab.lookup_node_exp_eff: node key '%s' NOT FOUND\n"
(Lic.string_of_node_key key);
flush stderr
);
raise Not_found
)
let node_builtin (this: t) (key: Lic.node_key) (lxm: Lxm.t) : Lic.node_exp =
(* 12/07 *)
(* ICI => courtcircuite les macros built-in *)
let nk2nd = fun nk ->
try
match Hashtbl.find this.nodes nk with
| Lic.Checked res -> res
| _ -> assert false
with Not_found -> assert false
in
let node_exp = LicMetaOp.do_node nk2nd key lxm in
Lv6Verbose.exe ~flag:dbg (fun () -> Printf.printf
"#DBG: licTab.lookup_node_exp_eff: BUILT-IN node key '%s'\n"
(Lic.string_of_node_key key)
);
Hashtbl.replace this.nodes key (Lic.Checked node_exp);
Hashtbl.replace this.prov_nodes key (Lic.Checked node_exp);
node_exp
(* lookup_x_eff "node ref " (fun k -> fst k) *)
(** This function performs the identifier (idref) resolution,
i.e., when an ident is not explicitely prefixed by a module
name, we decide here to which module it belongs.
The [provide_flag] indicates whether that function was called
from a provide part or not.
*)
let solve_x_idref
x_check_interface x_check find_x x_label to_x_key this symbols
provide_flag currpack idr _sargs lxm =
let s = Lv6Id.name_of_idref idr in
match Lv6Id.pack_of_idref idr with
| Some p ->
if p = currpack
then x_check this (to_x_key currpack s) lxm
else x_check_interface this (to_x_key p s) lxm
| None ->
(* no pack name: it must be in the symbols table *)
try
match (find_x symbols s lxm) with
| AstTabSymbol.Local _x_info ->
let x_key = to_x_key currpack s in
if provide_flag
then x_check_interface this x_key lxm
else x_check this x_key lxm
| AstTabSymbol.Imported(fid,_params) ->
let (pi,si) = (Lv6Id.pack_of_long fid, Lv6Id.of_long fid) in
(* todo *)
(* rien a faire : si on est arrive ici
c'est que les params statique ont pu etre evalues *)
(* assert(params=[]); *)
x_check_interface this (to_x_key pi si) lxm
with Not_found ->
(raise (Compile_error(lxm,"unbounded " ^ x_label ^ " ident")))
(******************************************************************************)
(* topologically sort vars wrt their clock dependecency *)
let find_var_info lxm vars id =
try Hashtbl.find vars.vartable id
with Not_found ->
raise (Compile_error (lxm,"\n*** Unknown ident: " ^ (Lv6Id.to_string id)))
(* returns the clock of a var *)
let find_direct_dep lxm v vars =
match (find_var_info lxm vars v).it.var_clock with
| Base -> None
| NamedClock({it=(_,vclk);_}) -> Some vclk
(* to track clock dependancy loops *)
type var_state = Todo | Doing | Done of Lv6Id.t list
let dep_star lxm vl vars =
let tbl = Hashtbl.create (List.length vl) in
List.iter (fun v -> Hashtbl.add tbl v Todo) vl ;
let rec find_deps v =
Lv6Verbose.exe ~flag:dbg (fun () -> Printf.printf " check clock dep : %s\n" v);
if not (Hashtbl.mem tbl v) then Hashtbl.add tbl v Todo;
match Hashtbl.find tbl v with
| Done cl -> cl
| Todo -> (
Hashtbl.replace tbl v (Doing);
match find_direct_dep lxm v vars with
| None -> Hashtbl.replace tbl v (Done []);[]
| Some v2 ->
let v2_deps = find_deps v2 in
let v_deps = v2::v2_deps in
Hashtbl.replace tbl v (Done v_deps);
v_deps
)
| Doing ->
let lxm =
try let vi = Hashtbl.find vars.vartable v in vi.src
with Not_found -> lxm (* sno *)
in
raise(Compile_error (
lxm, ("A loop in the clock dependancies exists for variable "^ v)))
in
List.iter
(fun v ->
match find_deps v with
| [] -> Hashtbl.remove tbl v (* cleaning *)
| _::_ -> ()
)
vl;
let tbl2 = Hashtbl.create(List.length vl) in
Hashtbl.iter (fun v dep ->
match dep with Done cl -> Hashtbl.replace tbl2 v cl | _ -> ()) tbl;
tbl2
module TopoSortVars =
TopoSort.Make(
struct
type elt = Lv6Id.t
type store = (Lv6Id.t, Lv6Id.t list) Hashtbl.t
let find_dep tbl x =
try Hashtbl.find tbl x with Not_found -> []
let have_dep tbl x = try Hashtbl.find tbl x <> [] with Not_found -> false
let remove_dep tbl x = Hashtbl.remove tbl x; tbl
end
)
(* Looks like the one in Lic *)
let (sort_vars : Lxm.t -> AstCore.node_vars-> Lv6Id.t list -> Lv6Id.t list) =
fun lxm vars l -> (* we sort vars according to their clock deps *)
profile_info "LicTab.sort_vars\n";
let tbl = dep_star lxm l vars in
TopoSortVars.f tbl l
(******************************************************************************)
(* And now we can start the big mutually recursive definition... *)
(** Tabulated version of [type_check_do]. *)
let rec type_check
(this: t)
(key: Lv6Id.long)
(lxm: Lxm.t)
: Lic.type_ =
Lv6Verbose.exe ~flag:dbg (fun () ->
Printf.printf "#DBG: licTab.type_check '%s'\n" (Lv6Id.string_of_long false key));
x_check this.types AstTabSymbol.find_type type_check_do type_builtin lookup_type_eff
Lv6Id.pack_of_long Lv6Id.of_long this
key lxm
(** Tabulated version of [const_check_do]. *)
and const_check
(this: t)
(key: Lv6Id.long)
(lxm: Lxm.t)
: Lic.const =
Lv6Verbose.exe ~flag:dbg (fun() -> Printf.printf
"#DBG: licTab.const_check '%s'\n" (Lv6Id.string_of_long false key));
x_check this.consts AstTabSymbol.find_const const_check_do const_builtin
lookup_const_eff
Lv6Id.pack_of_long Lv6Id.of_long this
key lxm
(** Tabulated version of [type_check_interface_do]. *)
and type_check_interface
(this: t)
(key: Lv6Id.long)
(lxm: Lxm.t)
: Lic.type_ =
Lv6Verbose.exe ~flag:dbg (fun() -> Printf.printf
"#DBG: licTab.type_check_interface '%s'\n" (Lv6Id.string_of_long false key));
x_check_interface
this.prov_types AstTabSymbol.find_type type_check type_check_interface_do
type_builtin lookup_type_eff Lv6Id.pack_of_long Lv6Id.of_long this
key lxm
(** Tabulated version of [const_check_interface_do]. *)
and const_check_interface
(this: t)
(key: Lv6Id.long)
(lxm: Lxm.t)
: Lic.const =
Lv6Verbose.exe ~flag:dbg (fun () -> Printf.printf
"#DBG: licTab.const_check_interface '%s'\n" (Lv6Id.string_of_long false key));
x_check_interface
this.prov_consts AstTabSymbol.find_const const_check const_check_interface_do
const_builtin lookup_const_eff Lv6Id.pack_of_long Lv6Id.of_long this
key lxm
(** solving type and constant references *)
and (solve_type_idref : t -> AstTabSymbol.t -> bool -> Lv6Id.pack_name ->
Lv6Id.idref -> Lxm.t -> Lic.type_) =
fun this symbols provide_flag currpack idr lxm ->
solve_x_idref
type_check_interface type_check AstTabSymbol.find_type "type"
(fun p id -> Lv6Id.make_long p id)
this symbols provide_flag currpack idr [] lxm
and (solve_const_idref : t -> AstTabSymbol.t -> bool -> Lv6Id.pack_name ->
Lv6Id.idref -> Lxm.t -> Lic.const) =
fun this symbols provide_flag currpack idr lxm ->
solve_x_idref
const_check_interface const_check AstTabSymbol.find_const "const"
(fun p id -> Lv6Id.make_long p id)
this symbols provide_flag currpack idr [] lxm
(* now the real work! *)
and (type_check_interface_do: t -> Lv6Id.long -> Lxm.t -> AstTabSymbol.t ->
Lv6Id.pack_name -> AstCore.type_info srcflagged ->
Lic.type_) =
fun this type_name lxm prov_symbols pack_name type_def ->
(* We type check the interface and the body.
For non-abstract types, we also check that both effective types are
the same. *)
let body_type_eff = type_check this type_name lxm in
let prov_type_eff =
type_check_do this type_name lxm prov_symbols true pack_name type_def
in
if Lic.type_are_compatible prov_type_eff body_type_eff then
prov_type_eff
else
raise(Compile_error (
type_def.src,
("provided type \n\t" ^
(Lic.string_of_type prov_type_eff) ^
"\n is not compatible with its implementation \n\t" ^
(Lic.string_of_type body_type_eff))))
and (const_check_interface_do: t -> Lv6Id.long -> Lxm.t -> AstTabSymbol.t ->
Lv6Id.pack_name -> AstCore.const_info srcflagged ->
Lic.const) =
fun this cn lxm prov_symbols p const_def ->
let prov_const_eff = const_check_do this cn lxm prov_symbols true p const_def in
let body_const_eff = const_check this cn lxm in
match prov_const_eff, body_const_eff with
| Lic.Extern_const_eff (_), _ -> assert false
| Lic.Abstract_const_eff (_id, _teff, _v, _is_exported),
Lic.Abstract_const_eff (_body_id, _body_teff, _body_v, _body_is_exported)
->
assert false
(* indeed, how can a body constant be extern and have a value? *)
| Lic.Abstract_const_eff (id, teff, _v, is_exported),
Lic.Extern_const_eff (body_id, body_teff)
->
if (id <> cn) then assert false
else if not (Lic.type_are_compatible teff body_teff) then
raise(Compile_error (
const_def.src,
("provided constant type \n***\t" ^
(Lic.string_of_type teff) ^
" is not compatible with its implementation \n***\t" ^
(Lic.string_of_type body_teff) ^ "")))
else if
is_exported
then
raise(Compile_error (const_def.src, " constant values mismatch"))
else
Lic.Extern_const_eff (body_id, body_teff)
| Lic.Abstract_const_eff (id, teff, v, is_exported), _ ->
let body_teff = Lic.type_of_const body_const_eff in
if (id <> cn) then assert false
else if not (Lic.type_are_compatible teff body_teff) then
raise(Compile_error (
const_def.src,
("provided constant type \n***\t" ^
(Lic.string_of_type teff) ^
" is not compatible with its implementation \n***\t" ^
(Lic.string_of_type body_teff) ^ "")))
else
if is_exported && body_const_eff <> v then
raise(Compile_error (const_def.src, " constant values mismatch"))
else
Lic.Abstract_const_eff (id, teff, body_const_eff, is_exported)
| Lic.Enum_const_eff (_, _), _
| Lic.Bool_const_eff _, _
| Lic.Int_const_eff _, _
| Lic.Real_const_eff _, _
| Lic.Struct_const_eff (_,_), _
| Lic.Array_const_eff (_,_), _
->
if prov_const_eff = body_const_eff then
body_const_eff
else
raise(Compile_error (
const_def.src,
"\n*** provided constant does not match with its definition."))
| Lic.Tuple_const_eff _, _ ->
print_internal_error "licTab.const_check_interface_do"
"should not have been called for a tuple";
assert false
and (type_check_do: t -> Lv6Id.long -> Lxm.t -> AstTabSymbol.t -> bool ->
Lv6Id.pack_name -> AstCore.type_info srcflagged ->
Lic.type_) =
fun this type_name lxm symbols provide_flag pack_name type_def ->
try (
(* Solveur d'idref pour les appels eval_type/eval_const *)
let id_solver = {
id2var = (fun id lxm -> raise (Unknown_var(lxm,id)) (* should not occur *));
id2const = solve_const_idref this symbols provide_flag pack_name;
id2type = solve_type_idref this symbols provide_flag pack_name;
id2node = solve_node_idref this symbols provide_flag pack_name;
global_symbols = symbols;
all_srcs = this.src_tab;
}
in
let type_eff =
match type_def.it with
| ArrayType _ -> finish_me " array handling "; assert false
| ExternalType s -> (
let lid = Lv6Id.make_long pack_name s in
let idref = Lv6Id.idref_of_long lid in
try
Abstract_type_eff (lid, id_solver.id2type idref lxm)
with _e ->
External_type_eff (lid)
)
| AliasedType (_s, texp) -> Ast2lic.of_type id_solver texp
| EnumType (s, clst) -> (
let n = Lv6Id.make_long pack_name s in
let add_pack_name x = Lv6Id.make_long pack_name x.it in
Enum_type_eff (n, List.map add_pack_name clst)
)
| StructType sti -> (
let make_field (fname : Lv6Id.t) =
let field_def = Hashtbl.find sti.st_ftable fname in
let teff = Ast2lic.of_type id_solver field_def.it.fd_type in
match field_def.it.fd_value with
| None -> (fname, (teff, None))
| Some vexp -> (
let veff = EvalConst.f id_solver vexp in
match veff with
| [v] -> (
let tv = Lic.type_of_const v in
if (tv = teff) then (fname, (teff, Some v)) else
raise
(Compile_error(field_def.src, Printf.sprintf
" this field is declared as '%s' but evaluated as '%s'"
(Lic.string_of_type teff)
(Lic.string_of_type tv)))
)
| [] -> assert false (* should not occur *)
| _::_ ->
raise (Compile_error(field_def.src,
"bad field value: tuple not allowed"))
)
in
let n = Lv6Id.make_long pack_name sti.st_name in
let eff_fields = List.map make_field sti.st_flist in
Struct_type_eff (n, eff_fields)
)
in
type_eff
)
with
(* capte et complete/stoppe les recursions *)
Recursion_error (root, stack) ->
if (root = type_name) then recursion_error type_def.src stack else
raise ( Recursion_error (root, ("type ref "^(Lxm.details lxm))::stack))
and (const_check_do : t -> Lv6Id.long -> Lxm.t -> AstTabSymbol.t -> bool ->
Lv6Id.pack_name -> AstCore.const_info srcflagged ->
Lic.const) =
fun this cn lxm symbols provide_flag currpack const_def ->
(* [cn] and [lxm] are used for recursion errors.
[symbols] is the current symbol table.
*)
try (
(* Solveur d'idref pour les les appels eval_type/eval_const *)
let id_solver = {
id2var = (fun _idref _lxm -> assert false (* should not occur *));
id2const = solve_const_idref this symbols provide_flag currpack;
id2type = solve_type_idref this symbols provide_flag currpack;
id2node = solve_node_idref this symbols provide_flag currpack;
global_symbols = symbols;
all_srcs = this.src_tab;
}
in
let const_eff =
match const_def.it with
| ExternalConst (id, texp, val_opt) ->
let lid = Lv6Id.make_long currpack id in
let teff = Ast2lic.of_type id_solver texp in
if provide_flag then
match val_opt with
| None ->
(* we put a fake value here as we don't know yet the
concrete value. this will be filled in
const_check_interface_do. I could have put an option
type, but that would make quite a lot of noise in the
remaining...
*)
Abstract_const_eff(lid, teff, Int_const_eff ("-666"), false)
| Some c ->
let ceff = match EvalConst.f id_solver c with
| [ceff] -> ceff
| _ -> assert false
in
Abstract_const_eff(lid, teff, ceff, true)
else
(match val_opt with
| None -> Extern_const_eff(lid, teff)
| Some _c -> assert false
(* indeed, how can a body constant be extern and have a value? *)
)
| EnumConst (id, texp) ->
Enum_const_eff ((Lv6Id.make_long currpack id),
Ast2lic.of_type id_solver texp)
| DefinedConst (_id, texp_opt, vexp ) -> (
match (EvalConst.f id_solver vexp) with
| [ceff] -> (
match texp_opt with
| None -> ceff
| Some texp -> (
let tdecl = Ast2lic.of_type id_solver texp in
let teff = Lic.type_of_const ceff in
if (tdecl = teff ) then ceff else
raise
(Compile_error (const_def.src, Printf.sprintf
" this constant is declared as '%s' but evaluated as '%s'"
(Lic.string_of_type tdecl)
(Lic.string_of_type teff)
)))
)
| [] -> assert false (* should not occur *)
| _::_ -> raise (Compile_error(const_def.src,
"bad constant value: tuple not allowed"))
)
in
const_eff
) with Recursion_error (root, stack) -> (
(* capte et complete/stoppe les recursions *)
if (root = cn) then recursion_error const_def.src stack else
(* on complete la stack *)
raise (Recursion_error (root, ("const ref "^(Lxm.details lxm))::stack))
)
(******************************************************************************)
and (node_check_interface_do: t -> Lic.node_key -> Lxm.t ->
AstTabSymbol.t -> Lv6Id.pack_name -> AstCore.node_info srcflagged ->
Lic.node_exp) =
fun this nk lxm symbols pn node_def ->
(* DEUX checks :
- le "complet" donne 'body_node_exp_eff' qui sera stock comme le vrai rsultat
- le "provide" donne 'prov_node_exp_eff', non stock, sert vrifier la
cohrence avec l'ventuelle dclaration 'provide'
*)
let body_node_exp_eff = node_check this nk lxm in
let prov_node_exp_eff = node_check_do this nk lxm symbols true pn node_def in
(* [type_eff_are_compatible t1 t2] checks that t1 is compatible with t2, i.e.,
if t1 = t2 or t1 is abstract and and t2.
*)
let msg_prefix =
("provided node for " ^ (Lv6Id.string_of_long false (fst nk)) ^
" is not compatible with its implementation: ")
in
let str_of_var = Lic.string_of_var_info in
let type_is_not_comp v1 v2 = not (Lic.var_are_compatible v1 v2) in
(* Checking the type profile (w.r.t the body and the provided part) *)
let ibtypes = List.map (fun v -> v.var_type_eff) body_node_exp_eff.inlist_eff
and iptypes = List.map (fun v -> v.var_type_eff) prov_node_exp_eff.inlist_eff
and obtypes = List.map (fun v -> v.var_type_eff) body_node_exp_eff.outlist_eff
and optypes = List.map (fun v -> v.var_type_eff) prov_node_exp_eff.outlist_eff
in
let _topt = UnifyType.profile_is_compatible nk
node_def.src (iptypes,ibtypes) (optypes,obtypes)
in
if
prov_node_exp_eff.node_key_eff <> body_node_exp_eff.node_key_eff
then
raise(Compile_error (node_def.src, msg_prefix ^ " ??? "))
else if
(* ougth to be checked above: well, it eats no bread to keep that check *)
(List.exists2 type_is_not_comp
prov_node_exp_eff.inlist_eff body_node_exp_eff.inlist_eff)
then
let msg = msg_prefix ^ "bad input profile. \n*** " ^
(String.concat "*" (List.map str_of_var prov_node_exp_eff.inlist_eff)) ^
" <> " ^
(String.concat "*" (List.map str_of_var body_node_exp_eff.inlist_eff))
in
raise(Compile_error (node_def.src, msg))
else if
(List.exists2 type_is_not_comp
prov_node_exp_eff.outlist_eff body_node_exp_eff.outlist_eff)
(* ougth to be checked above: well, it eats no bread to keep that check *)
then
let msg = msg_prefix ^ "bad output profile. \n*** " ^
(String.concat "*" (List.map str_of_var prov_node_exp_eff.outlist_eff)) ^
" <> " ^
(String.concat "*" (List.map str_of_var body_node_exp_eff.outlist_eff))
in
raise(Compile_error (node_def.src, msg))
else if
prov_node_exp_eff.has_mem_eff <> body_node_exp_eff.has_mem_eff
then
raise(Compile_error (node_def.src, msg_prefix ^ " node or function?"))
else if
prov_node_exp_eff.is_safe_eff <> body_node_exp_eff.is_safe_eff
then
raise(Compile_error (node_def.src, msg_prefix ^ "safe or unsafe?"))
else if
match prov_node_exp_eff.def_eff, body_node_exp_eff.def_eff with
| (AbstractLic _,_) -> false
| (_,_) -> prov_node_exp_eff.def_eff <> body_node_exp_eff.def_eff
then
raise(Compile_error (node_def.src, msg_prefix ^ "abstract or not?"))
else
match prov_node_exp_eff.def_eff, body_node_exp_eff.def_eff with
| AbstractLic None, BodyLic _node_body ->
{ prov_node_exp_eff with def_eff =
AbstractLic (Some body_node_exp_eff) }
| _,_ ->
prov_node_exp_eff
(*
LE GROS DU BOULOT
- suivant "provide_flag" : check d'interface (provide) ou le check
de la dfinition
(n.b. provide_flag influence la rsolution des idents dans l'env local de check)
*)
and node_check_do
(this: t)
(nk: Lic.node_key)
(lxm: Lxm.t)
(symbols: AstTabSymbol.t)
(provide_flag: bool)
(pack_name: Lv6Id.pack_name)
(node_def: AstCore.node_info srcflagged)
: Lic.node_exp =
(* START node_check_do *)
profile_info "node_check_do\n";
(
Lv6Verbose.exe ~flag:dbg (fun () -> Printf.printf
"#DBG: ENTERING node_check_do '%s'\n (%s)\n"
(Lic.string_of_node_key nk)
(Lxm.details lxm)
);
let lxm = node_def.src in
(* Creates a local_env with just the global bindings,
local bindinds will be added later (side effect)
*)
let local_env = make_local_env nk in
let _ =
Lv6Verbose.exe ~flag:dbg (fun () ->
Printf.printf "# local_env while entering (node_check_do %s):\n"
(Lic.string_of_node_key nk);
IdSolver.dump_local_env stderr local_env;
flush stdout
)
in
let node_id_solver = {
(* a [node_id_solver] is a [id_solver] where we begin to look
into the local environement before looking at the global
one. *)
id2var = (* var can only be local to the node *)
(fun id lxm ->
try IdSolver.lookup_var local_env id lxm
with Not_found ->
raise (Unknown_var(lxm,id))
);
id2const =
(fun id lxm ->
try IdSolver.lookup_const local_env id lxm
with Not_found ->
solve_const_idref this symbols provide_flag pack_name id lxm
);
id2type =
(fun id lxm ->
try IdSolver.lookup_type local_env id lxm
with Not_found ->
Lv6Verbose.exe ~level:3 (
fun () ->
Printf.printf "*** Dont find type %s in local_env\n"
(Lv6Id.string_of_idref false id);
Printf.printf "*** local_env.lenv_types contain def for: ";
Hashtbl.iter
(fun id _t ->
Printf.printf "%s, " (Lv6Id.to_string id) )
local_env.lenv_types;
Printf.printf "\n";
flush stdout);
solve_type_idref this symbols provide_flag pack_name id lxm);
id2node =
(fun id sargs lxm ->
(try
let (node_id,sargs) = IdSolver.lookup_node local_env id lxm in
let node_id = Lv6Id.idref_of_long node_id in
solve_node_idref this symbols provide_flag pack_name node_id sargs lxm
(* node_check this (node_id,[]) lxm *)
with
Not_found ->
solve_node_idref this symbols provide_flag pack_name id sargs lxm
| _ -> assert false)
);
(* ATTENTION EN SE SERVANT DE CA !
ne tient pas compte des params statiques du noeud ! *)
global_symbols = symbols;
all_srcs = this.src_tab;
}
in
let make_node_eff id node_def_eff = (
(* building not aliased nodes *)
Lv6Verbose.exe ~level:3
(fun () -> Printf.printf
"*** local_env while entering (make_node_eff %s):\n" (Lv6Id.to_string id);
IdSolver.dump_local_env stderr local_env
);
(********************************************************)
(* LOCAL CONSTANTS are evaluated and added to local_env *)
(********************************************************)
(* init intermediate table *)
let sz = List.length node_def.it.loc_consts in
let temp_const_eff_tab : (Lv6Id.long, Lic.const Lic.check_flag) Hashtbl.t =
Hashtbl.create sz
in
let temp_const_def_tab :
(Lv6Id.t,(Lxm.t * AstCore.type_exp option * AstCore.val_exp)) Hashtbl.t =
Hashtbl.create sz
in
let init_local_const (lxm, cinfo) = (
match cinfo with
| DefinedConst (i,topt,ve) -> (
Lv6Verbose.printf ~level:3 " * local const %s will be treated\n" i;
Hashtbl.add temp_const_def_tab i (lxm,topt,ve)
)
| ExternalConst _
| EnumConst _ -> (
let msg = "*** abstract constant bot allowed within node "
in
raise (Compile_error(lxm, msg))
)
) in
List.iter init_local_const node_def.it.loc_consts ;
(* differs from node_id_solver only on id2const *)
let rec local_id_solver = {
id2var = node_id_solver.id2var;
id2const = local_id2const;
id2type = node_id_solver.id2type;
id2node = node_id_solver.id2node;
global_symbols = node_id_solver.global_symbols;
all_srcs = node_id_solver.all_srcs;
}
and treat_local_const id = (
Lv6Verbose.printf ~level:3 " * call treat_local_const %s\n" id;
let id_key = ("", id) in
try (
let ce = lookup_const_eff temp_const_eff_tab id_key lxm in
Lv6Verbose.exe
~level:3 (fun() -> Printf.printf
" * const %s already treated = %s\n"
id (LicDump.string_of_const_eff false ce));
ce
) with Not_found -> (
let (lxmdef, toptdef, vedef) = Hashtbl.find temp_const_def_tab id in
Lv6Verbose.printf ~level:3 " * const %s not yet treated ...\n" id ;
(* yes, not yet checked *)
Hashtbl.add temp_const_eff_tab id_key Checking ;
(* computes the value with EvalConst.f id_solver ve ... *)
let ce = match (EvalConst.f local_id_solver vedef) with
| [ceff] -> (
match toptdef with
| None -> ceff
| Some texp -> (
let tdecl = Ast2lic.of_type local_id_solver texp in
let teff = Lic.type_of_const ceff in
if (tdecl = teff ) then ceff else
raise (Compile_error (
lxmdef, Printf.sprintf
" this constant is declared as '%s' but evaluated as '%s'"
(Lic.string_of_type tdecl)
(Lic.string_of_type teff)
)))
)
| [] -> assert false (* should not occur *)
| _::_ -> raise (Compile_error(lxmdef, "bad constant value: tuple not allowed"))
in
Lv6Verbose.exe
~level:3 (fun() -> Printf.printf " * const %s evaluated to %s\n"
id (LicDump.string_of_const_eff false ce));
Hashtbl.replace temp_const_eff_tab id_key (Checked ce) ;
ce
)
)
and local_id2const idrf lxm = (
(* is id a local const ? *)
try (
(* certainly NOT if id has a pack *)
let id = if (Lv6Id.pack_of_idref idrf = None)
then Lv6Id.name_of_idref idrf
else raise Not_found
in
let ce = treat_local_const id in
ce
) with Not_found -> (
(* not a local constant -> search in global env *)
Lv6Verbose.printf ~level:3
" * %s not a local const, should be global ?"
(Lv6Id.string_of_idref false idrf);
let ce = node_id_solver.id2const idrf lxm in
Lv6Verbose.exe ~level:3 (fun() -> Printf.printf
" YES -> %s\n" (LicDump.string_of_const_eff false ce));
ce
)
) in
(* iters local_id2const n eeach declared constant *)
Hashtbl.iter (fun id _ -> let _ = treat_local_const id in ())
temp_const_def_tab ;
(* Finally, adds each local const to ICI *)
let add_local_const idref ceck = (
Lv6Verbose.exe
~level:3
(fun() -> Printf.printf
" * add_local_const %s = %s\n" (snd idref)
(match ceck with
| Checking -> "Checking"
| Checked ce -> (LicDump.string_of_const_eff false ce)
| Incorrect -> "Incorrect"
));
match ceck with
| Checked ce -> Hashtbl.add local_env.lenv_const (snd idref) ce
| _ -> assert false
) in
Hashtbl.iter add_local_const temp_const_eff_tab ;
(********************************************************)
(* LOCAL FLOWS are added to local_env *)
(********************************************************)
(* (i.e. ins,outs,locs) *)
match node_def.it.vars with
| None -> assert false (* a node with a body should have a profile *)
| Some vars ->
(* let is_polymorphic = ref false in *)
let type_args id =
let vi = find_var_info lxm vars id in
let t_eff = Ast2lic.of_type node_id_solver vi.it.var_type in
(* let _ = if Lic.is_polymorphic t_eff then is_polymorphic := true in *)
let c_eff = Ast2lic.of_clock node_id_solver vi.it in
let vi_eff = {
var_name_eff = vi.it.var_name;
var_nature_eff = vi.it.var_nature;
var_number_eff = vi.it.var_number;
var_type_eff = t_eff;
var_clock_eff = c_eff;
}
in
Hashtbl.add local_env.lenv_types id t_eff;
Hashtbl.add local_env.lenv_vars id vi_eff;
vi_eff
in
let vars_in_sorted = sort_vars lxm vars vars.inlist
and vars_out_sorted = sort_vars lxm vars vars.outlist in
let inlist = List.map type_args vars_in_sorted
and outlist = List.map type_args vars_out_sorted
and loclist =
match vars.loclist with
| None -> None
| Some loclist ->
let vars_loc_sorted = sort_vars lxm vars loclist in
Some (List.map type_args vars_loc_sorted)
in
let unsort l_id l_vi =
let tab = List.map (fun vi -> vi.var_name_eff, vi) l_vi in
try List.map (fun id -> List.assoc id tab) l_id
with Not_found -> assert false
in
profile_info "LicTab.unsort\n";
let inlist2 = unsort vars.inlist inlist
and outlist2 = unsort vars.outlist outlist in
{
node_key_eff = nk;
inlist_eff = inlist2;
outlist_eff = outlist2;
loclist_eff = loclist;
def_eff = node_def_eff ();
has_mem_eff = node_def.it.has_mem;
is_safe_eff = node_def.it.is_safe;
lxm = node_def.src;
(* is_polym_eff = !is_polymorphic *)
}
) in
(* let's go *)
let res =
match node_def.it.def with
| Abstract -> make_node_eff node_def.it.name (fun () -> AbstractLic None)
| Extern -> make_node_eff node_def.it.name (fun () -> ExternLic)
| Body nb ->
make_node_eff node_def.it.name (
(fun () -> (* trick to force to delay this evaluation
after the local_env.lenv_vars has been
filled
*)
let eq_eff = List.map (Ast2lic.of_eq node_id_solver) nb.eqs in
BodyLic {
asserts_eff =
List.map (Ast2lic.of_assertion node_id_solver) nb.asserts;
eqs_eff = eq_eff;
}
)
)
| Alias({it= alias;src=lxm}) -> (
let aliased_node =
match alias with
(* 12/07 SOLUTION INTERMEDIAIRE
- les macros predefs sont traites comme des call
*)
| Predef_n(op) ->
let predef_op = op.it in
let _ = match predef_op with
| AstPredef.NOR_n
| AstPredef.DIESE_n ->
raise (Compile_error (lxm, "Can not alias 'nor' nor '#', sorry"))
| _ -> ()
in
let predef_op_eff = LicEvalType.make_node_exp_eff
node_id_solver (Some node_def.it.has_mem)
true predef_op lxm
in
predef_op_eff
| CALL_n(node_alias) ->
Ast2lic.of_node node_id_solver node_alias
| (ARRAY_SLICE_n _|ARRAY_ACCES_n _|STRUCT_ACCESS_n _
|IDENT_n _|ARRAY_n|HAT_n|CONCAT_n|WITH_n(_)|TUPLE_n|WHEN_n _
|CURRENT_n|FBY_n|ARROW_n|PRE_n)
->
raise (Compile_error (lxm, "can not alias this operator, sorry"))
(* does it make sense to alias when, pre, etc? *)
in
let (vil, vol) =
match node_def.it.vars with
| None -> aliased_node.inlist_eff, aliased_node.outlist_eff
| Some (vars) ->
(* a type profile is declared; let's check there are compatible *)
let (il,ol) = profile_of_node_exp aliased_node in
let (il_decl, ol_decl) =
let vi_il, vi_ol =
List.map (fun id -> find_var_info lxm vars id) vars.AstCore.inlist,
List.map (fun id -> find_var_info lxm vars id) vars.AstCore.outlist
in
let aux vi = Ast2lic.of_type node_id_solver vi.it.var_type in
let (il_decl, ol_decl) = List.map aux vi_il, List.map aux vi_ol in
let i_unif_res = UnifyType.f il_decl il
and o_unif_res = UnifyType.f ol_decl ol
in
(match i_unif_res with
| UnifyType.Ko msg -> raise(Compile_error(lxm, msg))
| UnifyType.Equal -> ()
| UnifyType.Unif _t -> ()
(* Ast2lic.dump_polymorphic_nodes t *)
);
(match o_unif_res with
| UnifyType.Ko msg -> raise(Compile_error (lxm, msg))
| UnifyType.Equal -> ()
| UnifyType.Unif _t -> ()
(* Ast2lic.dump_polymorphic_nodes t *)
);
(* ok, there are compatible. We use the declared profile. *)
(il_decl, ol_decl)
in
let instanciate_var_info vi t = { vi with var_type_eff = t } in
let vil = List.map2 instanciate_var_info aliased_node.inlist_eff
il_decl
and vol = List.map2 instanciate_var_info aliased_node.outlist_eff
ol_decl in
vil,vol
in
let (alias_node : Lic.node_exp) =
try make_alias_node aliased_node nk local_env node_id_solver
vil vol node_def.src
with Not_found -> assert false (* defense against List.assoc *)
in
alias_node
)
(* End Alias *)
in
L2lCheckOutputs.check_node res;
(* gen_code provide_flag current_env res; *)
Lv6Verbose.exe ~flag:dbg (fun() -> Printf.printf
"#DBG: EXITING node_check_do '%s'\n"
(Lic.string_of_node_key nk)
);
res
)
(*END node_check_do *)
(*
[make_alias_node aliased_node alias_nk node_id_solver_vars_opt lxm]
builds a node that calls the aliased node. It looks like:
node alias_node(ins) returns (outs);
let
outs = aliased_node(ins);
tel
When instanciating models with polymorphic operators, it
may happen that some exported user nodes become
polymorphic (via node alias precisely). But in that case,
a non-polymorphic profile is given in the package provided
part. In such a case, we can use the types of the provided
part (itl and otl) instead of the polymorphic ones. *)
and make_alias_node
(aliased_node: node_exp)
(alias_nk: node_key)
(local_env: local_env)
(_node_id_solver: IdSolver.t)
(vil: var_info list)
(vol: var_info list)
(lxm: Lxm.t)
: node_exp
=
Lv6Verbose.printf ~level:3
"*** Lic.make_alias_node %s \n" (Lv6Id.string_of_long false (fst alias_nk));
flush stdout;
let (outs:left list) = List.map (fun vi -> LeftVarLic (vi, lxm)) vol in
let tl = List.map type_of_left outs in
let cl = List.map (fun l -> (var_info_of_left l).var_clock_eff) outs in
let (aliased_node_call : val_exp) =
{ ve_core =
CallByPosLic(
(Lxm.flagit (CALL(Lxm.flagit aliased_node.node_key_eff lxm)) lxm,
(List.map
(fun vi -> (* build operands*)
let ve = {
ve_typ = [vi.var_type_eff];
ve_clk = [snd vi.var_clock_eff];
ve_core = CallByPosLic(
Lxm.flagit (VAR_REF(vi.var_name_eff)) lxm, []);
ve_src = lxm
}
in
ve
)
vil)));
ve_typ = tl;
ve_clk = List.map snd cl;
ve_src = lxm
}
in
let alias_node =
match aliased_node.def_eff with
| BodyLic _ -> { aliased_node with node_key_eff = alias_nk }
| _ -> {
aliased_node with
node_key_eff = alias_nk;
inlist_eff = vil;
outlist_eff = vol;
loclist_eff = None;
def_eff = BodyLic(
{ asserts_eff = [];
eqs_eff = [Lxm.flagit (outs, aliased_node_call) lxm]
});
(* is_polym_eff = List.exists is_polymorphic (List.map (fun vi
-> vi.var_type_eff) (vil@vol)); *)
}
in
(* update the local_env table *)
let _ =
let update_local_env_table vi =
Hashtbl.add local_env.lenv_vars vi.var_name_eff vi
in
List.iter update_local_env_table alias_node.inlist_eff;
List.iter update_local_env_table alias_node.outlist_eff;
match alias_node.loclist_eff with
None -> () | Some l -> List.iter update_local_env_table l;
in
alias_node
(** builds a [node_key] and calls [node_check] *)
and solve_node_idref
(this: t)
(symbols: AstTabSymbol.t)
(provide_flag: bool)
(currpack: Lv6Id.pack_name)
(idr: Lv6Id.idref)
(sargs: Lic.static_arg list)
(lxm: Lxm.t)
: Lic.node_exp =
solve_x_idref
node_check_interface node_check AstTabSymbol.find_node "node"
(fun p id ->
(* builds a [node_key] from a [pack_name] and a [node] id,
and a Lic.static_arg list *)
let long = Lv6Id.make_long p id in
let node_key = long, sargs in
node_key
)
this symbols provide_flag currpack idr sargs lxm
and node_check (this: t) (nk: Lic.node_key) (lxm: Lxm.t) : Lic.node_exp =
Lv6Verbose.printf ~flag:dbg
"#DBG: licTab.node_check '%s'\n" (Lic.string_of_node_key nk);
try (
let pack_of_x_key = fun nk -> Lv6Id.pack_of_long (fst nk) in
let name_of_x_key = fun nk -> Lv6Id.of_long (fst nk) in
x_check this.nodes AstTabSymbol.find_node node_check_do
node_builtin lookup_node_exp_eff
pack_of_x_key
name_of_x_key
this nk lxm
) with
Recursion_error (n, stack) ->
let msg = "Recursion loop detected in node " ^
(Lv6Id.string_of_long false (fst nk)) in
let msg = msg ^ "\n*** "^ (Lv6Id.string_of_long false n) ^
" depends on itself\n " ^ (String.concat "\n*****" stack) in
raise (Compile_error (lxm, msg))
and node_check_interface
(this: t)
(nk: Lic.node_key)
(lxm: Lxm.t)
: Lic.node_exp =
Lv6Verbose.printf ~flag:dbg "#DBG: licTab.node_check_interface '%s'\n"
(Lic.string_of_node_key nk);
x_check_interface this.prov_nodes AstTabSymbol.find_node node_check
node_check_interface_do node_builtin lookup_node_exp_eff
(fun nk -> Lv6Id.pack_of_long (fst nk))
(fun nk -> Lv6Id.of_long (fst nk)) this nk
lxm
(*-------------------------------------------------------------------------
compile all items
---------------------------------------------------------------------------*)
let compile_all_item this _label x_check_interface _string_of_x_key
_string_of_x_eff to_key id item_def =
match item_def with
| AstTabSymbol.Local _item_def ->
ignore
(x_check_interface this (to_key id) (Lxm.dummy "compile all items"))
(* Printf.printf "\t\t%s %s = %s\n" *)
(* label (string_of_x_key (to_key id)) (string_of_x_eff x_eff) *)
| AstTabSymbol.Imported(_item_def,_) -> ()
(* Printf.printf "\t\t%s %s = %s (imported)\n" *)
(* label (string_of_x_key (to_key id)) (Lv6Id.string_of_long item_def) *)
let compile_all_types pack_name this =
compile_all_item this "type" type_check_interface (Lv6Id.string_of_long false)
Lic.string_of_type (fun id -> Lv6Id.make_long pack_name id)
let compile_all_constants pack_name this =
compile_all_item this "const" const_check_interface (Lv6Id.string_of_long false)
(LicDump.string_of_const_eff true) (fun id -> Lv6Id.make_long pack_name id)
let (get_static_params : (node_info Lxm.srcflagged) AstTabSymbol.elt ->
static_param srcflagged list) =
fun node_info_flagged ->
match node_info_flagged with
| AstTabSymbol.Local nif -> nif.it.static_params
| AstTabSymbol.Imported(_id,sparams) -> sparams
let compile_all_nodes pack_name this id ni_f =
let sp = get_static_params ni_f in
if sp <> [] then () (* we need static arg to compile such kind of things *)
else
compile_all_item this "node" node_check_interface
(LicDump.string_of_node_key_rec true false)
Lic.profile_of_node_exp
(fun id -> (Lv6Id.make_long pack_name id, [])) id ni_f
(**** to_lic : translate the (finalized) internal structure
into a proper LicPrg, for forthcoming manip and other prg 2 prg
transformations
N.B. items belonging to the "Lustre" virtual pack are not
taken into account
*)
let to_lic_prg (this:t) : LicPrg.t =
(* normally, only checked and correct programs are lic'ified *)
let unflag = function Checked x -> x | _ -> assert false in
let add_item add_x k v prg =
match Lv6Id.pack_of_long k with
| "Lustre" -> prg
| _ -> add_x k (unflag v) prg
in
let add_node k v prg =
Lv6Verbose.printf ~flag:dbg "#DBG: licTab.to_lic: node key '%s'\n"
(Lic.string_of_node_key k);
match Lv6Id.pack_of_long (fst k) with
(* | "Lustre" -> prg *)
| _ -> LicPrg.add_node k (unflag v) prg
in
let res = LicPrg.empty in
let res = Hashtbl.fold (add_item LicPrg.add_type) this.types res in
let res = Hashtbl.fold (add_item LicPrg.add_const) this.consts res in
let res = Hashtbl.fold add_node this.nodes res in
res
(**** Entry points of the module :
either compile a single node or everithing ...
*)
let compile_all (this:t) : t =
let testpack pack_name = (
Lv6Verbose.printf ~level:3 " * package %s\n" (Lv6Id.pack_name_to_string pack_name);
let prov_symbols =
match AstTab.pack_prov_env this.src_tab pack_name with
| Some tab -> tab
| None -> AstTab.pack_body_env this.src_tab pack_name
in
Lv6Verbose.print_string ~level:3 "\tExported types:\n";
AstTabSymbol.iter_types prov_symbols (compile_all_types pack_name this);
flush stdout;
Lv6Verbose.print_string ~level:3 "\tExported constants:\n";
AstTabSymbol.iter_consts prov_symbols (compile_all_constants pack_name this);
flush stdout;
Lv6Verbose.print_string ~level:3 "\tExported nodes:\n";
AstTabSymbol.iter_nodes prov_symbols (compile_all_nodes pack_name this);
flush stdout
)
in
let plist = AstTab.pack_list this.src_tab in
Lv6Verbose.print_string ~level:3 "*** Dump the exported items of the packages.\n";
try
List.iter testpack plist;
this
with
Recursion_error (n, stack) ->
let msg = "Recursion loop detected in node " ^ (Lv6Id.string_of_long false n) in
let msg = msg ^ "\n*****" ^ (String.concat "\n*****" stack) in
raise (Compile_error (Lxm.dummy "", msg))
let compile_node (this:t) (main_node:Lv6Id.idref) : t =
(* la cle "absolue" du main node (pas d'args statiques) *)
let main_node_key = node_key_of_idref main_node in
profile_info "LicTab.compile_node\n";
Lv6Verbose.printf
"-- MAIN NODE: \"%s\"\n"
(LicDump.string_of_node_key_rec true false main_node_key);
let lxm = match Lv6Id.pack_of_idref main_node with
| None -> Lxm.dummy ""
| Some pn -> Lxm.dummy (Lv6Id.pack_name_to_string pn)
in
let _ = node_check this main_node_key lxm in
this