1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
|
(***********************************************************************)
(* *)
(* Objective Caml *)
(* *)
(* Jerome Vouillon, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 1996 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
(***********************************************************************)
(* $Id$ *)
open Misc
open Asttypes
open Types
open Typedtree
open Lambda
open Translobj
open Translcore
(* XXX Rajouter des evenements... *)
type error = Illegal_class_expr
exception Error of Location.t * error
let lfunction params body =
match body with
Lfunction (Curried, params', body') ->
Lfunction (Curried, params @ params', body')
| _ ->
Lfunction (Curried, params, body)
let lapply func args =
match func with
Lapply(func', args') ->
Lapply(func', args' @ args)
| _ ->
Lapply(func, args)
let lsequence l1 l2 =
if l2 = lambda_unit then l1 else Lsequence(l1, l2)
let transl_label l = Lconst (Const_base (Const_string l))
let rec transl_meth_list lst =
Lconst
(List.fold_right
(fun lab rem -> Const_block (0, [Const_base (Const_string lab); rem]))
lst (Const_pointer 0))
let set_inst_var obj id expr =
let kind = if Typeopt.maybe_pointer expr then Paddrarray else Pintarray in
Lprim(Parraysetu kind, [Lvar obj; Lvar id; transl_exp expr])
let copy_inst_var obj id expr templ offset =
let kind = if Typeopt.maybe_pointer expr then Paddrarray else Pintarray in
let id' = Ident.create (Ident.name id) in
Llet(Strict, id', Lprim (Pidentity, [Lvar id]),
Lprim(Parraysetu kind,
[Lvar obj; Lvar id';
Lprim(Parrayrefu kind, [Lvar templ; Lprim(Paddint,
[Lvar id';
Lvar offset])])]))
let transl_val tbl create name id rem =
Llet(StrictOpt, id, Lapply (oo_prim (if create then "new_variable"
else "get_variable"),
[Lvar tbl; transl_label name]),
rem)
let transl_vals tbl create vals rem =
List.fold_right
(fun (name, id) rem -> transl_val tbl create name id rem)
vals rem
let transl_super tbl meths inh_methods rem =
List.fold_right
(fun (nm, id) rem ->
begin try
Llet(StrictOpt, id, Lapply (oo_prim "get_method",
[Lvar tbl; Lvar (Meths.find nm meths)]),
rem)
with Not_found ->
rem
end)
inh_methods rem
let create_object cl obj init =
let obj' = Ident.create "self" in
let (inh_init, obj_init) = init obj' in
(inh_init,
Llet(Strict, obj', Lifthenelse(Lvar obj, Lvar obj,
Lapply (oo_prim "create_object", [Lvar cl])),
Lsequence(obj_init,
Lsequence(Lifthenelse(Lvar obj, lambda_unit,
Lapply (oo_prim "run_initializers",
[Lvar obj'; Lvar cl])),
Lvar obj'))))
let rec build_object_init cl_table obj params inh_init cl =
match cl.cl_desc with
Tclass_ident path ->
let obj_init = Ident.create "obj_init" in
(obj_init::inh_init, Lapply(Lvar obj_init, [Lvar obj]))
| Tclass_structure str ->
create_object cl_table obj (fun obj ->
let (inh_init, obj_init) =
List.fold_right
(fun field (inh_init, obj_init) ->
match field with
Cf_inher (cl, _, _) ->
let (inh_init, obj_init') =
build_object_init cl_table obj [] inh_init cl
in
(inh_init, lsequence obj_init' obj_init)
| Cf_val (_, id, exp) ->
(inh_init, lsequence (set_inst_var obj id exp) obj_init)
| Cf_meth _ | Cf_init _ ->
(inh_init, obj_init)
| Cf_let (rec_flag, defs, vals) ->
(inh_init,
Translcore.transl_let rec_flag defs
(List.fold_right
(fun (id, expr) rem ->
lsequence (Lifused(id, set_inst_var obj id expr))
rem)
vals obj_init)))
str.cl_field
(inh_init, lambda_unit)
in
(inh_init,
List.fold_right
(fun (id, expr) rem ->
lsequence (Lifused (id, set_inst_var obj id expr)) rem)
params obj_init))
| Tclass_fun (pat, vals, cl) ->
let (inh_init, obj_init) =
build_object_init cl_table obj (vals @ params) inh_init cl
in
(inh_init,
let build params rem =
let param = name_pattern "param" [pat, ()] in
Lfunction (Curried, param::params,
Matching.for_function
pat.pat_loc None (Lvar param) [pat, rem])
in
begin match obj_init with
Lfunction (Curried, params, rem) -> build params rem
| rem -> build [] rem
end)
| Tclass_apply (cl, exprs) ->
let (inh_init, obj_init) =
build_object_init cl_table obj params inh_init cl
in
(inh_init, lapply obj_init (List.map transl_exp exprs))
| Tclass_let (rec_flag, defs, vals, cl) ->
let (inh_init, obj_init) =
build_object_init cl_table obj (vals @ params) inh_init cl
in
(inh_init, Translcore.transl_let rec_flag defs obj_init)
| Tclass_constraint (cl, vals, pub_meths, concr_meths) ->
build_object_init cl_table obj params inh_init cl
let rec build_object_init_0 cl_table params cl =
match cl.cl_desc with
Tclass_let (rec_flag, defs, vals, cl) ->
let (inh_init, obj_init) =
build_object_init_0 cl_table (vals @ params) cl
in
(inh_init, Translcore.transl_let rec_flag defs obj_init)
| _ ->
let obj = Ident.create "self" in
let (inh_init, obj_init) = build_object_init cl_table obj params [] cl in
let obj_init = lfunction [obj] obj_init in
(inh_init, obj_init)
let bind_method tbl public_methods lab id cl_init =
if List.mem lab public_methods then
Llet(Alias, id, Lvar (meth lab), cl_init)
else
Llet(StrictOpt, id, Lapply (oo_prim "get_method_label",
[Lvar tbl; transl_label lab]),
cl_init)
let bind_methods tbl public_methods meths cl_init =
Meths.fold (bind_method tbl public_methods) meths cl_init
let rec build_class_init cla pub_meths cstr inh_init cl_init cl =
match cl.cl_desc with
Tclass_ident path ->
begin match inh_init with
obj_init::inh_init ->
(inh_init,
Llet (Strict, obj_init,
Lapply(Lprim(Pfield 1, [transl_path path]), [Lvar cla]),
cl_init))
| _ ->
assert false
end
| Tclass_structure str ->
let (inh_init, cl_init) =
List.fold_right
(fun field (inh_init, cl_init) ->
match field with
Cf_inher (cl, vals, meths) ->
build_class_init cla pub_meths false inh_init
(transl_vals cla false vals
(transl_super cla str.cl_meths meths cl_init))
cl
| Cf_val (name, id, exp) ->
(inh_init, transl_val cla true name id cl_init)
| Cf_meth (name, exp) ->
let met = Ident.create ("method_" ^ name) in
(inh_init,
Lsequence(Lapply (oo_prim "set_method",
[Lvar cla;
Lvar (Meths.find name str.cl_meths);
Llet(Strict, met, transl_exp exp,
Lvar met)]),
cl_init))
| Cf_let (rec_flag, defs, vals) ->
let vals =
List.map (function (id, _) -> (Ident.name id, id)) vals
in
(inh_init, transl_vals cla true vals cl_init)
| Cf_init exp ->
(inh_init,
Lsequence(Lapply (oo_prim "add_initializer",
[Lvar cla; transl_exp exp]),
cl_init)))
str.cl_field
(inh_init, cl_init)
in
(inh_init, bind_methods cla pub_meths str.cl_meths cl_init)
| Tclass_fun (pat, vals, cl) ->
let (inh_init, cl_init) =
build_class_init cla pub_meths cstr inh_init cl_init cl
in
let vals = List.map (function (id, _) -> (Ident.name id, id)) vals in
(inh_init, transl_vals cla true vals cl_init)
| Tclass_apply (cl, exprs) ->
build_class_init cla pub_meths cstr inh_init cl_init cl
| Tclass_let (rec_flag, defs, vals, cl) ->
let (inh_init, cl_init) =
build_class_init cla pub_meths cstr inh_init cl_init cl
in
let vals = List.map (function (id, _) -> (Ident.name id, id)) vals in
(inh_init, transl_vals cla true vals cl_init)
| Tclass_constraint (cl, vals, meths, concr_meths) ->
let core cl_init =
build_class_init cla pub_meths true inh_init cl_init cl
in
if cstr then
core cl_init
else
let virt_meths =
List.fold_right
(fun lab rem ->
if Concr.mem lab concr_meths then rem else lab::rem)
meths
[]
in
let (inh_init, cl_init) =
core (Lsequence (Lapply (oo_prim "widen", [Lvar cla]),
cl_init))
in
(inh_init,
Lsequence(Lapply (oo_prim "narrow",
[Lvar cla;
transl_meth_list vals;
transl_meth_list virt_meths;
transl_meth_list (Concr.elements concr_meths)]),
cl_init))
(*
XXX Il devrait etre peu couteux d'ecrire des classes :
class c x y = d e f
*)
(*
XXX
Exploiter le fait que les methodes sont definies dans l'ordre pour
l'initialisation des classes (et les variables liees par un
let ???) ?
*)
let transl_class ids cl_id arity pub_meths cl =
let cla = Ident.create "class" in
let (inh_init, obj_init) = build_object_init_0 cla [] cl in
if not (Translcore.check_recursive_lambda ids obj_init) then
raise(Error(cl.cl_loc, Illegal_class_expr));
let (inh_init, cl_init) =
build_class_init cla pub_meths true (List.rev inh_init) obj_init cl
in
assert (inh_init = []);
let table = Ident.create "table" in
let class_init = Ident.create "class_init" in
let obj_init = Ident.create "obj_init" in
Llet(Strict, table,
Lapply (oo_prim "create_table", [transl_meth_list pub_meths]),
Llet(Strict, class_init,
Lfunction(Curried, [cla], cl_init),
Llet(Strict, obj_init, Lapply(Lvar class_init, [Lvar table]),
Lsequence(Lapply (oo_prim "init_class", [Lvar table]),
Lprim(Pmakeblock(0, Immutable),
[Lvar obj_init;
Lvar class_init;
Lvar table])))))
let class_stub =
Lprim(Pmakeblock(0, Mutable), [lambda_unit; lambda_unit; lambda_unit])
(* Error report *)
open Format
let report_error = function
Illegal_class_expr ->
print_string
"This kind of class expression is not allowed"
|