99
99
done
100
100
]}
101
101
*)
102
-
103
- let scope_pass =
104
- object (self )
105
- inherit Js_fold. fold as super
106
-
107
- val defined_idents = Set_ident. empty
108
-
109
- (* * [used_idents]
110
- does not contain locally defined idents *)
111
- val used_idents = Set_ident. empty
112
- (* * we need collect mutable values and loop defined varaibles *)
113
- val loop_mutable_values = Set_ident. empty
114
-
115
- val mutable_values = Set_ident. empty
116
-
117
- val closured_idents = Set_ident. empty
118
-
119
- (* * check if in loop or not *)
120
- val in_loop = false
121
-
122
- (* method get_in_loop = in_loop *)
123
-
124
- method get_defined_idents = defined_idents
125
-
126
- method get_used_idents = used_idents
127
-
128
- method get_loop_mutable_values = loop_mutable_values
129
-
130
- (* method get_mutable_values = mutable_values *)
131
-
132
- method get_closured_idents = closured_idents
133
-
134
- method with_in_loop b =
135
- if b = in_loop then self
136
- else {< in_loop = b > }
137
- (* Since it's loop mutable variable, for sure
138
- it is mutable variable
139
- *)
140
- method with_loop_mutable_values b =
141
- {< loop_mutable_values = b > }
142
-
143
- method add_loop_mutable_variable id =
144
- {< loop_mutable_values = Set_ident. add loop_mutable_values id;
145
- mutable_values = Set_ident. add mutable_values id
146
- > }
147
-
148
- method add_mutable_variable id =
149
- {< mutable_values = Set_ident. add mutable_values id > }
150
-
151
- method add_defined_ident ident =
152
- {< defined_idents = Set_ident. add defined_idents ident > }
153
- method add_used_ident ident =
154
- {< used_idents = Set_ident. add used_idents ident > }
155
- method! expression x =
156
- match x.expression_desc with
157
- | Fun (_method_ , params , block , env ) ->
158
- (* Function is the only place to introduce a new scope in
159
- ES5
160
- TODO: check
161
- {[ try .. catch(exn) {.. }]}
162
- what's the scope of exn
163
- *)
164
- (* Note that [used_idents] is not complete
165
- it ignores some locally defined idents *)
166
- let param_set = Set_ident. of_list params in
167
- let obj = {< defined_idents = Set_ident. empty;
168
- (* * pass [empty]
169
- so that we can check which parameter was actually used *)
170
- used_idents = Set_ident. empty ;
171
- in_loop = false ;
172
- loop_mutable_values = Set_ident. empty;
173
- mutable_values = Set_ident. of_list (Js_fun_env. get_mutable_params params env) ;
174
- closured_idents = Set_ident. empty; (* think about nested function*)
175
- > } # block block in
176
- let defined_idents', used_idents' =
177
- obj#get_defined_idents, obj#get_used_idents in
178
- (* mark which param is used *)
179
- params |> List. iteri
180
- (fun i v ->
181
- if not (Set_ident. mem used_idents' v) then
182
- Js_fun_env. mark_unused env i) ;
183
- let closured_idents' = (* pass param_set down *)
184
- Set_ident. (diff used_idents' (union defined_idents' param_set )) in
185
-
186
- (* Noe that we don't know which variables are exactly mutable yet ..
187
- due to the recursive thing
188
- *)
189
- Js_fun_env. set_unbounded env closured_idents' ;
190
- let lexical_scopes = Set_ident. (inter closured_idents' self#get_loop_mutable_values) in
191
- Js_fun_env. set_lexical_scope env lexical_scopes;
192
- (* tailcall , note that these varibles are used in another pass *)
193
- {< used_idents =
194
- Set_ident. union used_idents closured_idents' ;
195
- (* There is a bug in ocaml -dsource*)
196
- closured_idents = Set_ident. union closured_idents closured_idents'
197
- > }
198
- | _ ->
199
- let obj = super#expression x in
200
- match Js_block_runtime. check_additional_id x with
201
- | None -> obj
202
- | Some id ->
203
- obj#add_used_ident id
204
- (* TODO: most variables are immutable *)
205
-
206
- method! variable_declaration x =
102
+ type state = {
103
+ defined_idents : Set_ident .t ;
104
+ used_idents : Set_ident .t ;
105
+ loop_mutable_values : Set_ident .t ;
106
+ mutable_values : Set_ident .t ;
107
+ closured_idents : Set_ident .t ;
108
+ in_loop : bool ;
109
+ }
110
+
111
+ let init_state = {
112
+ defined_idents = Set_ident. empty;
113
+ used_idents = Set_ident. empty;
114
+ loop_mutable_values = Set_ident. empty;
115
+ mutable_values = Set_ident. empty;
116
+ closured_idents = Set_ident. empty;
117
+ in_loop = false ;
118
+ }
119
+ let with_in_loop (st :state ) b =
120
+ if b = st.in_loop then st
121
+ else {st with in_loop = b}
122
+ let add_loop_mutable_variable (st : state ) id =
123
+ { st with
124
+ loop_mutable_values = Set_ident. add st.loop_mutable_values id;
125
+ mutable_values = Set_ident. add st.mutable_values id
126
+ }
127
+ let add_mutable_variable (st : state ) id =
128
+ {
129
+ st with
130
+ mutable_values = Set_ident. add st.mutable_values id
131
+ }
132
+ let add_defined_ident (st : state ) id = {
133
+ st with
134
+ defined_idents = Set_ident. add st.defined_idents id
135
+ }
136
+ let add_used_ident (st : state ) id = {
137
+ st with used_idents = Set_ident. add st.used_idents id
138
+ }
139
+
140
+
141
+ let super = Js_record_fold. super
142
+ let record_scope_pass = {
143
+ super with
144
+ expression = begin fun self state x ->
145
+ match x.expression_desc with
146
+ | Fun (_method_ , params , block , env ) ->
147
+ (* Function is the only place to introduce a new scope in
148
+ ES5
149
+ TODO: check
150
+ {[ try .. catch(exn) {.. }]}
151
+ what's the scope of exn
152
+ *)
153
+ (* Note that [used_idents] is not complete
154
+ it ignores some locally defined idents *)
155
+ let param_set = Set_ident. of_list params in
156
+ let {defined_idents = defined_idents' ; used_idents = used_idents' } = self.block self {
157
+ init_state with
158
+ mutable_values = Set_ident. of_list (Js_fun_env. get_mutable_params params env) ;
159
+ } block in
160
+ (* let defined_idents', used_idents' =
161
+ obj#get_defined_idents, obj#get_used_idents in *)
162
+ (* mark which param is used *)
163
+ params |> List. iteri
164
+ (fun i v ->
165
+ if not (Set_ident. mem used_idents' v) then
166
+ Js_fun_env. mark_unused env i) ;
167
+ let closured_idents' = (* pass param_set down *)
168
+ Set_ident. (diff used_idents' (union defined_idents' param_set )) in
169
+
170
+ (* Noe that we don't know which variables are exactly mutable yet ..
171
+ due to the recursive thing
172
+ *)
173
+ Js_fun_env. set_unbounded env closured_idents' ;
174
+ let lexical_scopes = Set_ident. (inter closured_idents' state.loop_mutable_values) in
175
+ Js_fun_env. set_lexical_scope env lexical_scopes;
176
+ (* tailcall , note that these varibles are used in another pass *)
177
+ {state with used_idents =
178
+ Set_ident. union state.used_idents closured_idents' ;
179
+ (* There is a bug in ocaml -dsource*)
180
+ closured_idents = Set_ident. union state.closured_idents closured_idents'
181
+ }
182
+ | _ ->
183
+ let obj = super.expression self state x in
184
+ match Js_block_runtime. check_additional_id x with
185
+ | None -> obj
186
+ | Some id -> add_used_ident obj id
187
+ end;
188
+ variable_declaration = begin fun self state x ->
207
189
match x with
208
190
| { ident ; value; property } ->
209
191
let obj =
210
- (match in_loop, property with
192
+ add_defined_ident (match state. in_loop, property with
211
193
| true , Variable
212
194
->
213
- self# add_loop_mutable_variable ident
195
+ add_loop_mutable_variable state ident
214
196
| true , (Strict | StrictOpt | Alias )
215
197
(* Not real true immutable in javascript
216
198
since it's in the loop
@@ -219,7 +201,7 @@ let scope_pass =
219
201
*)
220
202
->
221
203
begin match value with
222
- | None -> self# add_loop_mutable_variable ident
204
+ | None -> add_loop_mutable_variable state ident
223
205
(* TODO: Check why assertion failure *)
224
206
(* self#add_loop_mutable_variable ident *) (* assert false *)
225
207
| Some x
@@ -234,7 +216,7 @@ let scope_pass =
234
216
*)
235
217
match x.expression_desc with
236
218
| Fun _ | Number _ | Str _
237
- -> self
219
+ -> state
238
220
| _ ->
239
221
(* if Set_ident.(is_empty @@ *)
240
222
(* inter self#get_mutable_values *)
@@ -245,80 +227,87 @@ let scope_pass =
245
227
(* (\* FIXME: still need to check expression is pure or not*\) *)
246
228
(* self *)
247
229
(* else *)
248
- self# add_loop_mutable_variable ident
230
+ add_loop_mutable_variable state ident
249
231
end
250
232
| false , Variable
251
233
->
252
- self# add_mutable_variable ident
234
+ add_mutable_variable state ident
253
235
| false , (Strict | StrictOpt | Alias )
254
- -> self
255
- )#add_defined_ident ident
236
+ -> state
237
+ ) ident
256
238
in
257
239
begin match value with
258
240
| None -> obj
259
- | Some x -> obj # expression x
241
+ | Some x -> self.expression self obj x
260
242
end
261
-
262
-
263
- method! statement x =
243
+ end;
244
+ statement = begin fun self state x ->
264
245
match x.statement_desc with
265
- | ForRange (_ ,_ , loop_id , _ ,_ ,a_env ) as y -> (* TODO: simplify definition of For *)
266
- let obj =
267
- {< in_loop = true ;
268
- loop_mutable_values = Set_ident. singleton loop_id ;
269
- used_idents = Set_ident. empty; (* TODO: if unused, can we generate better code? *)
270
- defined_idents = Set_ident. singleton loop_id ;
271
- closured_idents = Set_ident. empty (* Think about nested for blocks *)
272
- (* Invariant: Finish id is never used *)
273
- > }
274
- # statement_desc y in
246
+ | ForRange (_ ,_ , loop_id , _ ,_ ,a_env ) -> (* TODO: simplify definition of For *)
247
+ let {defined_idents = defined_idents'; used_idents = used_idents'; closured_idents = closured_idents'} =
275
248
276
- let defined_idents', used_idents', closured_idents' =
277
- obj#get_defined_idents, obj#get_used_idents, obj#get_closured_idents in
249
+ super.statement self { in_loop = true ;
250
+ loop_mutable_values = Set_ident. singleton loop_id ;
251
+ used_idents = Set_ident. empty; (* TODO: if unused, can we generate better code? *)
252
+ defined_idents = Set_ident. singleton loop_id ;
253
+ closured_idents = Set_ident. empty ;(* Think about nested for blocks *)
254
+ (* Invariant: Finish id is never used *)
255
+ mutable_values = state.mutable_values
256
+ } x in (* CHECK*)
278
257
258
+ (* let defined_idents', used_idents', closured_idents' =
259
+ obj#get_defined_idents, obj#get_used_idents, obj#get_closured_idents in *)
279
260
280
- let lexical_scope = Set_ident. (inter (diff closured_idents' defined_idents') self#get_loop_mutable_values) in
261
+
262
+ let lexical_scope = Set_ident. (inter (diff closured_idents' defined_idents') state.loop_mutable_values) in
281
263
let () = Js_closure. set_lexical_scope a_env lexical_scope in
282
264
(* set scope *)
283
- {< used_idents = Set_ident. union used_idents used_idents';
265
+ { state with
266
+ used_idents = Set_ident. union state.used_idents used_idents';
284
267
(* walk around ocaml -dsource bug
285
268
{[
286
269
Set_ident.(union used_idents used_idents)
287
270
]}
288
271
*)
289
- defined_idents = Set_ident. union defined_idents defined_idents';
272
+ defined_idents = Set_ident. union state. defined_idents defined_idents';
290
273
(* TODO: if we our generated code also follow lexical scope,
291
274
this is not necessary ;
292
275
[varaibles] are mutable or not is known at definition
293
276
*)
294
- closured_idents = Set_ident. union closured_idents lexical_scope
295
- > }
277
+ closured_idents = Set_ident. union state. closured_idents lexical_scope
278
+ }
296
279
297
280
| While (_label ,pred ,body , _env ) ->
298
- ((( self# expression pred)#with_in_loop true ) # block body )
299
- #with _in_loop ( in_loop)
281
+ with_in_loop (self.block self (with_in_loop ( self. expression self state pred) true ) body )
282
+ (state. in_loop)
300
283
| _ ->
301
- super#statement x
302
-
303
- method! exception_ident x =
304
- (* we can not simply skip it, since it can be used
305
- TODO: check loop exception
306
- (loop {
307
- excption(i){
308
- () => {i}
309
- }
310
- })
311
- *)
312
- {< used_idents = Set_ident. add used_idents x ;
313
- defined_idents = Set_ident. add defined_idents x
314
- > }
315
- method! for_ident x = {< loop_mutable_values = Set_ident. add loop_mutable_values x > }
284
+ super.statement self state x
285
+ end;
286
+
287
+
288
+ exception_ident = begin fun _ state x ->
289
+ (* we can not simply skip it, since it can be used
290
+ TODO: check loop exception
291
+ (loop {
292
+ excption(i){
293
+ () => {i}
294
+ }
295
+ })
296
+ *)
297
+ {state with used_idents = Set_ident. add state.used_idents x ;
298
+ defined_idents = Set_ident. add state.defined_idents x
299
+ }
300
+ end;
301
+ for_ident = begin fun _ state x -> {state with loop_mutable_values = Set_ident. add state.loop_mutable_values x } end;
302
+
303
+ ident = begin fun _ state x ->
304
+ if Set_ident. mem state.defined_idents x then
305
+ state
306
+ else {state with used_idents = Set_ident. add state.used_idents x }
307
+ end
308
+ }
316
309
317
- method! ident x =
318
- if Set_ident. mem defined_idents x then
319
- self
320
- else {< used_idents = Set_ident. add used_idents x > }
321
- end
322
310
323
311
let program js =
324
- (scope_pass # program js ) # get_loop_mutable_values
312
+ (record_scope_pass.program record_scope_pass init_state js).loop_mutable_values
313
+ (* (scope_pass # program js ) # get_loop_mutable_values *)
0 commit comments