67
strings : string lookup;
69
floats : float lookup;
70
brights : as3_base_right lookup;
71
rights : as3_rights lookup;
72
types : as3_type lookup;
73
mtypes : as3_method_type lookup_nz;
74
mutable classes : as3_class list;
75
mutable statics : as3_static list;
76
functions : as3_function lookup;
77
rpublic : as3_base_right index;
78
gpublic : as3_rights index;
80
78
mutable last_line : int;
79
mutable last_file : string;
83
82
mutable locals : (string,local) PMap.t;
84
mutable code : as3_opcode DynArray.t;
83
mutable code : hl_opcode DynArray.t;
85
84
mutable infos : code_infos;
86
85
mutable trys : try_infos list;
87
86
mutable breaks : (unit -> unit) list;
88
87
mutable continues : (int -> unit) list;
89
88
mutable in_static : bool;
90
89
mutable curblock : texpr list;
91
mutable block_vars : (int * string) list;
92
mutable try_scope_reg : int option;
90
mutable block_vars : (hl_slot * string * t) list;
91
mutable try_scope_reg : register option;
92
mutable for_call : bool;
95
95
let error p = Typer.error "Invalid expression" p
96
96
let stack_error p = Typer.error "Stack error" p
98
let stack_delta = function
112
| A3XmlOp3 -> assert false
113
| A3ForIn | A3ForEach -> -1
127
| A3CatchDone -> assert false
130
| A3StackCall n -> -(n + 1)
132
| A3SuperCall (_,n) -> -n
136
| A3SuperConstr n -> -(n + 1)
138
| A3SuperCallUnknown (_,n) -> -(n + 1)
139
| A3CallUnknown (_,n) -> -(n + 1)
140
| A3Object n -> -(n * 2) + 1
141
| A3Array n -> -n + 1
144
| A3XmlOp1 _ -> assert false
145
| A3Catch _ -> assert false
152
| A3GetScope0 | A3GetScope _ -> 1
165
| A3XmlOp2 -> assert false
176
| A3ONeg | A3OIncr | A3ODecr | A3ONot | A3OBitNot | A3OIIncr | A3OIDecr -> 0
178
| A3Unk _ -> assert false
180
98
let index_int (x : int) : 'a index = Obj.magic (x + 1)
181
99
let index_nz_int (x : int) : 'a index_nz = Obj.magic x
182
100
let tid (x : 'a index) : int = Obj.magic x
184
let new_lookup() = { h = Hashtbl.create 0; a = DynArray.create(); c = index_int }
185
let new_lookup_nz() = { h = Hashtbl.create 0; a = DynArray.create(); c = index_nz_int }
187
let construct_string = "__skip__constructor__"
188
let jsize = As3code.length (A3Jump (J3Always,0))
195
let id = w.c (DynArray.length w.a) in
196
Hashtbl.add w.h i id;
201
let id = w.c (DynArray.length w.a) in
205
let lookup_array w = DynArray.to_array w.a
207
let string ctx i = lookup i ctx.strings
102
let ethis = mk (TConst TThis) (mk_mono()) null_pos
103
let dynamic_prop = HMMultiNameLate [HNPublic (Some "")]
105
let t_void = TEnum ({
112
e_constrs = PMap.empty;
116
let t_string = TInst (mk_class ([],"String") null_pos None false,[])
117
let t_int = TInst (mk_class ([],"Int") null_pos None false,[])
209
119
let write ctx op =
210
120
DynArray.add ctx.code op;
211
ctx.infos.ipos <- As3code.length op + ctx.infos.ipos;
212
let s = ctx.infos.istack + stack_delta op in
121
ctx.infos.ipos <- ctx.infos.ipos + 1;
122
let s = ctx.infos.istack + As3hlparse.stack_delta op in
213
123
ctx.infos.istack <- s;
214
124
if s > ctx.infos.imax then ctx.infos.imax <- s;
217
127
let n = ctx.infos.iscopes + 1 in
218
128
ctx.infos.iscopes <- n;
219
129
if n > ctx.infos.imaxscopes then ctx.infos.imaxscopes <- n
221
131
ctx.infos.iscopes <- ctx.infos.iscopes - 1
225
135
let jump ctx cond =
226
136
let op = DynArray.length ctx.code in
227
write ctx (A3Jump (cond,-4));
228
137
let p = ctx.infos.ipos in
138
write ctx (HJump (cond,0));
230
140
let delta = ctx.infos.ipos - p in
231
DynArray.set ctx.code op (A3Jump (cond,delta))
141
DynArray.set ctx.code op (HJump (cond,delta))
234
144
let jump_back ctx =
235
let j = jump ctx J3Always in
236
145
let p = ctx.infos.ipos in
239
let delta = p + -(ctx.infos.ipos + jsize) in
240
write ctx (A3Jump (cond,delta))
148
let delta = p - ctx.infos.ipos in
149
write ctx (HJump (cond,delta))
243
let type_path ctx ?(getclass=false) (pack,name) =
244
let pid = string ctx (String.concat "." pack) in
245
let nameid = string ctx name in
246
let pid = lookup (A3RPublic (Some pid)) ctx.brights in
247
let tid = lookup (if getclass then A3TClassInterface (Some nameid,lookup [pid] ctx.rights) else A3TMethodVar (nameid,pid)) ctx.types in
250
let fake_type_path ctx ?(getclass=false) path =
251
type_path ctx ~getclass (match path with
152
let type_path ctx path =
153
let pack, name = (match path with
252
154
| [] , "Int" -> [] , "int"
155
| [] , "UInt" -> [] , "uint"
253
156
| [] , "Float" -> [] , "Number"
254
157
| [] , "Bool" -> [] , "Boolean"
257
let ident ctx i = type_path ctx ([],i)
158
| [] , "Enum" -> [] , "Class"
159
| ["flash";"xml"], "XML" -> [], "XML"
160
| ["flash";"xml"], "XMLList" -> [], "XMLList"
161
| ["flash"] , "FlashXml__" -> [] , "Xml"
162
| ["flash"] , "Boot" -> [] , ctx.boot
167
let rec follow_basic t =
171
| Some t -> follow_basic t
175
| TType (t,tl) when t.t_path <> ([],"Null") && t.t_path <> ([],"UInt") ->
176
follow_basic (apply_params t.t_types tl t.t_type)
180
match follow_basic t with
181
| TEnum ({ e_path = path; e_extern = false },_) ->
184
(match c.cl_kind with
186
(match c.cl_implements with
187
| [csup,_] -> type_path ctx csup.cl_path
188
| _ -> type_path ctx ([],"Object"))
189
| KExtension (c,_) ->
190
type_path ctx c.cl_path
192
type_path ctx c.cl_path)
194
type_path ctx ([],"Function")
195
| TEnum ({ e_path = ([],"Class") as path },_)
196
| TEnum ({ e_path = ([],"Bool") as path },_)
197
| TType ({ t_path = ([],"UInt") as path },_) ->
205
| _ -> Some (type_id ctx t)
207
let type_void ctx t =
209
| TEnum ({ e_path = [],"Void" },_) -> Some (HMPath ([],"void"))
210
| _ -> type_opt ctx t
213
match follow_basic t with
214
| TInst ({ cl_path = [],"Int" },_) ->
216
| TInst ({ cl_path = [],"Float" },_) ->
218
| TEnum ({ e_path = [],"Bool" },_) ->
222
KType (type_id ctx t)
223
| TType ({ t_path = [],"UInt" },_) ->
226
KType (HMPath ([],"Function"))
228
(match !(a.a_status) with
238
let ident i = HMPath ([],i)
241
HMName (p,HNNamespace "http://adobe.com/AS3/2006/builtin")
245
| TInst ({ cl_path = [],"Array" },_) ->
247
| "length" -> ident p, Some KInt, false (* UInt in the spec *)
248
| "copy" | "insert" | "remove" | "iterator" | "toString" -> ident p , None, true
249
| _ -> as3 p, None, false);
250
| TInst ({ cl_path = [],"String" },_) ->
252
| "length" (* Int in AS3/haXe *) -> ident p, None, false
253
| "charCodeAt" (* use haXe version *) -> ident p, None, true
254
| _ -> as3 p, None, false);
256
(match !(a.a_status) with
257
| Statics { cl_path = [], "Math" } ->
259
| "POSITIVE_INFINITY" | "NEGATIVE_INFINITY" | "NaN" -> ident p, Some KFloat, false
260
| _ -> ident p, None, false)
261
| _ -> ident p, None, false)
259
265
let default_infos() =
260
{ ipos = 0; istack = 0; imax = 0; iregs = 0; imaxregs = 0; iscopes = 0; imaxscopes = 0; iloop = -1 }
263
let r = ctx.infos.iregs + 1 in
264
ctx.infos.iregs <- r;
265
if ctx.infos.imaxregs < r then ctx.infos.imaxregs <- r;
270
iregs = DynArray.create();
277
let alloc_reg ctx k =
278
let regs = ctx.infos.iregs in
280
let p = DynArray.index_of (fun r -> not r.rused && k = r.rtype) regs in
281
let r = DynArray.unsafe_get regs p in
288
rid = DynArray.length regs + 1;
298
(* it would be useful to know if we don't already have
299
this type on the stack (as detected by the bytecode verifier)...
300
maybe this get removed at JIT, so it's only useful to reduce codesize
303
write ctx (match t with
306
| KFloat -> HToNumber
310
| KNone -> assert false
314
if not r.rinit then begin
316
if ctx.infos.icond then r.rcond <- true;
319
write ctx (HSetReg r.rid)
268
321
let free_reg ctx r =
269
if ctx.infos.iregs <> r then assert false;
270
ctx.infos.iregs <- r - 1
274
326
if n > 0 then begin
302
358
let gen_local_access ctx name p (forset : 'a) : 'a access =
303
359
match (try PMap.find name ctx.locals with Not_found -> Typer.error ("Unbound variable " ^ name) p) with
305
| LScope n -> write ctx (A3GetScope 1); VScope n
307
if is_set forset then write ctx (A3SetInf id);
363
write ctx (HGetScope 1);
366
if is_set forset then write ctx (HFindProp p);
310
369
let rec setvar ctx (acc : write access) retval =
313
if retval then write ctx A3Dup;
314
write ctx (A3SetReg r);
316
if retval then write ctx A3Dup;
317
write ctx (A3SetProp g);
318
| VId _ | VArray | VScope _ when retval ->
319
let r = alloc_reg ctx in
321
write ctx (A3SetReg r);
372
if retval then write ctx HDup;
375
if retval then write ctx HDup;
376
write ctx (HSetProp g);
377
| VId _ | VCast _ | VArray | VScope _ when retval ->
378
let r = alloc_reg ctx KDynamic in
322
381
setvar ctx acc false;
382
write ctx (HReg r.rid);
384
| VId id | VCast (id,_) ->
385
write ctx (HInitProp id)
328
let id_aset = lookup (A3TArrayAccess ctx.gpublic) ctx.types in
329
write ctx (A3Set id_aset);
387
write ctx (HSetProp dynamic_prop);
330
388
ctx.infos.istack <- ctx.infos.istack - 1
332
write ctx (A3SetSlot n)
390
write ctx (HSetSlot n)
334
392
let getvar ctx (acc : read access) =
395
if not r.rinit then begin
399
write ctx (HReg r.rid)
340
| VGlobal (g,flag) ->
341
write ctx (A3GetProp g);
342
if flag then write ctx A3ToObject
401
write ctx (HGetProp id)
403
write ctx (HGetProp id);
406
write ctx (HGetLex g);
344
let id_aget = lookup (A3TArrayAccess ctx.gpublic) ctx.types in
345
write ctx (A3Get id_aget);
408
write ctx (HGetProp dynamic_prop);
346
409
ctx.infos.istack <- ctx.infos.istack - 1
348
write ctx (A3GetSlot n)
411
write ctx (HGetSlot n)
350
413
let open_block ctx el retval =
351
414
let old_stack = ctx.infos.istack in
352
let old_regs = ctx.infos.iregs in
415
let old_regs = DynArray.map (fun r -> r.rused) ctx.infos.iregs in
353
416
let old_locals = ctx.locals in
354
417
let old_block = ctx.curblock in
355
418
ctx.curblock <- el;
357
420
if ctx.infos.istack <> old_stack + (if retval then 1 else 0) then assert false;
358
ctx.infos.iregs <- old_regs;
421
let rcount = DynArray.length old_regs + 1 in
422
DynArray.iter (fun r ->
423
if r.rid < rcount then
424
r.rused <- DynArray.unsafe_get old_regs (r.rid - 1)
359
428
ctx.locals <- old_locals;
360
429
ctx.curblock <- old_block;
432
let begin_branch ctx =
433
if ctx.infos.icond then
436
ctx.infos.icond <- true;
437
(fun() -> ctx.infos.icond <- false)
440
let begin_switch ctx =
441
let branch = begin_branch ctx in
442
let switch_index = DynArray.length ctx.code in
443
let switch_pos = ctx.infos.ipos in
444
write ctx (HSwitch (0,[]));
445
let constructs = ref [] in
448
if tag > !max then max := tag;
449
constructs := (tag,ctx.infos.ipos) :: !constructs;
452
let cases = Array.create (!max + 1) 1 in
453
List.iter (fun (tag,pos) -> Array.set cases tag (pos - switch_pos)) !constructs;
454
DynArray.set ctx.code switch_index (HSwitch (1,Array.to_list cases));
363
460
let debug ctx p =
364
461
let line = Lexer.get_error_line p in
462
if ctx.last_file <> p.pfile then begin
463
write ctx (HDebugFile p.pfile);
464
ctx.last_file <- p.pfile;
365
467
if ctx.last_line <> line then begin
366
write ctx (A3DebugLine line);
468
write ctx (HDebugLine line);
367
469
ctx.last_line <- line;
370
let begin_fun ctx ?(varargs=false) args el stat =
472
let begin_fun ctx args tret el stat p =
371
473
let old_locals = ctx.locals in
372
474
let old_code = ctx.code in
373
475
let old_infos = ctx.infos in
382
484
ctx.block_vars <- [];
383
485
ctx.in_static <- stat;
384
486
ctx.last_line <- -1;
388
if ctx.debug then begin
389
write ctx (A3DebugFile (lookup e.epos.pfile ctx.strings));
488
if ctx.debug then debug ctx p;
489
let rec find_this e =
492
| TConst TThis | TConst TSuper -> raise Exit
493
| _ -> Transform.iter find_this e
495
let this_reg = try List.iter find_this el; false with Exit -> true in
392
496
ctx.locals <- PMap.foldi (fun name l acc ->
395
| LScope _ -> PMap.add name (LGlobal (type_path ctx ~getclass:true ([],name))) acc
499
| LScope _ -> PMap.add name (LGlobal (ident name)) acc
396
500
| LGlobal _ -> PMap.add name l acc
397
501
) ctx.locals PMap.empty;
398
List.iter (fun (name,_) ->
399
define_local ctx name el;
502
List.iter (fun (name,_,t) ->
503
define_local ctx name ~init:true t el;
400
504
match gen_local_access ctx name null_pos Write with
403
write ctx (A3Reg (alloc_reg ctx));
507
let r = alloc_reg ctx (classify ctx t) in
508
write ctx (HReg r.rid);
404
509
setvar ctx acc false
511
let args, varargs = (match args with
512
| ["__arguments__",_,_] -> [], true
406
515
let rec loop_try e =
407
516
match e.eexpr with
408
517
| TFunction _ -> ()
409
518
| TTry _ -> raise Exit
410
| _ -> Type.iter loop_try e
519
| _ -> Type.iter loop_try e
412
ctx.try_scope_reg <- (try List.iter loop_try el; None with Exit -> Some (alloc_reg ctx));
521
ctx.try_scope_reg <- (try List.iter loop_try el; None with Exit -> Some (alloc_reg ctx KDynamic));
414
523
let hasblock = ctx.block_vars <> [] || ctx.trys <> [] in
415
524
let dparams = ref None in
416
List.iter (fun (_,opt) ->
525
List.iter (fun (_,opt,t) ->
417
526
match !dparams with
418
| None -> if opt then dparams := Some [A3VNull]
419
| Some l -> dparams := Some (A3VNull :: l)
527
| None -> if opt then dparams := Some [HVNone]
528
| Some l -> dparams := Some (HVNone :: l)
423
mt3_args = List.map (fun _ -> None) args;
425
mt3_var_args = varargs;
426
mt3_debug_name = None;
427
mt3_dparams = !dparams;
429
mt3_new_block = hasblock;
430
mt3_unk_flags = (false,false,false);
432
530
let code = DynArray.to_list ctx.code in
434
532
if hasblock then begin
435
let scope, delta = (match ctx.try_scope_reg with
436
| None -> A3Scope :: code , 4
437
| Some r -> A3Dup :: A3SetReg r :: A3Scope :: code, 5 + As3code.length (A3SetReg r)
533
let scope = (match ctx.try_scope_reg with
535
| Some r -> [HDup; HSetReg r.rid; HScope]
439
A3This :: A3Scope :: A3NewBlock :: scope, delta
440
end else if not stat then
441
A3This :: A3Scope :: code , 2
537
HThis :: HScope :: HNewBlock :: scope
538
end else if this_reg then
543
(* add dummy registers initialization *)
544
let extra = extra @ List.concat (List.map (fun r ->
548
let s = [HSetReg r.rid] in
550
| KInt -> HSmallInt 0 :: s
551
| KUInt -> HSmallInt 0 :: HToUInt :: s
552
| KFloat -> HNaN :: s
553
| KBool -> HFalse :: s
554
| KType t -> HNull :: HAsType t :: s
555
| KDynamic -> HNull :: HAsAny :: s
556
| KNone -> HNull :: s
557
) (DynArray.to_list ctx.infos.iregs)) in
558
let delta = List.length extra in
446
fun3_id = add mt ctx.mtypes;
447
fun3_stack_size = (if ctx.infos.imax = 0 && (hasblock || not stat) then 1 else ctx.infos.imax);
448
fun3_nregs = ctx.infos.imaxregs + 1;
450
fun3_max_scope = ctx.infos.imaxscopes + 1 + (if hasblock then 2 else if not stat then 1 else 0);
452
fun3_trys = Array.of_list (List.map (fun t ->
560
hlf_stack_size = (if ctx.infos.imax = 0 && (hasblock || this_reg) then 1 else ctx.infos.imax);
561
hlf_nregs = DynArray.length ctx.infos.iregs + 1;
563
hlf_max_scope = ctx.infos.imaxscopes + 1 + (if hasblock then 2 else if this_reg then 1 else 0);
564
hlf_code = Array.of_list (extra @ code);
565
hlf_trys = Array.of_list (List.map (fun t ->
454
tc3_start = t.tr_pos + delta;
455
tc3_end = t.tr_end + delta;
456
tc3_handle = t.tr_catch_pos + delta;
457
tc3_type = (match follow t.tr_type with
458
| TInst (c,_) -> Some (fake_type_path ctx c.cl_path)
459
| TEnum (e,_) -> Some (fake_type_path ctx e.e_path)
461
| _ -> assert false);
567
hltc_start = t.tr_pos + delta;
568
hltc_end = t.tr_end + delta;
569
hltc_handle = t.tr_catch_pos + delta;
570
hltc_type = type_opt ctx t.tr_type;
464
573
) (List.rev ctx.trys));
465
fun3_locals = Array.of_list (List.map (fun (id,name) ->
467
f3_name = ident ctx name;
469
f3_kind = A3FVar { v3_type = None; v3_value = A3VNone; v3_const = false };
474
ignore(add f ctx.functions);
574
hlf_locals = Array.of_list (List.map (fun (id,name,t) -> ident name, type_opt ctx t, id) ctx.block_vars);
577
hlmt_mark = As3hlparse.alloc_mark();
578
hlmt_ret = type_void ctx tret;
579
hlmt_args = List.map (fun (_,_,t) -> type_opt ctx t) args;
581
hlmt_var_args = varargs;
582
hlmt_debug_name = None;
583
hlmt_dparams = !dparams;
585
hlmt_new_block = hasblock;
586
hlmt_unused_flag = false;
587
hlmt_arguments_defined = false;
588
hlmt_uses_dxns = false;
589
hlmt_function = Some f;
475
591
ctx.locals <- old_locals;
476
592
ctx.code <- old_code;
477
593
ctx.infos <- old_infos;
541
657
match e.eexpr with
543
659
gen_local_access ctx i e.epos forset
544
| TField ({ eexpr = TLocal "__native__" },f) ->
545
let nameid = string ctx f in
546
let adobeid = string ctx "http://adobe.com/AS3/2006/builtin" in
547
let pid = lookup (A3RUnknown1 adobeid) ctx.brights in
548
let id = lookup (A3TMethodVar (nameid,pid)) ctx.types in
549
write ctx (A3GetInf id);
552
let id = ident ctx f in
554
| TConst TThis when not ctx.in_static -> write ctx (A3GetInf id)
555
| _ -> gen_expr ctx true e);
661
let id, k, closure = property f e1.etype in
662
if closure && not ctx.for_call then Typer.error "In Flash9, this method cannot be accessed this way : please define a local function" e1.epos;
664
| TConst TThis when not ctx.in_static -> write ctx (HFindPropStrict id)
665
| _ -> gen_expr ctx true e1);
667
| Some t -> VCast (id,t)
669
match follow e1.etype with
672
let et = follow e.etype in
673
(* if the return type is one of the type-parameters, then we need to cast it *)
674
if List.exists (fun t -> follow t == et) tl then
675
VCast (id, classify ctx et)
678
| TAnon a when (match !(a.a_status) with Statics _ | EnumStatics _ -> true | _ -> false) -> VId id
679
| _ -> VCast (id,classify ctx e.etype))
557
680
| TArray ({ eexpr = TLocal "__global__" },{ eexpr = TConst (TString s) }) ->
558
681
let path = (match List.rev (ExtString.String.nsplit s ".") with [] -> assert false | x :: l -> List.rev l, x) in
559
682
let id = type_path ctx path in
560
if is_set forset then write ctx A3GetScope0;
683
if is_set forset then write ctx HGetGlobalScope;
562
685
| TArray (e,eindex) ->
563
686
gen_expr ctx true e;
564
687
gen_expr ctx true eindex;
567
let id = type_path ctx ~getclass:true (t_path t) in
568
if is_set forset then write ctx A3GetScope0;
690
let id = type_path ctx (t_path t) in
691
if is_set forset then write ctx HGetGlobalScope;
573
696
let rec gen_expr_content ctx retval e =
574
697
match e.eexpr with
699
gen_constant ctx c e.etype e.epos
578
701
gen_expr ctx true e;
580
703
no_value ctx retval;
581
704
| TParenthesis e ->
582
705
gen_expr ctx retval e
583
706
| TEnumField (e,s) ->
584
write ctx A3GetScope0;
585
write ctx (A3Get (type_path ctx e.e_path));
586
write ctx (A3Get (ident ctx s));
707
let id = type_path ctx e.e_path in
708
write ctx (HGetLex id);
709
write ctx (HGetProp (ident s));
587
710
| TObjectDecl fl ->
588
711
List.iter (fun (name,e) ->
589
write ctx (A3String (lookup name ctx.strings));
712
write ctx (HString name);
590
713
gen_expr ctx true e
592
write ctx (A3Object (List.length fl))
715
write ctx (HObject (List.length fl))
593
716
| TArrayDecl el ->
594
717
List.iter (gen_expr ctx true) el;
595
write ctx (A3Array (List.length el));
718
write ctx (HArray (List.length el))
598
720
let rec loop = function
600
if retval then write ctx A3Null
722
if retval then write ctx HNull
602
724
ctx.curblock <- [];
603
725
gen_expr ctx retval e
746
876
pop ctx (ctx.infos.istack - ctx.infos.iloop);
747
877
let op = DynArray.length ctx.code in
748
write ctx (A3Jump (J3Always,-4));
749
878
let p = ctx.infos.ipos in
750
ctx.continues <- (fun target -> DynArray.set ctx.code op (A3Jump (J3Always,target - p))) :: ctx.continues;
879
write ctx (HJump (J3Always,0));
880
ctx.continues <- (fun target -> DynArray.set ctx.code op (HJump (J3Always,target - p))) :: ctx.continues;
751
881
no_value ctx retval
752
| TSwitch (e,el,eo) ->
753
let r = alloc_reg ctx in
755
write ctx (A3SetReg r);
882
| TSwitch (e0,el,eo) ->
883
let t = classify ctx e.etype in
885
(* generate optimized int switch *)
886
if t <> KInt && t <> KUInt then raise Exit;
889
| TConst (TInt n) -> Int32.to_int n
890
| TParenthesis e | TBlock [e] -> get_int e
891
| _ -> raise Not_found
893
List.iter (fun (vl,_) -> List.iter (fun v ->
894
let n = (try get_int v with _ -> raise Exit) in
895
if n < 0 || n > 512 then raise Exit;
897
gen_expr ctx true e0;
898
let switch, case = begin_switch ctx in
906
gen_expr ctx retval e;
907
if retval && classify ctx e.etype <> t then coerce ctx t);
908
let jends = List.map (fun (vl,e) ->
909
let j = jump ctx J3Always in
910
List.iter (fun v -> case (get_int v)) vl;
911
gen_expr ctx retval e;
913
ctx.infos.istack <- ctx.infos.istack - 1;
914
if classify ctx e.etype <> t then coerce ctx t;
918
List.iter (fun j -> j()) jends;
921
let r = alloc_reg ctx (classify ctx e0.etype) in
922
gen_expr ctx true e0;
924
let branch = begin_branch ctx in
756
925
let prev = ref (fun () -> ()) in
757
let jend = List.map (fun (v,e) ->
926
let jend = List.map (fun (vl,e) ->
761
prev := jump ctx J3Neq;
762
gen_expr_obj ctx retval e;
763
if retval then ctx.infos.istack <- ctx.infos.istack - 1;
928
let rec loop = function
932
write ctx (HReg r.rid);
934
prev := jump ctx J3Neq;
936
write ctx (HReg r.rid);
938
let j = jump ctx J3Eq in
943
gen_expr ctx retval e;
945
if classify ctx e.etype <> t then coerce ctx t;
946
ctx.infos.istack <- ctx.infos.istack - 1;
764
948
jump ctx J3Always
769
| None -> if retval then begin write ctx A3Null; write ctx A3ToObject; end
770
| Some e -> gen_expr_obj ctx retval e);
959
gen_expr ctx retval e;
960
if retval && classify ctx e.etype <> t then coerce ctx t;
771
962
List.iter (fun j -> j()) jend;
772
| TMatch (e,_,cases,def) ->
773
let rparams = alloc_reg ctx in
774
let rtag = alloc_reg ctx in
777
write ctx (A3Get (ident ctx "tag"));
778
write ctx (A3SetReg rtag);
779
write ctx (A3Get (ident ctx "params"));
780
write ctx (A3SetReg rparams);
781
let prev = ref (fun () -> ()) in
782
let jend = List.map (fun (tag,params,e) ->
784
write ctx (A3Reg rtag);
785
write ctx (A3String (lookup tag ctx.strings));
786
prev := jump ctx J3Neq;
964
| TMatch (e0,_,cases,def) ->
965
let t = classify ctx e.etype in
966
let rparams = alloc_reg ctx (KType (type_path ctx ([],"Array"))) in
967
let has_params = List.exists (fun (_,p,_) -> p <> None) cases in
968
gen_expr ctx true e0;
969
if has_params then begin
971
write ctx (HGetProp (ident "params"));
974
write ctx (HGetProp (ident "index"));
976
let switch,case = begin_switch ctx in
984
gen_expr ctx retval e;
985
if retval && classify ctx e.etype <> t then coerce ctx t);
986
let jends = List.map (fun (cl,params,e) ->
987
let j = jump ctx J3Always in
787
989
let b = open_block ctx [e] retval in
788
990
(match params with
791
993
let p = ref (-1) in
792
List.iter (fun (name,_) ->
994
List.iter (fun (name,t) ->
797
define_local ctx v [e];
999
define_local ctx v t [e];
798
1000
let acc = gen_local_access ctx v e.epos Write in
799
write ctx (A3Reg rparams);
800
write ctx (A3SmallInt !p);
1001
write ctx (HReg rparams.rid);
1002
write ctx (HSmallInt !p);
801
1003
getvar ctx VArray;
802
1004
setvar ctx acc false
805
gen_expr_obj ctx retval e;
1007
gen_expr ctx retval e;
807
if retval then ctx.infos.istack <- ctx.infos.istack - 1;
1009
if retval then begin
1010
ctx.infos.istack <- ctx.infos.istack - 1;
1011
if classify ctx e.etype <> t then coerce ctx t;
812
| None -> if retval then begin write ctx A3Null; write ctx A3ToObject; end
813
| Some e -> gen_expr_obj ctx retval e);
814
List.iter (fun j -> j()) jend;
1016
List.iter (fun j -> j()) jends;
816
1017
free_reg ctx rparams
818
and gen_call ctx e el =
1019
and gen_call ctx retval e el =
819
1020
match e.eexpr , el with
820
1021
| TLocal "__is__" , [e;t] ->
821
1022
gen_expr ctx true e;
822
1023
gen_expr ctx true t;
823
write ctx (A3Op A3OIs)
824
| TLocal "__keys__" , [e] ->
825
let racc = alloc_reg ctx in
826
let rcounter = alloc_reg ctx in
827
let rtmp = alloc_reg ctx in
828
write ctx (A3SmallInt 0);
829
write ctx (A3SetReg rcounter);
830
write ctx (A3Array 0);
831
write ctx (A3SetReg racc);
833
write ctx (A3SetReg rtmp);
834
let start, loop = jump_back ctx in
835
write ctx (A3Reg racc);
836
write ctx (A3Reg rtmp);
837
write ctx (A3Reg rcounter);
839
write ctx (A3Call (ident ctx "push",1));
1024
write ctx (HOp A3OIs)
1025
| TLocal "__as__" , [e;t] ->
1026
gen_expr ctx true e;
1027
gen_expr ctx true t;
1028
write ctx (HOp A3OAs)
1029
| TLocal "__int__", [e] ->
1030
gen_expr ctx true e;
1032
| TLocal "__float__", [e] ->
1033
gen_expr ctx true e;
1035
| TLocal "__hkeys__" , [e2]
1036
| TLocal "__keys__" , [e2] ->
1037
let racc = alloc_reg ctx (KType (type_path ctx ([],"Array"))) in
1038
let rcounter = alloc_reg ctx KInt in
1039
let rtmp = alloc_reg ctx KDynamic in
1040
write ctx (HSmallInt 0);
1041
set_reg ctx rcounter;
1042
write ctx (HArray 0);
1044
gen_expr ctx true e2;
1046
let start = jump ctx J3Always in
1047
let loop = jump_back ctx in
1048
write ctx (HReg racc.rid);
1049
write ctx (HReg rtmp.rid);
1050
write ctx (HReg rcounter.rid);
1052
if e.eexpr = TLocal "__hkeys__" then begin
1053
write ctx (HSmallInt 1);
1054
write ctx (HCallProperty (as3 "substr",1));
1056
write ctx (HCallPropVoid (as3 "push",1));
842
write ctx (A3Next (rtmp,rcounter));
1058
write ctx (HNext (rtmp.rid,rcounter.rid));
844
write ctx (A3Reg racc);
1060
write ctx (HReg racc.rid);
845
1061
free_reg ctx rtmp;
846
1062
free_reg ctx rcounter;
847
1063
free_reg ctx racc;
848
1064
| TLocal "__new__" , e :: el ->
849
1065
gen_expr ctx true e;
850
1066
List.iter (gen_expr ctx true) el;
851
write ctx (A3StackNew (List.length el))
1067
write ctx (HConstruct (List.length el))
852
1068
| TLocal "__delete__" , [o;f] ->
853
1069
gen_expr ctx true o;
854
1070
gen_expr ctx true f;
855
write ctx (A3Delete (lookup (A3TArrayAccess ctx.gpublic) ctx.types))
1071
write ctx (HDeleteProp dynamic_prop);
856
1072
| TLocal "__unprotect__" , [e] ->
857
1073
gen_expr ctx true e
858
1074
| TLocal "__typeof__", [e] ->
859
1075
gen_expr ctx true e;
861
1077
| TLocal "__in__", [e; f] ->
862
1078
gen_expr ctx true e;
863
1079
gen_expr ctx true f;
864
write ctx (A3Op A3OIn)
1080
write ctx (HOp A3OIn)
1081
| TArray ({ eexpr = TLocal "__global__" },{ eexpr = TConst (TString s) }), _ ->
1082
(match gen_access ctx e Read with
1084
write ctx (HFindPropStrict id);
1085
List.iter (gen_expr ctx true) el;
1086
write ctx (HCallProperty (id,List.length el));
1087
| _ -> assert false)
865
1088
| TConst TSuper , _ ->
867
1090
List.iter (gen_expr ctx true) el;
868
write ctx (A3SuperConstr (List.length el));
1091
write ctx (HConstructSuper (List.length el));
869
1092
| TField ({ eexpr = TConst TSuper },f) , _ ->
870
let id = ident ctx f in
871
write ctx (A3GetInf id);
1094
write ctx (HFindPropStrict id);
872
1095
List.iter (gen_expr ctx true) el;
873
write ctx (A3SuperCall (id,List.length el));
1096
write ctx (HCallSuper (id,List.length el));
874
1097
| TField ({ eexpr = TConst TThis },f) , _ when not ctx.in_static ->
875
let id = ident ctx f in
876
write ctx (A3GetInf id);
877
List.iter (gen_expr ctx true) el;
878
write ctx (A3Call (id,List.length el));
879
| TField (e,f) , _ ->
881
List.iter (gen_expr ctx true) el;
882
write ctx (A3Call (ident ctx f,List.length el));
1099
write ctx (HFindPropStrict id);
1100
List.iter (gen_expr ctx true) el;
1101
write ctx (if retval then HCallProperty (id,List.length el) else HCallPropVoid (id,List.length el));
1102
| TField (e1,f) , _ ->
1103
let old = ctx.for_call in
1104
ctx.for_call <- true;
1105
gen_expr ctx true e1;
1106
ctx.for_call <- old;
1107
List.iter (gen_expr ctx true) el;
1108
let id , _, _ = property f e1.etype in
1110
write ctx (HCallPropVoid (id,List.length el))
1113
match follow e.etype with
1114
| TFun (_,r) -> coerce ctx (classify ctx r)
1117
write ctx (HCallProperty (id,List.length el));
1118
(match follow e1.etype with
1119
| TInst ({ cl_path = [],"Array" },_) ->
1121
| "copy" | "remove" -> coerce()
1123
| TInst ({ cl_path = [],"Date" },_) ->
1124
coerce() (* all date methods are typed as Number in AS3 and Int in haXe *)
1126
(match !(a.a_status) with
1127
| Statics { cl_path = ([],"Date") } ->
1129
| "now" | "fromString" | "fromTime" -> coerce()
1131
| Statics { cl_path = ([],"Math") } ->
1133
| "isFinite" | "isNaN" -> coerce()
1134
| "floor" | "ceil" | "round" -> coerce() (* AS3 state Number, while Int in haXe *)
1138
| TEnumField (e,f) , _ ->
1139
let id = type_path ctx e.e_path in
1140
write ctx (HGetLex id);
1141
List.iter (gen_expr ctx true) el;
1142
write ctx (HCallProperty (ident f,List.length el));
884
1144
gen_expr ctx true e;
885
write ctx A3GetScope0;
1145
write ctx HGetGlobalScope;
886
1146
List.iter (gen_expr ctx true) el;
887
write ctx (A3StackCall (List.length el))
1147
write ctx (HCallStack (List.length el))
889
1149
and gen_unop ctx retval op flag e =
1150
let k = classify ctx e.etype in
892
1153
gen_expr ctx true e;
893
write ctx (A3Op A3ONot);
1154
write ctx (HOp A3ONot);
895
1156
gen_expr ctx true e;
896
write ctx (A3Op A3ONeg);
1157
write ctx (HOp (if k = KInt then A3OINeg else A3ONeg));
898
1159
gen_expr ctx true e;
899
write ctx (A3Op A3OBitNot);
1160
write ctx (HOp A3OBitNot);
902
1163
let incr = (op = Increment) in
903
1164
let acc = gen_access ctx e Write in (* for set *)
1166
| VReg r when r.rtype = KInt ->
1167
if not r.rinit then r.rcond <- true;
1168
if retval && flag = Postfix then getvar ctx (gen_access ctx e Read);
1169
write ctx (if incr then HIncrIReg r.rid else HDecrIReg r.rid);
1170
if retval && flag = Prefix then getvar ctx (gen_access ctx e Read);
904
1172
getvar ctx (gen_access ctx e Read);
906
1174
| Postfix when retval ->
907
let r = alloc_reg ctx in
909
write ctx (A3SetReg r);
910
write ctx (A3Op (if incr then A3OIncr else A3ODecr));
911
write ctx A3ToObject;
1175
let r = alloc_reg ctx k in
1178
write ctx (HOp (if incr then A3OIncr else A3ODecr));
912
1179
setvar ctx acc false;
1180
write ctx (HReg r.rid);
915
1182
| Postfix | Prefix ->
916
write ctx (A3Op (if incr then A3OIncr else A3ODecr));
917
write ctx A3ToObject;
1183
write ctx (HOp (if incr then A3OIncr else A3ODecr));
918
1184
setvar ctx acc retval
920
and gen_binop ctx retval op e1 e2 =
1186
and gen_binop ctx retval op e1 e2 t =
922
1188
gen_expr ctx true e1;
923
1189
gen_expr ctx true e2;
1192
let k1 = classify ctx e1.etype in
1193
let k2 = classify ctx e2.etype in
1194
if k1 = KInt && k2 = KInt then
1198
if o = A3OAdd then coerce ctx (classify ctx t);
928
1205
let acc = gen_access ctx e1 Write in
929
gen_expr_obj ctx true e2;
1206
gen_expr ctx true e2;
930
1207
setvar ctx acc retval
932
gen_expr_obj ctx true e1;
934
let j = jump ctx J3False in
936
gen_expr_obj ctx true e2;
1210
let j = jump_expr ctx e1 false in
1211
let b = begin_branch ctx in
1213
gen_expr ctx true e2;
939
gen_expr_obj ctx true e1;
941
let j = jump ctx J3True in
943
gen_expr_obj ctx true e2;
1219
let j = jump_expr ctx e1 true in
1220
let b = begin_branch ctx in
1222
gen_expr ctx true e2;
945
1226
| OpAssignOp op ->
946
1227
let acc = gen_access ctx e1 Write in
947
gen_binop ctx true op e1 e2;
948
(match DynArray.last ctx.code with A3ToObject -> () | _ -> write ctx A3ToObject);
1228
gen_binop ctx true op e1 e2 t;
949
1229
setvar ctx acc retval
1231
gen_op ~iop:A3OIAdd A3OAdd
1233
gen_op ~iop:A3OIMul A3OMul
1237
gen_op ~iop:A3OISub A3OSub
961
1241
gen_op A3OPhysEq
964
write ctx (A3Op A3ONot)
1244
write ctx (HOp A3ONot)
965
1245
| OpPhysNotEq ->
966
1246
gen_op A3OPhysEq;
967
write ctx (A3Op A3ONot)
1247
write ctx (HOp A3ONot)
1270
if classify ctx e1.etype = KInt && classify ctx e2.etype = KInt then coerce ctx (classify ctx t);
993
and gen_expr_obj ctx retval e =
994
gen_expr ctx retval e;
995
if retval then match DynArray.last ctx.code with A3ToObject -> () | _ -> write ctx A3ToObject
997
1274
and gen_expr ctx retval e =
998
1275
let old = ctx.infos.istack in
999
1276
if ctx.debug then debug ctx e.epos;
1000
1277
gen_expr_content ctx retval e;
1001
1278
if old <> ctx.infos.istack then begin
1002
1279
if old + 1 <> ctx.infos.istack then stack_error e.epos;
1003
if not retval then write ctx A3Pop;
1280
if not retval then write ctx HPop;
1004
1281
end else if retval then stack_error e.epos
1006
1283
and generate_function ctx fdata stat =
1007
let f = begin_fun ctx (List.map (fun (name,opt,_) -> name,opt) fdata.tf_args) [fdata.tf_expr] stat in
1284
let f = begin_fun ctx fdata.tf_args fdata.tf_type [fdata.tf_expr] stat fdata.tf_expr.epos in
1008
1285
gen_expr ctx false fdata.tf_expr;
1009
write ctx A3RetVoid;
1286
(match follow fdata.tf_type with
1287
| TEnum ({ e_path = [],"Void" },[]) -> write ctx HRetVoid
1289
(* check that we have a return that can be accepted by Flash9 VM *)
1292
| TBlock [] -> false
1293
| TBlock l -> loop (List.hd (List.rev l))
1294
| TReturn None -> true
1295
| TReturn (Some e) ->
1296
let rec inner_loop e =
1298
| TSwitch _ | TMatch _ | TFor _ | TWhile _ | TTry _ -> false
1300
| TParenthesis e -> inner_loop e
1304
| TIf (_,e1,Some e2) -> loop e1 && loop e2
1305
| TSwitch (_,_,Some e) -> loop e
1306
| TParenthesis e -> loop e
1309
if not (loop fdata.tf_expr) then write ctx HRetVoid;
1012
let generate_construct ctx fdata cfields =
1013
let args = List.map (fun (name,opt,_) -> name,opt) fdata.tf_args in
1014
let args = (match args with [] -> ["__p",true] | _ -> args) in
1015
let f = begin_fun ctx args [fdata.tf_expr] false in
1016
write ctx (A3Reg 1);
1017
write ctx (A3String (string ctx construct_string));
1018
let j = jump ctx J3PhysNeq in
1019
write ctx A3RetVoid;
1313
and jump_expr_gen ctx e jif jfun =
1315
| TParenthesis e -> jump_expr_gen ctx e jif jfun
1316
| TBinop (op,e1,e2) ->
1318
gen_expr ctx true e1;
1319
gen_expr ctx true e2;
1320
jfun (if jif then t else f)
1323
| OpEq -> j J3Eq J3Neq
1324
| OpNotEq -> j J3Neq J3Eq
1325
| OpPhysEq -> j J3PhysEq J3PhysNeq
1326
| OpPhysNotEq -> j J3PhysNeq J3PhysEq
1327
| OpGt -> j J3Gt J3NotGt
1328
| OpGte -> j J3Gte J3NotGte
1329
| OpLt -> j J3Lt J3NotLt
1330
| OpLte -> j J3Lte J3NotLte
1332
gen_expr ctx true e;
1333
jfun (if jif then J3True else J3False))
1335
gen_expr ctx true e;
1336
jfun (if jif then J3True else J3False)
1338
and jump_expr ctx e jif =
1339
jump_expr_gen ctx e jif (jump ctx)
1341
let generate_method ctx fdata stat =
1342
generate_function ctx { fdata with tf_expr = Transform.block_vars fdata.tf_expr } stat
1344
let generate_construct ctx fdata c =
1345
(* make all args optional to allow no-param constructor *)
1346
let f = begin_fun ctx (List.map (fun (a,o,t) -> a,true,t) fdata.tf_args) fdata.tf_type [ethis;fdata.tf_expr] false fdata.tf_expr.epos in
1347
(* if skip_constructor, then returns immediatly *)
1348
(match c.cl_kind with
1349
| KGenericInstance _ -> ()
1351
let id = ident "skip_constructor" in
1352
getvar ctx (VGlobal (type_path ctx ([],ctx.boot)));
1353
getvar ctx (VId id);
1354
let j = jump ctx J3False in
1021
1358
PMap.iter (fun _ f ->
1022
1359
match f.cf_expr with
1023
1360
| Some { eexpr = TFunction fdata } when f.cf_set = NormalAccess ->
1024
let id = ident ctx f.cf_name in
1025
write ctx (A3SetInf id);
1026
write ctx (A3Function (generate_function ctx fdata false));
1027
write ctx (A3Set id);
1361
let id = ident f.cf_name in
1362
write ctx (HFindProp id);
1363
write ctx (HFunction (generate_method ctx fdata false));
1364
write ctx (HInitProp id);
1030
gen_expr ctx false fdata.tf_expr;
1031
write ctx A3RetVoid;
1032
f() , List.length args
1034
let generate_reflect_construct ctx cid nargs =
1036
function __construct__(args) {
1037
return if( args == null )
1038
new Class("__skip__constructor__",null,null,....);
1040
new Class(args[0],args[1],....);
1043
let f = begin_fun ctx ["args",false] [] true in
1044
write ctx (A3GetInf cid);
1045
write ctx (A3Reg 1);
1047
write ctx A3ToObject;
1048
let j = jump ctx J3PhysNeq in
1049
write ctx (A3String (string ctx construct_string));
1050
write ctx A3ToObject;
1051
for i = 2 to nargs do
1053
write ctx A3ToObject;
1055
let jend = jump ctx J3Always in
1057
for i = 1 to nargs do
1058
write ctx (A3Reg 0);
1059
write ctx (A3SmallInt i);
1063
write ctx (A3New (cid,nargs));
1066
f3_name = ident ctx "__construct__";
1068
f3_kind = A3FMethod {
1071
m3_override = false;
1072
m3_kind = MK3Normal;
1077
let generate_class_init ctx c slot =
1078
write ctx A3GetScope0;
1367
gen_expr ctx false (Transform.block_vars fdata.tf_expr);
1369
f() , List.length fdata.tf_args
1371
let generate_class_init ctx c hc =
1372
write ctx HGetGlobalScope;
1079
1373
if c.cl_interface then
1082
1376
let path = (match c.cl_super with None -> ([],"Object") | Some (sup,_) -> sup.cl_path) in
1083
write ctx (A3GetProp (type_path ctx path));
1085
write ctx (A3GetProp (type_path ctx ~getclass:true path));
1377
write ctx (HGetLex (type_path ctx path));
1379
write ctx (HGetLex (type_path ctx path));
1087
write ctx (A3ClassDef slot);
1381
write ctx (HClassDef hc);
1088
1382
List.iter (fun f ->
1089
1383
match f.cf_expr with
1090
1384
| Some { eexpr = TFunction fdata } when f.cf_set = NormalAccess ->
1092
write ctx (A3Function (generate_function ctx fdata true));
1093
write ctx (A3Set (ident ctx f.cf_name));
1386
write ctx (HFunction (generate_method ctx fdata true));
1387
write ctx (HInitProp (ident f.cf_name));
1095
1389
) c.cl_ordered_statics;
1096
if not c.cl_interface then write ctx A3PopScope;
1097
write ctx (A3Set (type_path ctx c.cl_path))
1390
if not c.cl_interface then write ctx HPopScope;
1391
write ctx (HInitProp (type_path ctx c.cl_path))
1099
1393
let generate_class_statics ctx c =
1100
let r = alloc_reg ctx in
1394
let r = alloc_reg ctx KDynamic in
1101
1395
let first = ref true in
1102
let nslot = ref 1 in
1396
let nslot = ref 0 in
1103
1397
List.iter (fun f ->
1105
1398
match f.cf_expr with
1106
| Some { eexpr = TFunction _ } | None -> ()
1399
| Some { eexpr = TFunction _ } when f.cf_set <> NormalAccess -> ()
1108
1402
if !first then begin
1109
write ctx A3GetScope0;
1110
write ctx (A3Get (type_path ctx c.cl_path));
1111
write ctx (A3SetReg r);
1403
write ctx HGetGlobalScope;
1404
write ctx (HGetProp (type_path ctx c.cl_path));
1405
write ctx (HSetReg r.rid); (* needed for setslot *)
1112
1406
first := false;
1114
write ctx (A3Reg r);
1115
gen_expr ctx true e;
1116
write ctx (A3SetSlot !nslot);
1408
write ctx (HReg r.rid);
1409
gen_expr ctx true (Transform.block_vars e);
1410
write ctx (HSetSlot !nslot);
1117
1413
) c.cl_ordered_statics;
1120
let generate_enum_init ctx e slot =
1416
let generate_enum_init ctx e hc =
1121
1417
let path = ([],"Object") in
1122
1418
let name_id = type_path ctx e.e_path in
1123
write ctx A3GetScope0;
1124
write ctx (A3GetProp (type_path ctx path));
1126
write ctx (A3GetProp (type_path ~getclass:true ctx path));
1127
write ctx (A3ClassDef slot);
1128
write ctx A3PopScope;
1129
let r = alloc_reg ctx in
1131
write ctx (A3SetReg r);
1132
write ctx (A3Set name_id);
1419
write ctx HGetGlobalScope;
1420
write ctx (HGetLex (type_path ctx path));
1422
write ctx (HGetLex (type_path ctx path));
1423
write ctx (HClassDef hc);
1424
write ctx HPopScope;
1425
let r = alloc_reg ctx KDynamic in
1427
write ctx (HSetReg r.rid); (* needed for setslot *)
1428
write ctx (HInitProp name_id);
1133
1429
let nslot = ref 0 in
1134
1430
PMap.iter (fun _ f ->
1136
1432
match f.ef_type with
1139
write ctx (A3Reg r);
1140
write ctx (A3GetInf name_id);
1141
write ctx (A3String (lookup f.ef_name ctx.strings));
1143
write ctx (A3New (name_id,2));
1144
write ctx (A3SetSlot !nslot);
1435
write ctx (HReg r.rid);
1436
write ctx (HFindPropStrict name_id);
1437
write ctx (HString f.ef_name);
1438
write ctx (HInt f.ef_index);
1440
write ctx (HConstructProperty (name_id,3));
1441
write ctx (HSetSlot !nslot);
1443
write ctx (HReg r.rid);
1444
List.iter (fun n -> write ctx (HString n)) e.e_names;
1445
write ctx (HArray (List.length e.e_names));
1446
write ctx (HSetSlot (!nslot + 1));
1148
1449
let generate_field_kind ctx f c stat =
1217
f3_name = ident ctx f.cf_name;
1508
hlf_name = ident f.cf_name;
1222
1513
) c.cl_fields []) in
1225
cl3_super = (if c.cl_interface then None else Some (type_path ctx (match c.cl_super with None -> [],"Object" | Some (c,_) -> c.cl_path)));
1228
cl3_interface = c.cl_interface;
1230
cl3_implements = Array.of_list (List.map (fun (c,_) ->
1514
let st_field_count = ref 0 in
1515
let st_meth_count = ref 0 in
1516
let rec is_dynamic c =
1517
if c.cl_dynamic <> None then true
1518
else match c.cl_super with
1520
| Some (c,_) -> is_dynamic c
1524
hlc_super = (if c.cl_interface then None else Some (type_path ctx (match c.cl_super with None -> [],"Object" | Some (c,_) -> c.cl_path)));
1525
hlc_sealed = not (is_dynamic c);
1527
hlc_interface = c.cl_interface;
1528
hlc_namespace = None;
1529
hlc_implements = Array.of_list (List.map (fun (c,_) ->
1231
1530
if not c.cl_interface then Typer.error "Can't implement class in Flash9" c.cl_pos;
1232
1531
type_path ctx c.cl_path
1233
1532
) c.cl_implements);
1234
cl3_construct = cid;
1235
cl3_fields = fields;
1237
let st_count = ref 1 in
1238
let f_construct = generate_reflect_construct ctx name_id cnargs in
1241
st3_fields = Array.of_list (f_construct :: (List.map (fun f ->
1533
hlc_construct = cid;
1534
hlc_fields = fields;
1535
hlc_static_construct = empty_method ctx c.cl_pos;
1536
hlc_static_fields = Array.of_list (List.map (fun f ->
1537
let k = (match generate_field_kind ctx f c true with None -> assert false | Some k -> k) in
1538
let count = (match k with HFMethod _ -> st_meth_count | HFVar _ -> st_field_count | _ -> assert false) in
1244
f3_name = ident ctx f.cf_name;
1245
f3_slot = !st_count;
1246
f3_kind = (match generate_field_kind ctx f c true with None -> assert false | Some k -> k);
1541
hlf_name = ident f.cf_name;
1249
) c.cl_ordered_statics))
1251
ctx.classes <- sc :: ctx.classes;
1252
ctx.statics <- st :: ctx.statics
1546
) c.cl_ordered_statics);
1254
1549
let generate_enum ctx e =
1255
1550
let name_id = type_path ctx e.e_path in
1256
let st_id = empty_method ctx in
1257
let f = begin_fun ctx [("tag",false);("params",false)] [] false in
1258
let tag_id = ident ctx "tag" in
1259
let params_id = ident ctx "params" in
1260
write ctx (A3SetInf tag_id);
1261
write ctx (A3Reg 1);
1262
write ctx (A3Set tag_id);
1263
write ctx (A3SetInf params_id);
1264
write ctx (A3Reg 2);
1265
write ctx (A3Set params_id);
1266
write ctx A3RetVoid;
1551
let f = begin_fun ctx [("tag",false,t_string);("index",false,t_int);("params",false,mk_mono())] t_void [ethis] false e.e_pos in
1552
let tag_id = ident "tag" in
1553
let index_id = ident "index" in
1554
let params_id = ident "params" in
1555
write ctx (HFindProp tag_id);
1557
write ctx (HInitProp tag_id);
1558
write ctx (HFindProp index_id);
1560
write ctx (HInitProp index_id);
1561
write ctx (HFindProp params_id);
1563
write ctx (HInitProp params_id);
1267
1565
let construct = f() in
1268
let f = begin_fun ctx [] [] true in
1269
write ctx (A3GetProp (type_path ctx ~getclass:true (["flash"],"Boot")));
1271
write ctx (A3Call (ident ctx "enum_to_string",1));
1566
let f = begin_fun ctx [] t_string [] true e.e_pos in
1567
write ctx (HGetLex (type_path ctx ([],ctx.boot)));
1569
write ctx (HCallProperty (ident "enum_to_string",1));
1273
1571
let tostring = f() in
1276
cl3_super = Some (type_path ctx ([],"Object"));
1279
cl3_interface = false;
1281
cl3_implements = [||];
1282
cl3_construct = construct;
1284
{ f3_name = tag_id; f3_slot = 0; f3_kind = A3FVar { v3_type = None; v3_value = A3VNone; v3_const = false; }; f3_metas = None };
1285
{ f3_name = params_id; f3_slot = 0; f3_kind = A3FVar { v3_type = None; v3_value = A3VNone; v3_const = false; }; f3_metas = None };
1286
{ f3_name = ident ctx "__enum__"; f3_slot = 0; f3_kind = A3FVar { v3_type = None; v3_value = A3VBool true; v3_const = true }; f3_metas = None };
1288
f3_name = ident ctx "toString";
1290
f3_kind = A3FMethod {
1293
m3_override = false;
1294
m3_kind = MK3Normal;
1300
1572
let st_count = ref 0 in
1301
1573
let constrs = PMap.fold (fun f acc ->
1304
f3_name = ident ctx f.ef_name;
1305
f3_slot = !st_count;
1306
f3_kind = (match f.ef_type with
1576
hlf_name = ident f.ef_name;
1577
hlf_slot = !st_count;
1578
hlf_kind = (match f.ef_type with
1307
1579
| TFun (args,_) ->
1308
let fdata = begin_fun ctx (List.map (fun (name,opt,_) -> name,opt) args) [] true in
1309
write ctx (A3GetInf name_id);
1310
write ctx (A3String (lookup f.ef_name ctx.strings));
1580
let fdata = begin_fun ctx args (TEnum (e,[])) [] true f.ef_pos in
1581
write ctx (HFindPropStrict name_id);
1582
write ctx (HString f.ef_name);
1583
write ctx (HInt f.ef_index);
1311
1584
let n = ref 0 in
1312
List.iter (fun _ -> incr n; write ctx (A3Reg !n)) args;
1313
write ctx (A3Array (!n));
1314
write ctx (A3New (name_id,2));
1585
List.iter (fun _ -> incr n; write ctx (HReg !n)) args;
1586
write ctx (HArray (!n));
1587
write ctx (HConstructProperty (name_id,3));
1316
1589
let fid = fdata() in
1320
m3_override = false;
1321
m3_kind = MK3Normal;
1593
hlm_override = false;
1594
hlm_kind = MK3Normal;
1324
A3FVar { v3_type = (Some name_id); v3_value = A3VNone; v3_const = false; }
1597
HFVar { hlv_type = (Some name_id); hlv_value = HVNone; hlv_const = false; }
1328
1601
) e.e_constrs [] in
1331
st3_fields = Array.of_list ({
1332
f3_name = ident ctx "__isenum";
1333
f3_slot = !st_count + 1;
1334
f3_kind = A3FVar { v3_type = None; v3_value = A3VBool true; v3_const = true; };
1338
ctx.classes <- sc :: ctx.classes;
1339
ctx.statics <- st :: ctx.statics
1604
hlc_super = Some (type_path ctx ([],"Object"));
1607
hlc_interface = false;
1608
hlc_namespace = None;
1609
hlc_implements = [||];
1610
hlc_construct = construct;
1612
{ hlf_name = tag_id; hlf_slot = 0; hlf_kind = HFVar { hlv_type = None; hlv_value = HVNone; hlv_const = false; }; hlf_metas = None };
1613
{ hlf_name = index_id; hlf_slot = 0; hlf_kind = HFVar { hlv_type = None; hlv_value = HVNone; hlv_const = false; }; hlf_metas = None };
1614
{ hlf_name = params_id; hlf_slot = 0; hlf_kind = HFVar { hlv_type = None; hlv_value = HVNone; hlv_const = false; }; hlf_metas = None };
1615
{ hlf_name = ident "__enum__"; hlf_slot = 0; hlf_kind = HFVar { hlv_type = None; hlv_value = HVBool true; hlv_const = true }; hlf_metas = None };
1617
hlf_name = ident "toString";
1619
hlf_kind = HFMethod {
1620
hlm_type = tostring;
1622
hlm_override = false;
1623
hlm_kind = MK3Normal;
1628
hlc_static_construct = empty_method ctx e.e_pos;
1629
hlc_static_fields = Array.of_list ({
1630
hlf_name = ident "__isenum";
1631
hlf_slot = !st_count + 2;
1632
hlf_kind = HFVar { hlv_type = None; hlv_value = HVBool true; hlv_const = true; };
1635
hlf_name = ident "__constructs__";
1636
hlf_slot = !st_count + 1;
1637
hlf_kind = HFVar { hlv_type = None; hlv_value = HVNone; hlv_const = false; };
1341
1642
let generate_type ctx t =
1343
| TClassDecl c -> if not c.cl_extern then generate_class ctx c
1345
| TEnumDecl e -> if not e.e_extern then generate_enum ctx e
1347
let generate_inits ctx types =
1348
let f = begin_fun ctx [] [] false in
1648
Some (generate_class ctx c)
1653
Some (generate_enum ctx e)
1657
let generate_resources ctx hres =
1658
write ctx HGetGlobalScope;
1659
write ctx (HGetProp (type_path ctx ([],ctx.boot)));
1660
let id = type_path ctx (["flash";"utils"],"Dictionary") in
1661
write ctx (HFindPropStrict id);
1662
write ctx (HConstructProperty (id,0));
1663
let r = alloc_reg ctx (KType id) in
1665
Hashtbl.iter (fun name data ->
1666
write ctx (HReg r.rid);
1667
write ctx (HString name);
1668
write ctx (HString data);
1669
setvar ctx VArray false;
1671
write ctx (HReg r.rid);
1672
write ctx (HInitProp (ident "__res"))
1674
let generate_inits ctx types hres =
1675
let f = begin_fun ctx [] t_void [ethis] false null_pos in
1349
1676
let slot = ref 0 in
1350
let classes = List.fold_left (fun acc t ->
1352
| TClassDecl c when not c.cl_extern ->
1354
generate_class_init ctx c (!slot - 1);
1356
f3_name = type_path ctx c.cl_path;
1358
f3_kind = A3FClass (index_nz_int (!slot - 1));
1361
| TEnumDecl e when not e.e_extern ->
1363
generate_enum_init ctx e (!slot - 1);
1365
f3_name = type_path ctx e.e_path;
1367
f3_kind = A3FClass (index_nz_int (!slot - 1));
1677
let classes = List.fold_left (fun acc (t,hc) ->
1684
generate_class_init ctx c hc;
1686
hlf_name = type_path ctx c.cl_path;
1688
hlf_kind = HFClass hc;
1693
generate_enum_init ctx e hc;
1695
hlf_name = type_path ctx e.e_path;
1697
hlf_kind = HFClass hc;
1374
1704
(* define flash.Boot.init method *)
1375
write ctx A3GetScope0;
1376
write ctx (A3Get (type_path ctx (["flash"],"Boot")));
1377
let finit = begin_fun ctx [] [] true in
1705
write ctx HGetGlobalScope;
1706
write ctx (HGetProp (type_path ctx ([],ctx.boot)));
1707
let finit = begin_fun ctx [] t_void [] true null_pos in
1708
List.iter (fun (t,_) ->
1380
1710
| TClassDecl c ->
1381
1711
(match c.cl_init with
1383
| Some e -> gen_expr ctx false e);
1713
| Some e -> gen_expr ctx false (Transform.block_vars e));
1716
List.iter (fun (t,_) ->
1388
1718
| TClassDecl c -> generate_class_statics ctx c
1391
write ctx A3RetVoid;
1392
write ctx (A3Function (finit()));
1393
write ctx (A3Set (ident ctx "init"));
1394
write ctx A3RetVoid;
1722
write ctx (HFunction (finit()));
1723
write ctx (HInitProp (ident "init"));
1725
(* generate resources *)
1726
generate_resources ctx hres;
1397
st3_fields = Array.of_list (List.rev classes);
1731
hls_fields = Array.of_list (List.rev classes);
1400
1734
let generate types hres =
1401
let brights = new_lookup() in
1402
let strings = new_lookup() in
1403
let rights = new_lookup() in
1404
let empty_id = lookup "" strings in
1405
let rpublic = lookup (A3RPublic (Some empty_id)) brights in
1408
ints = new_lookup();
1409
floats = new_lookup();
1412
types = new_lookup();
1413
mtypes = new_lookup_nz();
1415
gpublic = lookup [rpublic] rights;
1418
functions = new_lookup();
1736
boot = "Boot_" ^ Printf.sprintf "%X" (Random.int 0xFFFFFF);
1419
1737
code = DynArray.create();
1420
1738
locals = PMap.empty;
1421
1739
infos = default_infos();
1427
1745
in_static = false;
1428
1746
debug = Plugin.defined "debug";
1429
1747
last_line = -1;
1430
1749
try_scope_reg = None;
1432
List.iter (generate_type ctx) types;
1433
Hashtbl.iter (fun _ _ -> assert false) hres;
1434
let init = generate_inits ctx types in
1436
as3_ints = lookup_array ctx.ints;
1437
as3_floats = lookup_array ctx.floats;
1438
as3_idents = lookup_array ctx.strings;
1439
as3_base_rights = lookup_array ctx.brights;
1440
as3_rights = lookup_array ctx.rights;
1441
as3_types = lookup_array ctx.types;
1442
as3_method_types = lookup_array ctx.mtypes;
1443
as3_metadatas = [||];
1444
as3_classes = Array.of_list (List.rev ctx.classes);
1445
as3_statics = Array.of_list (List.rev ctx.statics);
1446
as3_inits = [|init|];
1447
as3_functions = lookup_array ctx.functions;
1450
[Swf.TActionScript3 (Some (0,""),a)]
1453
(* ----------------------------------------------------------------------------------------
1457
---------------------------------------------------------------------------------------- *)
1460
As3code.iget ctx.as3_idents p
1462
let package ctx idx =
1463
match As3code.iget ctx.as3_base_rights idx with
1464
| A3RPrivate (Some id)
1465
| A3RPublic (Some id)
1466
| A3RInternal (Some id)
1469
| A3RUnknown2 (Some id) ->
1470
let pack = ident ctx id in
1471
ExtString.String.nsplit pack "."
1472
| A3RPrivate None | A3RPublic None | A3RInternal None | A3RUnknown2 None ->
1475
let real_type_path ctx p =
1476
match As3code.iget ctx.as3_types p with
1477
| A3TMethodVar (id,pack) ->
1478
let name = ident ctx id in
1479
let pack = package ctx pack in
1481
| A3TClassInterface (Some id,pack) ->
1482
let name = ident ctx id in
1483
let pack = package ctx (List.hd (As3code.iget ctx.as3_rights pack)) in
1485
| A3TClassInterface (None,_) ->
1486
[] , "$ClassInterfaceNone"
1487
| A3TArrayAccess _ ->
1494
let type_path ctx p =
1495
match real_type_path ctx p with
1496
| [] , "Object" -> [] , "Dynamic"
1497
| [] , "Boolean" -> [] , "Bool"
1498
| [] , "int" -> [] , "Int"
1499
| [] , "uint" -> [] , "UInt"
1500
| [] , "Number" -> [] , "Float"
1501
| [] , "Array" -> [] , "Array<Dynamic>"
1502
| [] , "void" -> [] , "Void"
1503
| [] , "Function" -> [] , "Dynamic"
1506
let ident_rights ctx id =
1507
match As3code.iget ctx.as3_types id with
1508
| A3TMethodVar (id,r) ->
1509
let name = ident ctx id in
1510
let r = (match As3code.iget ctx.as3_base_rights r with
1511
| A3RPublic _ | A3RUnknown1 _ -> false
1517
let rec create_dir acc = function
1520
let path = acc ^ "/" ^ d in
1521
(try Unix.mkdir path 0o777 with _ -> ());
1524
let value_type = function
1526
| A3VNull -> "Dynamic"
1527
| A3VBool _ -> "Bool"
1528
| A3VString _ -> "String"
1530
| A3VFloat _ -> "Float"
1531
| A3VNamespace _ -> "$Namespace"
1533
let type_val ctx t v =
1538
| Some v -> value_type v)
1540
s_type_path (type_path ctx t)
1542
let has_getset ml f m =
1543
List.exists (fun f2 ->
1544
match f2.f3_kind with
1545
| A3FMethod m2 when f.f3_name = f2.f3_name ->
1546
(match m.m3_kind , m2.m3_kind with
1547
| MK3Getter , MK3Setter | MK3Setter , MK3Getter -> true
1552
let gen_method ctx ch name mt =
1553
let m = As3code.iget ctx.as3_method_types (As3parse.no_nz mt) in
1554
let ret = (match m.mt3_ret with
1556
| Some t -> s_type_path (type_path ctx t)
1559
let params = List.map (fun a ->
1560
let name = (match m.mt3_pnames with
1561
| None -> "p" ^ string_of_int !p
1562
| Some l -> ident ctx (List.nth l (!p))
1564
let opt_val = (match m.mt3_dparams with
1568
Some (List.nth l (!p - List.length m.mt3_args + List.length l))
1572
let t = type_val ctx a opt_val in
1574
(if opt_val <> None then "?" else "") ^ name ^ " : " ^ t
1576
let vargs = if m.mt3_var_args then " /* ...arguments */" else "" in
1577
IO.printf ch "function %s(%s%s) : %s;\n" name (String.concat ", " params) vargs ret
1579
let gen_fields ctx ch fields stat =
1580
let fields = List.sort (fun f1 f2 -> compare (ident_rights ctx f1.f3_name) (ident_rights ctx f2.f3_name)) (Array.to_list fields) in
1582
match f.f3_kind with
1584
if m.m3_override then
1587
let priv , name = ident_rights ctx f.f3_name in
1588
(match m.m3_kind with
1591
if priv then IO.printf ch "private ";
1592
if stat then IO.printf ch "static ";
1593
gen_method ctx ch name m.m3_type
1595
let set = has_getset fields f m in
1596
let set_str = if set then "" else "(default,null)" in
1597
let m = As3code.iget ctx.as3_method_types (As3parse.no_nz m.m3_type) in
1598
let t = (match m.mt3_ret with None -> "Dynamic" | Some t -> s_type_path (type_path ctx t)) in
1599
IO.printf ch "\t%s%svar %s%s : %s;\n" (if priv then "private " else "") (if stat then "static " else "") name set_str t
1601
let get = has_getset fields f m in
1602
if not get then begin
1603
let m = As3code.iget ctx.as3_method_types (As3parse.no_nz m.m3_type) in
1604
let t = (match m.mt3_ret with None -> "Dynamic" | Some t -> s_type_path (type_path ctx t)) in
1605
IO.printf ch "\t%s%svar %s(null,default) : %s;\n" (if priv then "private " else "") (if stat then "static " else "") name t
1609
let t = type_val ctx v.v3_type (Some v.v3_value) in
1610
let priv , n = ident_rights ctx f.f3_name in
1611
IO.printf ch "\t%s%svar %s : %s;\n" (if priv then "private " else "") (if stat then "static " else "") n t
1613
IO.printf ch "\t// ????\n"
1616
let genhx_class ctx c s =
1617
let base_path = "hxclasses" in
1618
let pack , name = real_type_path ctx c.cl3_name in
1619
prerr_string ("import " ^ s_type_path (pack,name));
1620
create_dir "." (base_path :: pack);
1621
let f = open_out (base_path ^ "/" ^ (match pack with [] -> "" | l -> String.concat "/" l ^ "/") ^ name ^ ".hx") in
1622
let ch = IO.output_channel f in
1623
if pack <> [] then IO.printf ch "package %s;\n\n" (String.concat "." pack);
1624
IO.printf ch "extern %s %s" (if c.cl3_interface then "interface" else "class") name;
1625
let prev = ref (match c.cl3_super with
1628
match type_path ctx p with
1629
| [] , "Dynamic" -> false
1631
IO.printf ch " extends %s" (s_type_path path);
1634
Array.iter (fun i ->
1635
if !prev then IO.printf ch ",";
1637
IO.printf ch " implements %s" (s_type_path (type_path ctx i));
1639
IO.printf ch " {\n";
1640
IO.printf ch "\t"; gen_method ctx ch "new" c.cl3_construct;
1641
gen_fields ctx ch c.cl3_fields false;
1642
gen_fields ctx ch s.st3_fields true;
1648
let file = (try Plugin.find_file file with Not_found -> failwith ("File not found : " ^ file)) in
1649
let ch = IO.input_channel (open_in_bin file) in
1650
SwfParser.full_parsing := true;
1651
let _, swf = Swf.parse ch in
1652
SwfParser.full_parsing := false;
1655
match t.Swf.tdata with
1656
| Swf.TActionScript3 (_,t) -> Array.iteri (fun i c -> genhx_class t c t.as3_statics.(i)) t.as3_classes
1752
let classes = List.map (fun t -> (t,generate_type ctx t)) types in
1753
let init = generate_inits ctx classes hres in
1754
[init], ctx.boot, (fun () -> empty_method ctx null_pos)
1661
1758
gen_expr_ref := gen_expr