lustrec / src / compiler_common.ml @ master
History | View | Annotate | Download (10.1 KB)
1 |
(********************************************************************) |
---|---|
2 |
(* *) |
3 |
(* The LustreC compiler toolset / The LustreC Development Team *) |
4 |
(* Copyright 2012 - -- ONERA - CNRS - INPT *) |
5 |
(* *) |
6 |
(* LustreC is free software, distributed WITHOUT ANY WARRANTY *) |
7 |
(* under the terms of the GNU Lesser General Public License *) |
8 |
(* version 2.1. *) |
9 |
(* *) |
10 |
(********************************************************************) |
11 |
|
12 |
open Utils |
13 |
open Format |
14 |
open Lustre_types |
15 |
open Corelang |
16 |
|
17 |
let check_main () = |
18 |
if !Options.main_node = "" then |
19 |
begin |
20 |
eprintf "Code generation error: %a@." Error.pp_error_msg Error.No_main_specified; |
21 |
raise (Error (Location.dummy_loc, Error.No_main_specified)) |
22 |
end |
23 |
|
24 |
let create_dest_dir () = |
25 |
begin |
26 |
if not (Sys.file_exists !Options.dest_dir) then |
27 |
begin |
28 |
Log.report ~level:1 (fun fmt -> fprintf fmt ".. creating destination directory@ "); |
29 |
Unix.mkdir !Options.dest_dir (Unix.stat ".").Unix.st_perm |
30 |
end; |
31 |
if (Unix.stat !Options.dest_dir).Unix.st_kind <> Unix.S_DIR then |
32 |
begin |
33 |
eprintf "Failure: destination %s is not a directory.@.@." !Options.dest_dir; |
34 |
exit 1 |
35 |
end |
36 |
end |
37 |
|
38 |
(* Loading Lusi file and filling type tables with parsed |
39 |
functions/nodes *) |
40 |
let parse_header own filename = |
41 |
Location.set_input filename; |
42 |
let h_in = open_in filename in |
43 |
let lexbuf = Lexing.from_channel h_in in |
44 |
Location.init lexbuf filename; |
45 |
(* Parsing *) |
46 |
Log.report ~level:1 (fun fmt -> fprintf fmt ".. parsing header file %s@ " filename); |
47 |
try |
48 |
let header = Parse.header Parser_lustre.header Lexer_lustre.token lexbuf in |
49 |
(*ignore (Modules.load_header ISet.empty header);*) |
50 |
close_in h_in; |
51 |
header |
52 |
with |
53 |
| (Parse.Error err) as exc -> |
54 |
Parse.report_error err; |
55 |
raise exc |
56 |
| Corelang.Error (loc, err) as exc -> ( |
57 |
eprintf "Parsing error: %a%a@." |
58 |
Error.pp_error_msg err |
59 |
Location.pp_loc loc; |
60 |
raise exc |
61 |
) |
62 |
|
63 |
let parse_source source_name = |
64 |
(* Loading the input file *) |
65 |
Location.set_input source_name; |
66 |
let s_in = open_in source_name in |
67 |
let lexbuf = Lexing.from_channel s_in in |
68 |
Location.init lexbuf source_name; |
69 |
|
70 |
(* Parsing *) |
71 |
Log.report ~level:1 |
72 |
(fun fmt -> fprintf fmt ".. parsing source file %s@ " source_name); |
73 |
try |
74 |
let prog = Parse.prog Parser_lustre.prog Lexer_lustre.token lexbuf in |
75 |
(*ignore (Modules.load_program ISet.empty prog);*) |
76 |
close_in s_in; |
77 |
prog |
78 |
with |
79 |
| (Parse.Error err) as exc -> |
80 |
Parse.report_error err; |
81 |
raise exc |
82 |
| Corelang.Error (loc, err) as exc -> |
83 |
eprintf "Parsing error: %a%a@." |
84 |
Error.pp_error_msg err |
85 |
Location.pp_loc loc; |
86 |
raise exc |
87 |
|
88 |
let expand_automata decls = |
89 |
Log.report ~level:1 (fun fmt -> fprintf fmt ".. expanding automata@ "); |
90 |
try |
91 |
Automata.expand_decls decls |
92 |
with (Corelang.Error (loc, err)) as exc -> |
93 |
eprintf "Automata error: %a%a@." |
94 |
Error.pp_error_msg err |
95 |
Location.pp_loc loc; |
96 |
raise exc |
97 |
|
98 |
let check_stateless_decls decls = |
99 |
Log.report ~level:1 (fun fmt -> fprintf fmt ".. checking stateless/stateful status@ "); |
100 |
try |
101 |
Stateless.check_prog decls |
102 |
with (Stateless.Error (loc, err)) as exc -> |
103 |
eprintf "Stateless status error: %a%a@." |
104 |
Stateless.pp_error err |
105 |
Location.pp_loc loc; |
106 |
raise exc |
107 |
|
108 |
let force_stateful_decls decls = |
109 |
Log.report ~level:1 (fun fmt -> fprintf fmt ".. forcing stateful status@ "); |
110 |
try |
111 |
Stateless.force_prog decls |
112 |
with (Stateless.Error (loc, err)) as exc -> |
113 |
eprintf "Stateless status error: %a%a@." |
114 |
Stateless.pp_error err |
115 |
Location.pp_loc loc; |
116 |
raise exc |
117 |
|
118 |
let type_decls env decls = |
119 |
Log.report ~level:1 (fun fmt -> fprintf fmt ".. typing@ "); |
120 |
let new_env = |
121 |
begin |
122 |
try |
123 |
Typing.type_prog env decls |
124 |
with (Types.Error (loc,err)) as exc -> |
125 |
eprintf "Typing error: %a%a@." |
126 |
Types.pp_error err |
127 |
Location.pp_loc loc; |
128 |
raise exc |
129 |
end |
130 |
in |
131 |
if !Options.print_types || !Options.verbose_level > 2 then |
132 |
Log.report ~level:1 (fun fmt -> fprintf fmt "@[<v 2> %a@]@ " Corelang.pp_prog_type decls); |
133 |
new_env |
134 |
|
135 |
let clock_decls env decls = |
136 |
Log.report ~level:1 (fun fmt -> fprintf fmt ".. clock calculus@ "); |
137 |
let new_env = |
138 |
begin |
139 |
try |
140 |
Clock_calculus.clock_prog env decls |
141 |
with (Clocks.Error (loc,err)) as exc -> |
142 |
eprintf "Clock calculus error: %a%a@." Clocks.pp_error err Location.pp_loc loc; |
143 |
raise exc |
144 |
end |
145 |
in |
146 |
if !Options.print_clocks || !Options.verbose_level > 2 then |
147 |
Log.report ~level:1 (fun fmt -> fprintf fmt "@[<v 2> %a@]@ " Corelang.pp_prog_clock decls); |
148 |
new_env |
149 |
|
150 |
(* Typing/Clocking with an empty env *) |
151 |
let check_top_decls header = |
152 |
let new_tenv = type_decls Basic_library.type_env header in (* Typing *) |
153 |
let new_cenv = clock_decls Basic_library.clock_env header in (* Clock calculus *) |
154 |
header, new_tenv, new_cenv |
155 |
|
156 |
let get_envs_from_const const_decl (ty_env, ck_env) = |
157 |
(Env.add_value ty_env const_decl.const_id const_decl.const_type, |
158 |
Env.add_value ck_env const_decl.const_id (Clocks.new_var true)) |
159 |
|
160 |
let get_envs_from_consts const_decls (ty_env, ck_env) = |
161 |
List.fold_right get_envs_from_const const_decls (ty_env, ck_env) |
162 |
|
163 |
let rec get_envs_from_top_decl (ty_env, ck_env) top_decl = |
164 |
match top_decl.top_decl_desc with |
165 |
| Node nd -> (Env.add_value ty_env nd.node_id nd.node_type, |
166 |
Env.add_value ck_env nd.node_id nd.node_clock) |
167 |
| ImportedNode ind -> (Env.add_value ty_env ind.nodei_id ind.nodei_type, |
168 |
Env.add_value ck_env ind.nodei_id ind.nodei_clock) |
169 |
| Const c -> get_envs_from_const c (ty_env, ck_env) |
170 |
| TypeDef _ -> List.fold_left get_envs_from_top_decl (ty_env, ck_env) (consts_of_enum_type top_decl) |
171 |
| Open _ -> (ty_env, ck_env) |
172 |
|
173 |
(* get type and clock environments from a header *) |
174 |
let get_envs_from_top_decls header = |
175 |
List.fold_left get_envs_from_top_decl (Env.initial, Env.initial) header |
176 |
|
177 |
(* |
178 |
List.fold_right |
179 |
(fun top_decl (ty_env, ck_env) -> |
180 |
match top_decl.top_decl_desc with |
181 |
| Node nd -> (Env.add_value ty_env nd.node_id nd.node_type, |
182 |
Env.add_value ck_env nd.node_id nd.node_clock) |
183 |
| ImportedNode ind -> (Env.add_value ty_env ind.nodei_id ind.nodei_type, |
184 |
Env.add_value ck_env ind.nodei_id ind.nodei_clock) |
185 |
| Const c -> get_envs_from_const c (ty_env, ck_env) |
186 |
| TypeDef _ -> List.fold_left (fun envs top -> consts_of_enum_type top_decl |
187 |
| Open _ -> (ty_env, ck_env)) |
188 |
header |
189 |
(Env.initial, Env.initial) |
190 |
*) |
191 |
|
192 |
let generate_lusic_header destname lusic_ext = |
193 |
match !Options.output with |
194 |
| "C" -> C_backend_lusic.print_lusic_to_h destname lusic_ext |
195 |
| _ -> () |
196 |
|
197 |
|
198 |
|
199 |
let check_compatibility (prog, computed_types_env, computed_clocks_env) (header, declared_types_env, declared_clocks_env) = |
200 |
try |
201 |
(* checking defined types are compatible with declared types*) |
202 |
Typing.check_typedef_compat header; |
203 |
|
204 |
(* checking type compatibility with computed types*) |
205 |
Typing.check_env_compat header declared_types_env computed_types_env; |
206 |
|
207 |
(* checking clocks compatibility with computed clocks*) |
208 |
Clock_calculus.check_env_compat header declared_clocks_env computed_clocks_env; |
209 |
|
210 |
(* checking stateless status compatibility *) |
211 |
Stateless.check_compat header |
212 |
with |
213 |
| (Types.Error (loc,err)) as exc -> |
214 |
eprintf "Type mismatch between computed type and declared type in lustre interface file: %a%a@." |
215 |
Types.pp_error err |
216 |
Location.pp_loc loc; |
217 |
raise exc |
218 |
| Clocks.Error (loc, err) as exc -> |
219 |
eprintf "Clock mismatch between computed clock and declared clock in lustre interface file: %a%a@." |
220 |
Clocks.pp_error err |
221 |
Location.pp_loc loc; |
222 |
raise exc |
223 |
| Stateless.Error (loc, err) as exc -> |
224 |
eprintf "Stateless status mismatch between defined status and declared status in lustre interface file: %a%a@." |
225 |
Stateless.pp_error err |
226 |
Location.pp_loc loc; |
227 |
raise exc |
228 |
|
229 |
let is_stateful topdecl = |
230 |
match topdecl.top_decl_desc with |
231 |
| Node nd -> (match nd.node_stateless with Some b -> not b | None -> not nd.node_dec_stateless) |
232 |
| ImportedNode nd -> not nd.nodei_stateless |
233 |
| _ -> false |
234 |
|
235 |
(* Beware of the side effect: reads and modifies Global.(type_env/clock_env) *) |
236 |
let rec import_dependencies prog : dep_t list = |
237 |
Log.report ~level:1 (fun fmt -> fprintf fmt "@[<v 4>.. extracting dependencies"); |
238 |
let dependencies = Corelang.get_dependencies prog in |
239 |
let (compilation_deps, type_env, clock_env) = |
240 |
List.fold_left |
241 |
(fun (compilation_dep, type_env, clock_env) dep -> |
242 |
let (local, s) = Corelang.dependency_of_top dep in |
243 |
let basename = Options_management.name_dependency (local, s) in |
244 |
Log.report ~level:1 (fun fmt -> Format.fprintf fmt "@ Library %s@ " basename); |
245 |
let lusic = Modules.import_dependency dep.top_decl_loc (local, s) in |
246 |
(*Log.report ~level:1 (fun fmt -> Format.fprintf fmt "");*) |
247 |
let lusic_deps = import_dependencies lusic.Lusic.contents in |
248 |
let (lusi_type_env, lusi_clock_env) = get_envs_from_top_decls lusic.Lusic.contents in |
249 |
let is_stateful = List.exists is_stateful lusic.Lusic.contents in |
250 |
let new_dep = Dep (local, s, lusic.Lusic.contents, is_stateful ) in |
251 |
new_dep::lusic_deps@compilation_dep, |
252 |
Env.overwrite type_env lusi_type_env, |
253 |
Env.overwrite clock_env lusi_clock_env) |
254 |
([], !Global.type_env, !Global.clock_env) |
255 |
dependencies in |
256 |
Global.type_env := type_env; |
257 |
Global.clock_env := clock_env; |
258 |
begin |
259 |
Log.report ~level:1 (fun fmt -> fprintf fmt "@]@ "); |
260 |
compilation_deps |
261 |
end |
262 |
|
263 |
let track_exception () = |
264 |
if !Options.track_exceptions |
265 |
then (Printexc.print_backtrace stdout; flush stdout) |
266 |
else () |
267 |
|
268 |
|
269 |
let update_vdecl_parents_prog prog = |
270 |
let update_vdecl_parents parent v = |
271 |
v.var_parent_nodeid <- Some parent |
272 |
in |
273 |
List.iter ( |
274 |
fun top -> match top.top_decl_desc with |
275 |
| Node nd -> |
276 |
List.iter |
277 |
(update_vdecl_parents nd.node_id) |
278 |
(nd.node_inputs @ nd.node_outputs @ nd.node_locals ) |
279 |
| ImportedNode ind -> |
280 |
List.iter |
281 |
(update_vdecl_parents ind.nodei_id) |
282 |
(ind.nodei_inputs @ ind.nodei_outputs ) |
283 |
| _ -> () |
284 |
) prog |