1
|
open Format
|
2
|
|
3
|
(** Represent the possible mode for a type of a procedure parameter **)
|
4
|
type parameter_mode = AdaNoMode | AdaIn | AdaOut | AdaInOut
|
5
|
|
6
|
type kind_def = AdaType | AdaProcedure | AdaFunction | AdaPackageDecl | AdaPackageBody
|
7
|
|
8
|
type visibility = AdaNoVisibility | AdaPrivate | AdaLimitedPrivate
|
9
|
|
10
|
type printer = Format.formatter -> unit
|
11
|
|
12
|
type ada_with = (bool * (printer list) * (printer list)) option
|
13
|
|
14
|
type ada_var_decl = parameter_mode * printer * printer * ada_with
|
15
|
|
16
|
type ada_local_decl =
|
17
|
| AdaLocalVar of ada_var_decl
|
18
|
| AdaLocalPackage of (printer * printer * ((printer*printer) list))
|
19
|
|
20
|
type def_content =
|
21
|
| AdaNoContent
|
22
|
| AdaPackageContent of printer
|
23
|
| AdaSimpleContent of printer
|
24
|
| AdaVisibilityDefinition of visibility
|
25
|
| AdaProcedureContent of ((ada_local_decl list list) * (printer list))
|
26
|
| AdaRecord of ((ada_var_decl list) list)
|
27
|
| AdaPackageInstanciation of (printer * (printer * printer) list)
|
28
|
|
29
|
(** Print a parameter_mode.
|
30
|
@param fmt the formater to print on
|
31
|
@param mode the modifier
|
32
|
**)
|
33
|
let pp_parameter_mode fmt mode =
|
34
|
fprintf fmt "%s" (match mode with
|
35
|
| AdaNoMode -> ""
|
36
|
| AdaIn -> "in"
|
37
|
| AdaOut -> "out"
|
38
|
| AdaInOut -> "in out")
|
39
|
|
40
|
let pp_kind_def fmt kind_def =
|
41
|
fprintf fmt "%s" (match kind_def with
|
42
|
| AdaType -> "type"
|
43
|
| AdaProcedure -> "procedure"
|
44
|
| AdaFunction -> "function"
|
45
|
| AdaPackageDecl -> "package"
|
46
|
| AdaPackageBody -> "package body")
|
47
|
|
48
|
let pp_visibility fmt visibility =
|
49
|
fprintf fmt "%s" (match visibility with
|
50
|
| AdaNoVisibility -> ""
|
51
|
| AdaPrivate -> "private"
|
52
|
| AdaLimitedPrivate -> "limited private")
|
53
|
|
54
|
(** Print the integer type name.
|
55
|
@param fmt the formater to print on
|
56
|
**)
|
57
|
let pp_integer_type fmt = fprintf fmt "Integer"
|
58
|
|
59
|
(** Print the float type name.
|
60
|
@param fmt the formater to print on
|
61
|
**)
|
62
|
let pp_float_type fmt = fprintf fmt "Float"
|
63
|
|
64
|
(** Print the boolean type name.
|
65
|
@param fmt the formater to print on
|
66
|
**)
|
67
|
let pp_boolean_type fmt = fprintf fmt "Boolean"
|
68
|
|
69
|
let pp_group ~sep:sep pp_list fmt =
|
70
|
assert(pp_list != []);
|
71
|
fprintf fmt "@[%a@]"
|
72
|
(Utils.fprintf_list ~sep:sep (fun fmt pp->pp fmt)) pp_list
|
73
|
|
74
|
let pp_args ~sep:sep fmt = function
|
75
|
| [] -> fprintf fmt ""
|
76
|
| args -> fprintf fmt " (@[<v>%a)@]" (Utils.fprintf_list ~sep:sep (fun fmt pp->pp fmt)) args
|
77
|
|
78
|
let pp_block fmt pp_item_list =
|
79
|
fprintf fmt "%t@[<v>%a@]%t"
|
80
|
(Utils.pp_final_char_if_non_empty " " pp_item_list)
|
81
|
(Utils.fprintf_list ~sep:";@," (fun fmt pp -> pp fmt)) pp_item_list
|
82
|
(Utils.pp_final_char_if_non_empty ";@," pp_item_list)
|
83
|
|
84
|
|
85
|
let pp_ada_with fmt = function
|
86
|
| None -> fprintf fmt ""
|
87
|
| Some (ghost, pres, posts) ->
|
88
|
assert(ghost || (pres != []) || (posts != []));
|
89
|
let contract = pres@posts in
|
90
|
let pp_ghost fmt = if not ghost then fprintf fmt "" else
|
91
|
fprintf fmt " Ghost%t" (Utils.pp_final_char_if_non_empty ",@," contract)
|
92
|
in
|
93
|
let pp_aspect aspect fmt pps = if pps = [] then fprintf fmt "" else
|
94
|
fprintf fmt "%s => %t" aspect (pp_group ~sep:"@,and " pps)
|
95
|
in
|
96
|
let pp_contract fmt = if contract = [] then fprintf fmt "" else
|
97
|
let sep = if pres != [] && posts != [] then ",@," else "" in
|
98
|
fprintf fmt "@, @[<v>%a%s%a@]"
|
99
|
(pp_aspect "Pre") pres
|
100
|
sep
|
101
|
(pp_aspect "Post") posts
|
102
|
in
|
103
|
fprintf fmt " with%t%t"
|
104
|
pp_ghost
|
105
|
pp_contract
|
106
|
|
107
|
(** Print instanciation of a generic type in a new statement.
|
108
|
@param fmt the formater to print on
|
109
|
@param id id of the polymorphic type
|
110
|
@param typ the new type
|
111
|
**)
|
112
|
let pp_generic_instanciation (pp_name, pp_type) fmt =
|
113
|
fprintf fmt "%t => %t" pp_name pp_type
|
114
|
|
115
|
(** Print a variable declaration with mode
|
116
|
@param mode input/output mode of the parameter
|
117
|
@param pp_name a format printer wich print the variable name
|
118
|
@param pp_type a format printer wich print the variable type
|
119
|
@param fmt the formater to print on
|
120
|
@param id the variable
|
121
|
**)
|
122
|
let pp_var_decl (mode, pp_name, pp_type, with_statement) fmt =
|
123
|
fprintf fmt "%t: %a%s%t%a"
|
124
|
pp_name
|
125
|
pp_parameter_mode mode
|
126
|
(if mode = AdaNoMode then "" else " ")
|
127
|
pp_type
|
128
|
pp_ada_with with_statement
|
129
|
|
130
|
let apply_var_decl_lists var_list =
|
131
|
List.map (fun l-> List.map pp_var_decl l) var_list
|
132
|
|
133
|
let pp_generic fmt = function
|
134
|
| [] -> fprintf fmt ""
|
135
|
| l -> fprintf fmt "generic@,%a" pp_block l
|
136
|
|
137
|
let pp_opt intro fmt = function
|
138
|
| None -> fprintf fmt ""
|
139
|
| Some pp -> fprintf fmt " %s %t" intro pp
|
140
|
|
141
|
let rec pp_local local fmt =
|
142
|
match local with
|
143
|
| AdaLocalVar var -> pp_var_decl var fmt
|
144
|
| AdaLocalPackage (pp_name, pp_base_name, instanciations) ->
|
145
|
pp_package_instanciation pp_name pp_base_name fmt instanciations
|
146
|
and pp_content pp_name fmt = function
|
147
|
| AdaNoContent ->
|
148
|
fprintf fmt ""
|
149
|
| AdaVisibilityDefinition visbility ->
|
150
|
fprintf fmt " is %a" pp_visibility visbility
|
151
|
| AdaPackageContent pp_package ->
|
152
|
fprintf fmt " is@, @[<v>%t;@]@,end %t" pp_package pp_name
|
153
|
| AdaSimpleContent pp_content ->
|
154
|
fprintf fmt " is@, @[<v 2>(%t)@]" pp_content
|
155
|
| AdaProcedureContent (local_list, pp_instr_list) ->
|
156
|
fprintf fmt " is@,%abegin@,%aend %t"
|
157
|
pp_block (List.map (fun l -> pp_group ~sep:";@;" (List.map pp_local l)) local_list)
|
158
|
pp_block pp_instr_list
|
159
|
pp_name
|
160
|
| AdaRecord var_list ->
|
161
|
assert(var_list != []);
|
162
|
let pp_lists = apply_var_decl_lists var_list in
|
163
|
fprintf fmt " is@, @[<v>record@, @[<v>%a@]@,end record@]"
|
164
|
pp_block (List.map (pp_group ~sep:";@;") pp_lists)
|
165
|
| AdaPackageInstanciation (pp_name, instanciations) ->
|
166
|
fprintf fmt " is new %t%a"
|
167
|
pp_name
|
168
|
(pp_args ~sep:",@,") (List.map pp_generic_instanciation instanciations)
|
169
|
and pp_def fmt (pp_generics, kind_def, pp_name, args, pp_type_opt, content, pp_with_opt) =
|
170
|
let pp_arg_lists = apply_var_decl_lists args in
|
171
|
fprintf fmt "%a%a %t%a%a%a%a"
|
172
|
pp_generic pp_generics
|
173
|
pp_kind_def kind_def
|
174
|
pp_name
|
175
|
(pp_args ~sep:";@,") (List.map (pp_group ~sep:";@,") pp_arg_lists)
|
176
|
(pp_opt "return") pp_type_opt
|
177
|
(pp_content pp_name) content
|
178
|
pp_ada_with pp_with_opt
|
179
|
and pp_package_instanciation pp_name pp_base_name fmt instanciations =
|
180
|
pp_def fmt ([], AdaPackageDecl, pp_name, [], None, (AdaPackageInstanciation (pp_base_name, instanciations)), None)
|
181
|
|
182
|
(** Print the ada package introduction sentence it can be used for body and
|
183
|
declaration. Boolean parameter body should be true if it is a body delcaration.
|
184
|
@param fmt the formater to print on
|
185
|
@param fmt the formater to print on
|
186
|
@param machine the machine
|
187
|
**)
|
188
|
let pp_package pp_name pp_generics body fmt pp_content =
|
189
|
let kind = if body then AdaPackageBody else AdaPackageDecl in
|
190
|
pp_def fmt (pp_generics, kind, pp_name, [], None, (AdaPackageContent pp_content), None)
|
191
|
|
192
|
(** Print a new statement instantiating a generic package.
|
193
|
@param fmt the formater to print on
|
194
|
@param substitutions the instanciation substitution
|
195
|
@param machine the machine to instanciate
|
196
|
**)
|
197
|
|
198
|
(** Print a type declaration
|
199
|
@param fmt the formater to print on
|
200
|
@param pp_name a format printer which print the type name
|
201
|
@param pp_value a format printer which print the type definition
|
202
|
**)
|
203
|
let pp_type_decl pp_name visibility fmt =
|
204
|
pp_def fmt ([], AdaType, pp_name, [], None, AdaVisibilityDefinition visibility, None)
|
205
|
|
206
|
let pp_record pp_name fmt var_lists =
|
207
|
pp_def fmt ([], AdaType, pp_name, [], None, AdaRecord var_lists, None)
|
208
|
|
209
|
let pp_procedure pp_name args pp_with_opt fmt content =
|
210
|
pp_def fmt ([], AdaProcedure, pp_name, args, None, content, pp_with_opt)
|
211
|
|
212
|
let pp_predicate pp_name args fmt content_opt =
|
213
|
let rec quantify pp_content = function
|
214
|
| [] -> pp_content
|
215
|
| (pp_var, pp_type)::q -> fun fmt ->
|
216
|
fprintf fmt "for some %t in %t => (@, @[<v>%t@])" pp_var pp_type (quantify pp_content q)
|
217
|
in
|
218
|
let content, with_st = match content_opt with
|
219
|
| Some (locals, booleans) -> AdaSimpleContent (quantify (fun fmt -> Utils.fprintf_list ~sep:"@;and " (fun fmt pp->pp fmt) fmt booleans) locals), None
|
220
|
| None -> AdaNoContent, Some (true, [], [])
|
221
|
in
|
222
|
pp_def fmt ([], AdaFunction, pp_name, args, Some pp_boolean_type, content, with_st)
|
223
|
|
224
|
|
225
|
|
226
|
|
227
|
(** Print a cleaned an identifier for ada exportation : Ada names must not start by an
|
228
|
underscore and must not contain a double underscore
|
229
|
@param var name to be cleaned*)
|
230
|
let pp_clean_ada_identifier fmt name =
|
231
|
let reserved_words = ["abort"; "else"; "new"; "return"; "boolean"; "integer";
|
232
|
"abs"; "elsif"; "not"; "reverse"; "abstract"; "end";
|
233
|
"null"; "accept"; "entry"; "select"; "access";
|
234
|
"exception"; "of"; "separate"; "aliased"; "exit";
|
235
|
"or"; "some"; "all"; "others"; "subtype"; "and";
|
236
|
"for"; "out"; "synchronized"; "array"; "function";
|
237
|
"overriding"; "at"; "tagged"; "generic"; "package";
|
238
|
"task"; "begin"; "goto"; "pragma"; "terminate";
|
239
|
"body"; "private"; "then"; "if"; "procedure"; "type";
|
240
|
"case"; "in"; "protected"; "constant"; "interface";
|
241
|
"until"; "is"; "raise"; "use"; "declare"; " range";
|
242
|
"delay"; "limited"; "record"; "when"; "delta"; "loop";
|
243
|
"rem"; "while"; "digits"; "renames"; "with"; "do";
|
244
|
"mod"; "requeue"; "xor"; "float"] in
|
245
|
let base_size = String.length name in
|
246
|
assert(base_size > 0);
|
247
|
let rec remove_double_underscore s = function
|
248
|
| i when i == String.length s - 1 -> s
|
249
|
| i when String.get s i == '_' && String.get s (i+1) == '_' ->
|
250
|
remove_double_underscore (sprintf "%s%s" (String.sub s 0 i) (String.sub s (i+1) (String.length s-i-1))) i
|
251
|
| i -> remove_double_underscore s (i+1)
|
252
|
in
|
253
|
let name = if String.get name (base_size-1) == '_' then name^"ada" else name in
|
254
|
let name = remove_double_underscore name 0 in
|
255
|
let prefix = if String.length name != base_size
|
256
|
|| String.get name 0 == '_'
|
257
|
|| List.exists (String.equal (String.lowercase_ascii name)) reserved_words then
|
258
|
"ada"
|
259
|
else
|
260
|
""
|
261
|
in
|
262
|
fprintf fmt "%s%s" prefix name
|
263
|
|
264
|
(** Print the access of an item from an other package.
|
265
|
@param fmt the formater to print on
|
266
|
@param package the package to use
|
267
|
@param item the item which is accessed
|
268
|
**)
|
269
|
let pp_package_access (pp_package, pp_item) fmt =
|
270
|
fprintf fmt "%t.%t" pp_package pp_item
|
271
|
|
272
|
let pp_with visibility fmt pp_pakage_name =
|
273
|
fprintf fmt "%a with %t" pp_visibility visibility pp_pakage_name
|
274
|
|
275
|
(** Print a one line comment with the final new line character to avoid
|
276
|
commenting anything else.
|
277
|
@param fmt the formater to print on
|
278
|
@param s the comment without newline character
|
279
|
**)
|
280
|
let pp_oneline_comment fmt s =
|
281
|
assert (not (String.contains s '\n'));
|
282
|
fprintf fmt "-- %s@," s
|
283
|
|
284
|
let pp_call fmt (pp_name, args) =
|
285
|
fprintf fmt "%t%a"
|
286
|
pp_name
|
287
|
(pp_args ~sep:",@ ") (List.map (pp_group ~sep:",@,") args)
|
288
|
|
289
|
|
290
|
(** Print the complete name of variable.
|
291
|
@param m the machine to check if it is memory
|
292
|
@param fmt the formater to print on
|
293
|
@param var the variable
|
294
|
**)
|
295
|
let pp_access pp_state pp_var fmt =
|
296
|
fprintf fmt "%t.%t" pp_state pp_var
|
297
|
|
298
|
let pp_old pp fmt = fprintf fmt "%t'Old" pp
|
299
|
|