1
|
(********************************************************************)
|
2
|
(* *)
|
3
|
(* The LustreC compiler toolset / The LustreC Development Team *)
|
4
|
(* Copyright 2012 - -- ONERA - CNRS - INPT - ISAE-SUPAERO *)
|
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 Format
|
13
|
|
14
|
open Machine_code_types
|
15
|
open Lustre_types
|
16
|
open Corelang
|
17
|
open Machine_code_common
|
18
|
|
19
|
open Misc_printer
|
20
|
open Misc_lustre_function
|
21
|
open Ada_printer
|
22
|
open Ada_backend_common
|
23
|
|
24
|
(** Functions printing the .ads file **)
|
25
|
module Main =
|
26
|
struct
|
27
|
|
28
|
(** Print a new statement instantiating a generic package.
|
29
|
@param fmt the formater to print on
|
30
|
@param substitutions the instanciation substitution
|
31
|
@param machine the machine to instanciate
|
32
|
**)
|
33
|
let pp_new_package fmt (substitutions, machine) =
|
34
|
let pp_name = pp_package_name machine in
|
35
|
let pp_new_name = pp_package_name_with_polymorphic substitutions machine in
|
36
|
let instanciations = List.map (fun (id, typ) -> (pp_polymorphic_type id, fun fmt -> pp_type fmt typ)) substitutions in
|
37
|
pp_package_instanciation pp_new_name pp_name fmt instanciations
|
38
|
|
39
|
(** Print a precondition in aspect
|
40
|
@param fmt the formater to print on
|
41
|
@param expr the expession to print as pre
|
42
|
**)
|
43
|
let pp_pre fmt expr =
|
44
|
fprintf fmt "Pre => %a"
|
45
|
pp_clean_ada_identifier expr
|
46
|
|
47
|
(** Print a postcondition in aspect
|
48
|
@param fmt the formater to print on
|
49
|
@param expr the expession to print as pre
|
50
|
**)
|
51
|
let pp_post fmt ident =
|
52
|
fprintf fmt "Post => %a"
|
53
|
pp_clean_ada_identifier ident
|
54
|
|
55
|
(** Print the declaration of a procedure with a contract
|
56
|
@param pp_prototype the prototype printer
|
57
|
@param fmt the formater to print on
|
58
|
@param contract the contract for the function to declare
|
59
|
**)
|
60
|
let pp_contract guarantees fmt =
|
61
|
fprintf fmt "@, @[<v>Global => null%t%a@]"
|
62
|
(Utils.pp_final_char_if_non_empty ",@," guarantees)
|
63
|
(Utils.fprintf_list ~sep:",@," pp_post) guarantees
|
64
|
|
65
|
(*
|
66
|
let pp_transition_name fmt = fprintf fmt "transition"
|
67
|
let pp_state_name_transition suffix fmt = fprintf fmt "%t_%s" pp_state_name suffix
|
68
|
|
69
|
(** Printing function for basic assignement [var_name := value].
|
70
|
|
71
|
@param fmt the formater to print on
|
72
|
@param var_name the name of the variable
|
73
|
@param value the value to be assigned
|
74
|
**)
|
75
|
let pp_basic_assign m fmt var_name value =
|
76
|
fprintf fmt "%a = %a"
|
77
|
(pp_access_var m) var_name
|
78
|
(pp_value m) value
|
79
|
|
80
|
|
81
|
(** Printing function for instruction. See
|
82
|
{!type:Machine_code_types.instr_t} for more details on
|
83
|
machine types.
|
84
|
|
85
|
@param typed_submachines list of all typed machine instances of this machine
|
86
|
@param machine the current machine
|
87
|
@param fmt the formater to print on
|
88
|
@param instr the instruction to print
|
89
|
**)
|
90
|
let rec pp_machine_instr typed_submachines machine instr fmt =
|
91
|
let pp_instr = pp_machine_instr typed_submachines machine in
|
92
|
(* Print args for a step call *)
|
93
|
let pp_state i fmt = fprintf fmt "%t.%s" pp_state_name i in
|
94
|
let pp_args vl il fmt =
|
95
|
fprintf fmt "@[%a@]%t@[%a@]"
|
96
|
(Utils.fprintf_list ~sep:",@ " (pp_value machine)) vl
|
97
|
(Utils.pp_final_char_if_non_empty ",@," il)
|
98
|
(Utils.fprintf_list ~sep:",@ " pp_var_name) il
|
99
|
in
|
100
|
(* Print a when branch of a case *)
|
101
|
let pp_when (cond, instrs) fmt =
|
102
|
fprintf fmt "when %s =>@,%a" cond pp_block (List.map pp_instr instrs)
|
103
|
in
|
104
|
(* Print a case *)
|
105
|
let pp_case fmt (g, hl) =
|
106
|
fprintf fmt "case %a is@,%aend case"
|
107
|
(pp_value machine) g
|
108
|
pp_block (List.map pp_when hl)
|
109
|
in
|
110
|
(* Print a if *)
|
111
|
(* If neg is true the we must test for the negation of the condition. It
|
112
|
first check that we don't have a negation and a else case, if so it
|
113
|
inverses the two branch and remove the negation doing a recursive
|
114
|
call. *)
|
115
|
let rec pp_if neg fmt (g, instrs1, instrs2) =
|
116
|
match neg, instrs2 with
|
117
|
| true, Some x -> pp_if false fmt (g, x, Some instrs1)
|
118
|
| _ ->
|
119
|
let pp_cond =
|
120
|
if neg then
|
121
|
fun fmt x -> fprintf fmt "! (%a)" (pp_value machine) x
|
122
|
else
|
123
|
pp_value machine
|
124
|
in
|
125
|
let pp_else = match instrs2 with
|
126
|
| None -> fun fmt -> fprintf fmt ""
|
127
|
| Some i2 -> fun fmt ->
|
128
|
fprintf fmt "else@,%a" pp_block (List.map pp_instr i2)
|
129
|
in
|
130
|
fprintf fmt "if %a then@,%a%tend if"
|
131
|
pp_cond g
|
132
|
pp_block (List.map pp_instr instrs1)
|
133
|
pp_else
|
134
|
in
|
135
|
match get_instr_desc instr with
|
136
|
(* no reset *)
|
137
|
| MNoReset _ -> ()
|
138
|
(* reset *)
|
139
|
| MReset i when List.mem_assoc i typed_submachines ->
|
140
|
let (substitution, submachine) = get_instance i typed_submachines in
|
141
|
let pp_package = pp_package_name_with_polymorphic substitution submachine in
|
142
|
pp_call fmt (pp_package_access (pp_package, pp_name), [pp_state i])
|
143
|
| MLocalAssign (ident, value) ->
|
144
|
pp_basic_assign machine fmt ident value
|
145
|
| MStateAssign (ident, value) ->
|
146
|
pp_basic_assign machine fmt ident value
|
147
|
| MStep ([i0], i, vl) when is_builtin_fun i ->
|
148
|
let value = mk_val (Fun (i, vl)) i0.var_type in
|
149
|
pp_basic_assign machine fmt i0 value
|
150
|
| MStep (il, i, vl) when List.mem_assoc i typed_submachines ->
|
151
|
let (substitution, submachine) = get_instance i typed_submachines in
|
152
|
pp_package_call
|
153
|
pp_step_procedure_name
|
154
|
fmt
|
155
|
(substitution, submachine, pp_state i, Some (pp_args vl il))
|
156
|
| MBranch (_, []) -> assert false
|
157
|
| MBranch (g, (c1, i1)::tl) when c1=tag_false || c1=tag_true ->
|
158
|
let neg = c1=tag_false in
|
159
|
let other = match tl with
|
160
|
| [] -> None
|
161
|
| [(c2, i2)] -> Some i2
|
162
|
| _ -> assert false
|
163
|
in
|
164
|
pp_if neg fmt (g, i1, other)
|
165
|
| MBranch (g, hl) -> pp_case fmt (g, hl)
|
166
|
| MComment s ->
|
167
|
let lines = String.split_on_char '\n' s in
|
168
|
fprintf fmt "%a" (Utils.fprintf_list ~sep:"" pp_oneline_comment) lines
|
169
|
| _ -> assert false
|
170
|
|
171
|
(** Print the expression function representing the transition predicate.
|
172
|
@param fmt the formater to print on
|
173
|
@param machine the machine
|
174
|
**)
|
175
|
let pp_transition_predicate typed_submachines fmt (opt_spec_machine, m) =
|
176
|
let spec_instrs = match opt_spec_machine with
|
177
|
| None -> []
|
178
|
| Some m -> m.mstep.step_instrs
|
179
|
in
|
180
|
fprintf fmt "function %t (%a; %a) return Boolean is (@, @[<v>%a@,@]) with Ghost"
|
181
|
pp_transition_name
|
182
|
pp_var_decl_mode (In, pp_state_name_transition "old", pp_state_type)
|
183
|
pp_var_decl_mode (In, pp_state_name_transition "new", pp_state_type)
|
184
|
(Utils.fprintf_list ~sep:" and@," (pp_machine_instr typed_submachines m)) (m.mstep.step_instrs@spec_instrs)*)
|
185
|
|
186
|
(** Remove duplicates from a list according to a given predicate.
|
187
|
@param eq the predicate defining equality
|
188
|
@param l the list to parse
|
189
|
**)
|
190
|
let remove_duplicates eq l =
|
191
|
let aux l x = if List.exists (eq x) l then l else x::l in
|
192
|
List.fold_left aux [] l
|
193
|
|
194
|
|
195
|
(** Compare two typed machines.
|
196
|
**)
|
197
|
let eq_typed_machine (subst1, machine1) (subst2, machine2) =
|
198
|
(String.equal machine1.mname.node_id machine2.mname.node_id) &&
|
199
|
(List.for_all2 (fun a b -> pp_eq_type (snd a) (snd b)) subst1 subst2)
|
200
|
|
201
|
|
202
|
(** Print the package declaration(ads) of a machine.
|
203
|
It requires the list of all typed instance.
|
204
|
A typed submachine is a (ident, typed_machine) with
|
205
|
- ident: the name
|
206
|
- typed_machine: a (substitution, machine) with
|
207
|
- machine: the submachine struct
|
208
|
- substitution the instanciation of all its polymorphic types.
|
209
|
@param fmt the formater to print on
|
210
|
@param typed_submachines list of all typed submachines of this machine
|
211
|
@param m the machine
|
212
|
**)
|
213
|
let pp_file fmt (typed_submachines, ((opt_spec_machine, guarantees), m)) =
|
214
|
let typed_machines = snd (List.split typed_submachines) in
|
215
|
let typed_machines_set = remove_duplicates eq_typed_machine typed_machines in
|
216
|
|
217
|
let machines_to_import = List.map pp_package_name (snd (List.split typed_machines_set)) in
|
218
|
|
219
|
let polymorphic_types = find_all_polymorphic_type m in
|
220
|
|
221
|
let typed_machines_to_instanciate =
|
222
|
List.filter (fun (l, _) -> l != []) typed_machines_set in
|
223
|
|
224
|
let typed_instances = List.filter is_submachine_statefull typed_submachines in
|
225
|
|
226
|
let pp_state_decl_and_reset fmt = fprintf fmt "%t;@,@,%a;@,@,"
|
227
|
(*Declare the state type*)
|
228
|
(pp_type_decl pp_state_type AdaLimitedPrivate)
|
229
|
(*Declare the reset procedure*)
|
230
|
(pp_procedure pp_reset_procedure_name (build_pp_arg_reset m) None) AdaNoContent
|
231
|
in
|
232
|
|
233
|
let vars = List.map (build_pp_var_decl AdaNoMode) m.mmemory in
|
234
|
let states = List.map build_pp_state_decl_from_subinstance typed_instances in
|
235
|
let var_lists = (if vars = [] then [] else [vars])@(if states = [] then [] else [states]) in
|
236
|
|
237
|
let pp_private_section fmt = fprintf fmt "@,private@,@,%a%t%a"
|
238
|
(*Instantiate the polymorphic type that need to be instantiated*)
|
239
|
(Utils.fprintf_list ~sep:";@," pp_new_package) typed_machines_to_instanciate
|
240
|
(Utils.pp_final_char_if_non_empty ";@,@," typed_machines_to_instanciate)
|
241
|
(*Define the state type*)
|
242
|
(pp_record pp_state_type) var_lists
|
243
|
in
|
244
|
|
245
|
let pp_ifstatefull fmt pp =
|
246
|
if is_machine_statefull m then
|
247
|
fprintf fmt "%t" pp
|
248
|
else
|
249
|
fprintf fmt ""
|
250
|
in
|
251
|
|
252
|
let pp_content fmt =
|
253
|
let pp_contract_opt = match guarantees with
|
254
|
| [] -> None
|
255
|
| _ -> Some (pp_contract guarantees) in
|
256
|
fprintf fmt "%a%a%a%a" (* %a;@, *)
|
257
|
pp_ifstatefull pp_state_decl_and_reset
|
258
|
|
259
|
(*Declare the transition predicate*)
|
260
|
(* pp_transition_predicate typed_submachines) (opt_spec_machine, m) *)
|
261
|
|
262
|
(*Declare the step procedure*)
|
263
|
(pp_procedure pp_step_procedure_name (build_pp_arg_step m) pp_contract_opt) AdaNoContent
|
264
|
|
265
|
pp_ifstatefull (fun fmt -> fprintf fmt ";@,")
|
266
|
|
267
|
(*Print the private section*)
|
268
|
pp_ifstatefull pp_private_section
|
269
|
in
|
270
|
|
271
|
let pp_poly_types id = pp_type_decl (pp_polymorphic_type id) AdaPrivate in
|
272
|
let pp_generics = List.map pp_poly_types polymorphic_types in
|
273
|
|
274
|
fprintf fmt "@[<v>%a%t%a;@]@."
|
275
|
|
276
|
(* Include all the subinstance package*)
|
277
|
(Utils.fprintf_list ~sep:";@," (pp_with AdaPrivate)) machines_to_import
|
278
|
(Utils.pp_final_char_if_non_empty ";@,@," machines_to_import)
|
279
|
|
280
|
(*Begin the package*)
|
281
|
(pp_package (pp_package_name m) pp_generics false) pp_content
|
282
|
|
283
|
end
|