2010-07-13 14:03:39 +02:00
|
|
|
open Names
|
|
|
|
open Types
|
|
|
|
open Misc
|
|
|
|
open Location
|
|
|
|
open Signature
|
|
|
|
open Modules
|
|
|
|
open Static
|
|
|
|
open Global_mapfold
|
|
|
|
open Mls_mapfold
|
|
|
|
open Minils
|
|
|
|
|
|
|
|
module Error =
|
|
|
|
struct
|
|
|
|
type error =
|
|
|
|
| Enode_unbound of longname
|
|
|
|
| Evar_unbound of name
|
|
|
|
|
|
|
|
let message loc kind =
|
|
|
|
begin match kind with
|
|
|
|
| Enode_unbound ln ->
|
|
|
|
Printf.eprintf "%aUnknown node '%s'\n"
|
|
|
|
output_location loc
|
|
|
|
(fullname ln)
|
|
|
|
| Evar_unbound n ->
|
|
|
|
Printf.eprintf "%aUnbound static var '%s'\n"
|
|
|
|
output_location loc
|
|
|
|
n
|
|
|
|
end;
|
|
|
|
raise Misc.Error
|
|
|
|
end
|
|
|
|
|
|
|
|
type info =
|
|
|
|
{ mutable opened : program NamesEnv.t;
|
|
|
|
mutable called_nodes : ((longname * static_exp list) list) LongNameEnv.t;
|
|
|
|
mutable nodes_instances : (static_exp list list) LongNameEnv.t;
|
|
|
|
mutable nodes_names : (longname * static_exp list, longname) Hashtbl.t }
|
|
|
|
|
|
|
|
let info =
|
2010-07-15 11:31:48 +02:00
|
|
|
{ (** opened programs*)
|
|
|
|
opened = NamesEnv.empty;
|
|
|
|
(** Maps a node to the list of (node name, params) it calls *)
|
2010-07-13 14:03:39 +02:00
|
|
|
called_nodes = LongNameEnv.empty;
|
2010-07-15 11:31:48 +02:00
|
|
|
(** Maps a node to its list of instances *)
|
2010-07-13 14:03:39 +02:00
|
|
|
nodes_instances = LongNameEnv.empty;
|
2010-07-15 11:31:48 +02:00
|
|
|
(** Maps a couple (node name, params) to the name of the instantiated node*)
|
2010-07-13 14:03:39 +02:00
|
|
|
nodes_names = Hashtbl.create 100 }
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** Loads the modname.epo file. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let load_object_file modname =
|
2010-07-13 15:37:29 +02:00
|
|
|
Modules.open_module modname;
|
2010-07-13 14:03:39 +02:00
|
|
|
let name = String.uncapitalize modname in
|
|
|
|
try
|
|
|
|
let filename = Modules.findfile (name ^ ".epo") in
|
|
|
|
let ic = open_in_bin filename in
|
|
|
|
try
|
|
|
|
let p:program = input_value ic in
|
|
|
|
if p.p_format_version <> minils_format_version then (
|
|
|
|
Printf.eprintf "The file %s was compiled with \
|
|
|
|
an older version of the compiler.\n \
|
|
|
|
Please recompile %s.ept first.\n" filename name;
|
|
|
|
raise Error
|
|
|
|
);
|
|
|
|
close_in ic;
|
|
|
|
info.opened <- NamesEnv.add p.p_modname p info.opened
|
|
|
|
with
|
|
|
|
| End_of_file | Failure _ ->
|
|
|
|
close_in ic;
|
|
|
|
Printf.eprintf "Corrupted object file %s.\n\
|
|
|
|
Please recompile %s.ept first.\n" filename name;
|
|
|
|
raise Error
|
|
|
|
with
|
|
|
|
| Modules.Cannot_find_file(filename) ->
|
|
|
|
Printf.eprintf "Cannot find the object file '%s'.\n"
|
|
|
|
filename;
|
|
|
|
raise Error
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** @return the node with name [ln], loading the corresponding
|
|
|
|
object file if necessary. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let node_by_longname ln =
|
|
|
|
match ln with
|
|
|
|
| Modname { qual = q; id = id } ->
|
|
|
|
if not (NamesEnv.mem q info.opened) then
|
|
|
|
load_object_file q;
|
|
|
|
(try
|
|
|
|
let p = NamesEnv.find q info.opened in
|
|
|
|
List.find (fun n -> n.n_name = id) p.p_nodes
|
|
|
|
with
|
|
|
|
Not_found -> Error.message no_location (Error.Enode_unbound ln))
|
|
|
|
| _ -> assert false
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** @return the list of nodes called by the node named [ln], with the
|
|
|
|
corresponding params (static parameters appear as free variables). *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let collect_node_calls ln =
|
2010-07-16 12:26:53 +02:00
|
|
|
let add_called_node ln params acc =
|
|
|
|
match ln with
|
|
|
|
| Modname { qual = "Pervasives" } -> acc
|
|
|
|
| _ -> (ln, params)::acc
|
|
|
|
in
|
2010-07-13 14:03:39 +02:00
|
|
|
let edesc funs acc ed = match ed with
|
|
|
|
| Eapp ({ a_op = (Enode ln | Efun ln); a_params = params }, _, _) ->
|
2010-07-16 12:26:53 +02:00
|
|
|
ed, add_called_node ln params acc
|
|
|
|
| Eiterator(_, { a_op = (Enode ln | Efun ln); a_params = params },
|
|
|
|
_, _, _) ->
|
|
|
|
ed, add_called_node ln params acc
|
2010-07-13 14:03:39 +02:00
|
|
|
| _ -> raise Misc.Fallback
|
|
|
|
in
|
2010-07-14 02:31:31 +02:00
|
|
|
let funs = { Mls_mapfold.defaults with
|
2010-07-13 14:03:39 +02:00
|
|
|
edesc = edesc } in
|
|
|
|
let n = node_by_longname ln in
|
|
|
|
let _, acc = Mls_mapfold.node_dec funs [] n in
|
|
|
|
acc
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** @return the list of nodes called by the node named [ln]. This list is
|
|
|
|
computed lazily the first time it is needed. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let called_nodes ln =
|
|
|
|
if not (LongNameEnv.mem ln info.called_nodes) then (
|
|
|
|
let called = collect_node_calls ln in
|
|
|
|
info.called_nodes <- LongNameEnv.add ln called info.called_nodes;
|
|
|
|
called
|
|
|
|
) else
|
|
|
|
LongNameEnv.find ln info.called_nodes
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** Adds a new instance of a node. [params] should not contain
|
|
|
|
any static variable. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let add_node_instance ln params =
|
|
|
|
if LongNameEnv.mem ln info.nodes_instances then
|
|
|
|
info.nodes_instances <- LongNameEnv.add ln
|
|
|
|
(params::(LongNameEnv.find ln info.nodes_instances)) info.nodes_instances
|
|
|
|
else
|
|
|
|
info.nodes_instances <- LongNameEnv.add ln [params] info.nodes_instances
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** @return the list of instances of a node. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let get_node_instances ln =
|
|
|
|
try
|
|
|
|
LongNameEnv.find ln info.nodes_instances
|
|
|
|
with
|
|
|
|
Not_found -> []
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** @return the name of the node corresponding to the instance of
|
|
|
|
[ln] with the static parameters [params]. The parameters should
|
|
|
|
be normalized using [Static.simplify] before calling this function. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let node_for_params_call ln params =
|
|
|
|
match params with
|
|
|
|
| [] -> ln
|
|
|
|
| _ -> Hashtbl.find info.nodes_names (ln,params)
|
|
|
|
|
|
|
|
let build env params_names params_values =
|
|
|
|
List.fold_left2 (fun m { p_name = n } v -> NamesEnv.add n v m)
|
|
|
|
env params_names params_values
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** Generates a fresh name for the the instance of
|
|
|
|
[ln] with the static parameters [params] and stores it. *)
|
|
|
|
let generate_new_name ln params =
|
|
|
|
match params with
|
|
|
|
| [] -> Hashtbl.add info.nodes_names (ln, params) ln
|
|
|
|
| _ ->
|
|
|
|
(match ln with
|
|
|
|
| Modname { qual = q; id = id } ->
|
|
|
|
let new_ln =
|
|
|
|
Modname { qual = q;
|
|
|
|
id = id ^ (Ident.name (Ident.fresh "")) } in
|
|
|
|
Hashtbl.add info.nodes_names (ln, params) new_ln
|
|
|
|
| _ -> assert false)
|
|
|
|
|
|
|
|
(** This module creates an instance of a node with a given
|
|
|
|
list of static parameters. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
module Instantiate =
|
|
|
|
struct
|
2010-07-15 11:31:48 +02:00
|
|
|
(** Replaces static parameters with their value in the instance. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let static_exp funs m se = match se.se_desc with
|
|
|
|
| Svar ln ->
|
|
|
|
let se = (match ln with
|
|
|
|
| Name n ->
|
|
|
|
(try NamesEnv.find n m
|
|
|
|
with Not_found ->
|
2010-07-15 11:31:48 +02:00
|
|
|
Error.message se.se_loc (Error.Evar_unbound n))
|
2010-07-13 14:03:39 +02:00
|
|
|
| Modname _ -> se) in
|
|
|
|
se, m
|
2010-07-13 15:37:29 +02:00
|
|
|
| _ -> Global_mapfold.static_exp funs m se
|
2010-07-13 14:03:39 +02:00
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** Replaces nodes call with the call to the correct instance. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let edesc funs m ed =
|
|
|
|
let ed, _ = Mls_mapfold.edesc funs m ed in
|
|
|
|
let ed = match ed with
|
|
|
|
| Eapp ({ a_op = Efun ln; a_params = params } as app, e_list, r) ->
|
2010-07-13 15:37:29 +02:00
|
|
|
let params = List.map (simplify m) params in
|
2010-07-13 14:03:39 +02:00
|
|
|
Eapp ({ app with a_op = Efun (node_for_params_call ln params);
|
|
|
|
a_params = [] }, e_list, r)
|
|
|
|
| Eapp ({ a_op = Enode ln; a_params = params } as app, e_list, r) ->
|
2010-07-13 15:37:29 +02:00
|
|
|
let params = List.map (simplify m) params in
|
2010-07-13 14:03:39 +02:00
|
|
|
Eapp ({ app with a_op = Enode (node_for_params_call ln params);
|
|
|
|
a_params = [] }, e_list, r)
|
2010-07-16 12:33:08 +02:00
|
|
|
| Eiterator(it, ({ a_op = Efun ln; a_params = params } as app),
|
|
|
|
n, e_list, r) ->
|
|
|
|
let params = List.map (simplify m) params in
|
|
|
|
Eiterator(it,
|
|
|
|
{ app with a_op = Efun
|
|
|
|
(node_for_params_call ln params);
|
|
|
|
a_params = [] }, n, e_list, r)
|
|
|
|
| Eiterator(it, ({ a_op = Enode ln; a_params = params } as app),
|
|
|
|
n, e_list, r) ->
|
|
|
|
let params = List.map (simplify m) params in
|
|
|
|
Eiterator(it,
|
|
|
|
{ app with a_op = Enode
|
|
|
|
(node_for_params_call ln params);
|
|
|
|
a_params = [] }, n, e_list, r)
|
2010-07-13 14:03:39 +02:00
|
|
|
| _ -> ed
|
|
|
|
in ed, m
|
|
|
|
|
|
|
|
let node_dec_instance modname n params =
|
2010-07-14 02:31:31 +02:00
|
|
|
let global_funs = { Global_mapfold.defaults with
|
2010-07-13 14:03:39 +02:00
|
|
|
static_exp = static_exp } in
|
2010-07-14 02:31:31 +02:00
|
|
|
let funs = { Mls_mapfold.defaults with
|
2010-07-13 14:03:39 +02:00
|
|
|
edesc = edesc;
|
|
|
|
global_funs = global_funs } in
|
|
|
|
let m = build NamesEnv.empty n.n_params params in
|
|
|
|
let n, _ = Mls_mapfold.node_dec_it funs m n in
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(* Add to the global environment the signature of the new instance *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let ln = Modname { qual = modname; id = n.n_name } in
|
|
|
|
let { info = node_sig } = find_value ln in
|
|
|
|
let node_sig, _ = Global_mapfold.node_it global_funs m node_sig in
|
2010-07-15 11:31:48 +02:00
|
|
|
let node_sig = { node_sig with node_params = [];
|
|
|
|
node_params_constraints = [] } in
|
|
|
|
(* Find the name that was associated to this instance *)
|
2010-07-13 15:37:29 +02:00
|
|
|
let ln = node_for_params_call ln params in
|
2010-07-13 14:03:39 +02:00
|
|
|
Modules.add_value_by_longname ln node_sig;
|
2010-07-15 11:31:48 +02:00
|
|
|
{ n with n_name = shortname ln;
|
|
|
|
n_params = []; n_params_constraints = []; }
|
2010-07-13 14:03:39 +02:00
|
|
|
|
|
|
|
let node_dec modname n =
|
|
|
|
let ln = Modname { qual = modname; id = n.n_name } in
|
|
|
|
List.map (node_dec_instance modname n) (get_node_instances ln)
|
|
|
|
|
|
|
|
let program p =
|
2010-07-14 02:31:31 +02:00
|
|
|
{ p
|
|
|
|
with p_nodes = List.flatten (List.map (node_dec p.p_modname) p.p_nodes) }
|
2010-07-13 14:03:39 +02:00
|
|
|
end
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** Checks that a static expression does not contain any static parameter. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let check_no_static_var se =
|
|
|
|
let static_exp_desc funs acc sed = match sed with
|
|
|
|
| Svar (Name n) -> Error.message se.se_loc (Error.Evar_unbound n)
|
|
|
|
| _ -> raise Misc.Fallback
|
|
|
|
in
|
2010-07-14 02:31:31 +02:00
|
|
|
let funs = { Global_mapfold.defaults with
|
2010-07-13 14:03:39 +02:00
|
|
|
static_exp_desc = static_exp_desc } in
|
|
|
|
ignore (Global_mapfold.static_exp_it funs false se)
|
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(** Generates the list of instances of nodes needed to call
|
|
|
|
[ln] with static parameters [params]. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let rec call_node (ln, params) =
|
2010-07-15 11:31:48 +02:00
|
|
|
(* First, add the instance for this node *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let n = node_by_longname ln in
|
|
|
|
let m = build NamesEnv.empty n.n_params params in
|
|
|
|
List.iter check_no_static_var params;
|
|
|
|
add_node_instance ln params;
|
2010-07-15 11:31:48 +02:00
|
|
|
generate_new_name ln params;
|
2010-07-13 14:03:39 +02:00
|
|
|
|
2010-07-15 11:31:48 +02:00
|
|
|
(* Recursively generate instances for called nodes. *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let call_list = called_nodes ln in
|
|
|
|
let call_list = List.map
|
2010-07-13 15:37:29 +02:00
|
|
|
(fun (ln, p) -> ln, List.map (simplify m) p) call_list in
|
2010-07-13 14:03:39 +02:00
|
|
|
List.iter call_node call_list
|
|
|
|
|
|
|
|
let program p =
|
2010-07-15 11:31:48 +02:00
|
|
|
(* Find the nodes without static parameters *)
|
2010-07-13 14:03:39 +02:00
|
|
|
let main_nodes = List.filter (fun n -> is_empty n.n_params) p.p_nodes in
|
|
|
|
let main_nodes = List.map (fun n -> (longname n.n_name, [])) main_nodes in
|
|
|
|
info.opened <- NamesEnv.add p.p_modname p NamesEnv.empty;
|
2010-07-15 11:31:48 +02:00
|
|
|
(* Creates the list of instances starting from these nodes *)
|
2010-07-13 14:03:39 +02:00
|
|
|
List.iter call_node main_nodes;
|
|
|
|
let p_list = NamesEnv.fold (fun _ p l -> p::l) info.opened [] in
|
2010-07-15 11:31:48 +02:00
|
|
|
(* Generate all the needed instances *)
|
2010-07-13 14:03:39 +02:00
|
|
|
List.map Instantiate.program p_list
|