type bind = Scope of int | Register of int | Global
type env = {depth:int; binding: (string * bind) list }
-let empty_env =
- {depth=0; binding=[("this",Register 0)]}
-
-let add_scope names {depth=n;binding=xs} =
- let names' =
- List.map (fun name-> name,Scope n) names in
- {depth=n+1; binding=names' @ xs}
-
-let add_global name env =
- {env with binding=(name,Global)::env.binding}
-
-let add_current_scope name {depth=n;binding=xs} =
- {depth=n; binding=(name,Scope (n-1))::xs}
-
-let add_register names env =
- let names' =
- ExtList.List.mapi (fun i name-> name,Register (i+1)) names in
- {env with binding = names'@env.binding}
-
-let add_this env =
- {env with binding = ("this",Register 0)::env.binding}
-
let get_bind name {binding=xs} =
List.assoc name xs
let is_bind name {binding=xs} =
List.mem_assoc name xs
-let ensure_scope name env =
- match get_bind name env with
- Scope x ->
- x
- | _ ->
- failwith ("scope not found:"^name)
+let empty_env =
+ {depth=0; binding=[("this",Register 0)]}
+
+let script_bootstrap _ =
+ [ GetLocal_0; PushScope ],{depth=1; binding=[]}
+
+let arguments env args f =
+ let b =
+ ExtList.List.mapi (fun i arg-> (arg,Register (i+1))) args in
+ let code =
+ f ({empty_env with binding = b }) in
+ code
+
+let let_scope {depth=n; binding=binding} vars f =
+ let env' =
+ {depth = n+1;
+ binding= List.map (fun (var,_) -> (var,Scope n)) vars @ binding} in
+ List.concat [HList.concat_map
+ (fun (var,init)->
+ List.concat [[PushString var]; init]) vars;
+ [NewObject (List.length vars);
+ PushWith];
+ f env';
+ [PopScope]]
+
+let let_rec_scope {depth=n; binding=binding} vars f =
+ let env' =
+ {depth = n+1;
+ binding= List.map (fun (var,_) -> (var,Scope n)) vars @ binding } in
+ let init =
+ HList.concat_map
+ (fun (var,g)->
+ List.concat [[GetScopeObject n];
+ g env';
+ [SetProperty (make_qname var)]]) vars in
+ List.concat [[NewObject 0;PushWith];
+ init;
+ f env';
+ [PopScope]]
+
+let define_scope name ({depth=n;binding=xs} as env) f =
+ let env' =
+ {depth=n; binding=(name,Scope (n-1))::xs} in
+ let body' =
+ if is_bind name env then
+ List.concat [
+ [NewObject 0;PushWith];
+ f env';
+ [GetScopeObject n;
+ Swap;
+ SetProperty (make_qname name)]]
+ else
+ List.concat [
+ f env';
+ [GetScopeObject (n-1);
+ Swap;
+ SetProperty (make_qname name)]] in
+ env',body'
+
+let define_class name ({sname=super; cname=cname} as klass) env =
+ let env' =
+ {env with binding=(name,Global)::env.binding} in
+ env',[
+ (* init class *)
+ GetLex super;
+ PushScope;
+ GetLex super;
+ NewClass klass;
+ PopScope;
+
+ (* add to scope *)
+ GetGlobalScope;
+ Swap;
+ InitProperty cname]
+let var_ref var env =
+ let qname =
+ make_qname var in
+ match get_bind_sure var env with
+ Some (Scope scope) ->
+ [GetScopeObject scope;
+ GetProperty qname]
+ | Some (Register n) ->
+ [GetLocal n]
+ | Some Global ->
+ [GetGlobalScope;
+ GetProperty qname]
+ | None ->
+ [GetLex qname]
+
+let var_call var args env =
+ let qname =
+ make_qname var in
+ let nargs =
+ List.length args in
+ match get_bind_sure var env with
+ Some (Scope scope) ->
+ List.concat [[GetScopeObject scope];
+ List.concat args;
+ [CallPropLex (qname,nargs)]]
+ | Some (Register n) ->
+ List.concat [[GetLocal n;
+ GetGlobalScope];
+ List.concat args;
+ [Asm.Call nargs]]
+ | Some Global ->
+ List.concat [[GetGlobalScope];
+ List.concat args;
+ [CallPropLex (qname,nargs)]]
+ | None ->
+ List.concat [[FindPropStrict qname];
+ List.concat args;
+ [CallPropLex (qname,nargs)]]
+
+let add_register names env =
+ let names' =
+ ExtList.List.mapi (fun i name-> name,Register (i+1)) names in
+ {env with binding = names'@env.binding}
+
(** {6 Builtin operator } *)
let builtin = ["+",(Add_i,2);
"-",(Subtract_i,2);
HList.concat_map gen args;
[ConstructProp (qname,List.length args)]]
| Lambda (args,body) ->
- let args',body' =
- generate_lambda args body empty_env in
- let m =
- Asm.make_meth ~args:args' "" body' in
- [NewFunction m]
+ arguments env args
+ (fun e ->
+ let args' =
+ List.map (const 0) args in
+ let body' =
+ generate_expr body e in
+ let m =
+ Asm.make_meth ~args:args' "" body' in
+ [NewFunction m])
| Var name ->
- let qname =
- make_qname name in
- begin match get_bind_sure name env with
- Some (Scope scope) ->
- [GetScopeObject scope;
- GetProperty qname]
- | Some (Register n) ->
- [GetLocal n]
- | Some Global ->
- [GetGlobalScope;
- GetProperty qname]
- | _ ->
- [GetLex qname]
- end
+ var_ref name env
| Let (vars,body) ->
- let env' =
- add_scope (List.map fst vars) env in
- let inits =
- HList.concat_map (fun (name,init)->
- List.concat [[PushString name];gen init]) vars in
- List.concat [inits;
- [NewObject (List.length vars);
- PushWith];
- generate_expr body env';
- [PopScope]]
+ let vars' =
+ List.map (Core.Tuple.T2.map2 ~f:gen) vars in
+ let_scope env vars' @@ generate_expr body
| LetRec (vars,body) ->
- let env' =
- add_scope (List.map fst vars) env in
- let init =
- HList.concat_map (fun (name,init)->
- List.concat [[GetScopeObject (ensure_scope name env')];
- gen init;
- [SetProperty (make_qname name)]])
- vars in
- List.concat [[NewObject 0;PushWith];
- init;
- generate_expr body env';
- [PopScope]]
+ let vars' =
+ List.map (Core.Tuple.T2.map2 ~f:generate_expr) vars in
+ let_rec_scope env vars' @@ generate_expr body
| Invoke (obj,name,args)->
List.concat [
gen obj;
HList.concat_map gen args;
[inst]]
| Ast.Call (Var name::args) ->
- let qname =
- make_qname name in
- let nargs =
- List.length args in
let args' =
- HList.concat_map gen args; in
- begin match get_bind_sure name env with
- Some (Scope scope) ->
- List.concat [[GetScopeObject scope];
- args';
- [CallPropLex (make_qname name,nargs)]]
- | Some (Register n) ->
- List.concat [[GetLocal n;
- GetGlobalScope];
- args';
- [Asm.Call nargs]]
- | _ ->
- List.concat [[FindPropStrict qname];
- args';
- [CallPropLex (qname,nargs)]]
- end
+ List.map gen args in
+ var_call name args' env
| Ast.Call (name::args) ->
let nargs =
List.length args in
match stmt with
Expr expr ->
env,(generate_expr expr env)@[Pop]
- | Define (name,body) when not @@ is_bind name env ->
- let env' =
- add_current_scope name env in
- let scope =
- ensure_scope name env' in
- let body' =
- List.concat [generate_expr body env';
- [GetScopeObject scope;
- Swap;
- SetProperty (make_qname name)]] in
- env',body'
| Define (name,body) ->
- let env' =
- add_scope [name] env in
- let scope =
- ensure_scope name env' in
- let body' =
- List.concat [[NewObject 0;PushWith];
- generate_expr body env';
- [GetScopeObject scope;
- Swap;
- SetProperty (make_qname name)]] in
- env',body'
+ define_scope name env @@ generate_expr body
| Class (name,(ns,sname),body) ->
- let env' =
- add_global name env in
let name' =
make_qname name in
let sname' =
List.fold_left
(fun (init',cinit',methods') (name,args,body) ->
let args',body' =
- generate_lambda (List.tl args) body (add_global name empty_env) in
+ generate_lambda (List.tl args) body empty_env in
match name with
"init" ->
(Asm.make_proc ~args:args' name (prefix@body'),
interface = [];
methods = methods
} in
- env',[
- (* init class *)
- GetLex sname';
- PushScope;
- GetLex sname';
- NewClass klass;
- PopScope;
-
- (* add to scope *)
- GetGlobalScope;
- Swap;
- InitProperty name']
+ define_class name klass env
let generate_program xs env =
List.concat @@ snd @@ map_accum_left generate_stmt env xs
-let generate_method xs =
- let init_env =
- add_scope ["this"] empty_env in
+let generate_script xs =
+ let bootstrap,env =
+ script_bootstrap () in
let program =
- generate_program xs init_env in
- Asm.make_proc "" ([GetLocal_0;PushScope] @ program)
+ generate_program xs env in
+ Asm.make_proc "" (bootstrap @ program)
let generate program =
- let m =
- generate_method program in
+ let script =
+ generate_script program in
let {Asm.abc_cpool=cpool;
method_info=info;
method_body=body;
class_info =class_info;
instance_info=instance_info} =
- assemble m in
+ assemble script in
let traits_class =
ExtList.List.mapi
- (fun i {Abc.name_i=name} -> {Abc.t_name=name; data=Abc.ClassTrait (i,i)})
+ (fun i {Abc.name_i=name} ->
+ {Abc.t_name=name; data=Abc.ClassTrait (i,i)})
instance_info in
{ Abc.cpool=cpool;
method_info=info;
QName ((Namespace ""),name)
let compile x =
- (generate_method [Expr x])
+ (generate_script [Expr x])
(** test *)
test lib_call =
test let_ =
assert_equal
(expr [PushString "x"; PushByte 1;
- PushString "y"; PushByte 2;
- NewObject 2;
- PushWith;
- GetScopeObject 1;
- GetProperty (qname "x");
- Pop;
- GetScopeObject 1;
- GetProperty (qname "y");
- PopScope])
+ PushString "y"; PushByte 2;
+ NewObject 2;
+ PushWith;
+ GetScopeObject 1;
+ GetProperty (qname "x");
+ Pop;
+ GetScopeObject 1;
+ GetProperty (qname "y");
+ PopScope])
(compile (Let (["x",Int 1;"y",Int 2],
Block [Var "x";Var "y"])))
PopScope])
(compile (LetRec (["x",Int 42],Block [])))
+test letrec =
+ assert_equal
+ (expr [NewObject 0;
+ PushWith;
+ GetScopeObject 1;
+
+ GetScopeObject 1;
+ GetProperty (qname "x");
+
+ SetProperty (qname "x");
+ PopScope])
+ (compile (LetRec (["x",Var "x"],Block [])))
+
test define =
assert_equal
(toplevel [NewFunction (inner [] [PushByte 42]);
GetScopeObject 0;
Swap;
SetProperty (qname "f")])
- (generate_method @@ compile_string "(define (f) 42)")
+ (generate_script @@ compile_string "(define (f) 42)")
test define_not_hidden =
assert_equal
(toplevel [NewFunction (inner [] [PushByte 42]);GetScopeObject 0;Swap;SetProperty (qname "f");
NewFunction (inner [] [PushByte 30]);GetScopeObject 0;Swap;SetProperty (qname "g")])
- (generate_method @@ compile_string "(define (f) 42) (define (g) 30)")
+ (generate_script @@ compile_string "(define (f) 42) (define (g) 30)")
test define_hidden =
assert_equal
(toplevel [NewFunction (inner [] [PushByte 42]);GetScopeObject 0;Swap;SetProperty (qname "f");
NewObject 0;PushWith;
NewFunction (inner [] [PushByte 30]);GetScopeObject 1;Swap;SetProperty (qname "f")])
- (generate_method @@ compile_string "(define (f) 42) (define (f) 30)")
+ (generate_script @@ compile_string "(define (f) 42) (define (f) 30)")
test closure =
assert_equal
GetScopeObject 0;
Swap;
SetProperty (qname "f")])
- (generate_method @@ compile_string "(define (f) (lambda () x))")
+ (generate_script @@ compile_string "(define (f) (lambda () x))")
(* function call *)
test call =
(expr [NewFunction (inner [0;0] [GetLocal 2])])
(compile (Lambda (["x";"y"],Block [Var "y"])))
+test closure_lambda =
+ assert_equal
+ (expr [PushString "z"; PushByte 42;
+ NewObject 1;
+ PushWith;
+ NewFunction (inner [] [GetLex (qname "z")]);
+ PopScope])
+ (compile (Let (["z",Int 42],
+ Lambda ([],Block [Var "z"]))))
+
+
test new_ =
assert_equal
(expr [FindPropStrict (make_qname "Foo");ConstructProp (make_qname "Foo",0)])
- (generate_method @@ compile_string "(new Foo)")
+ (generate_script @@ compile_string "(new Foo)")
test new_ =
assert_equal
(expr [FindPropStrict (make_qname "Foo");PushByte 42;ConstructProp (make_qname "Foo",1)])
- (generate_method @@ compile_string "(new Foo 42)")
+ (generate_script @@ compile_string "(new Foo 42)")
test invoke =
assert_equal
(expr [GetLex (make_qname "x");PushByte 10;CallProperty (make_qname "foo",1)])
- (generate_method @@ compile_string "(. x (foo 10))")
+ (generate_script @@ compile_string "(. x (foo 10))")
let new_class klass =
iinit = Asm.make_proc "init" @@ prefix@[PushByte 10];
interface = [];
methods = []})
- (generate_method @@ compile_string
+ (generate_script @@ compile_string
"(define-class Foo (Object) ())
(define-method init ((self Foo)) 10)")
iinit = Asm.make_proc "init" prefix;
interface = [];
methods = []})
- (generate_method @@ compile_string "(define-class Foo (Object) ())")
+ (generate_script @@ compile_string "(define-class Foo (Object) ())")
test klass_f =
assert_equal
iinit = Asm.make_proc "init" prefix;
interface = [];
methods = [Asm.make_meth "f" [PushByte 42]]})
- (generate_method @@ compile_string
+ (generate_script @@ compile_string
"(define-class Foo (Object) ())
(define-method f ((self Foo)) 42)")
iinit = Asm.make_proc "init" @@ prefix@[PushByte 10];
interface = [];
methods = []})
- (generate_method @@ compile_string
+ (generate_script @@ compile_string
"(define-class Foo (flash.text.Object) ())
(define-method init ((self Foo)) 10)")
iinit = Asm.make_proc "init" ~args:[0] @@ prefix@[GetLocal 1];
interface = [];
methods = []})
- (generate_method @@ compile_string
+ (generate_script @@ compile_string
"(define-class Foo (Object) ())
(define-method init ((self Foo) x) x)")
iinit = Asm.make_proc "init" prefix;
interface = [];
methods = [Asm.make_meth "f" ~args:[0] [GetLocal 1]]})
- (generate_method @@ compile_string "(define-class Foo (Object) ())
+ (generate_script @@ compile_string "(define-class Foo (Object) ())
(define-method f ((self Foo) x) x)")