Created
October 19, 2011 13:49
-
-
Save skial/1298328 to your computer and use it in GitHub Desktop.
small changes to haxe js output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* | |
* Haxe Compiler | |
* Copyright (c)2005 Nicolas Cannasse | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program; if not, write to the Free Software | |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
*) | |
open Type | |
open Common | |
type ctx = { | |
com : Common.context; | |
buf : Buffer.t; | |
packages : (string list,unit) Hashtbl.t; | |
stack : Codegen.stack_context; | |
namespace : string option; | |
mutable current : tclass; | |
mutable statics : (tclass * string * texpr) list; | |
mutable inits : texpr list; | |
mutable tabs : string; | |
mutable in_value : tvar option; | |
mutable in_loop : bool; | |
mutable handle_break : bool; | |
mutable id_counter : int; | |
mutable curmethod : (string * bool); | |
mutable type_accessor : module_type -> string; | |
mutable separator : bool; | |
} | |
let s_path ctx = function | |
| ([],p) -> | |
(match ctx.namespace with | |
| None -> p | |
| Some ns -> ns ^ "." ^ p) | |
| p -> Ast.s_type_path p | |
let kwds = | |
let h = Hashtbl.create 0 in | |
List.iter (fun s -> Hashtbl.add h s ()) [ | |
"abstract"; "as"; "boolean"; "break"; "byte"; "case"; "catch"; "char"; "class"; "continue"; "const"; | |
"debugger"; "default"; "delete"; "do"; "double"; "else"; "enum"; "export"; "extends"; "false"; "final"; | |
"finally"; "float"; "for"; "function"; "goto"; "if"; "implements"; "import"; "in"; "instanceof"; "int"; | |
"interface"; "is"; "long"; "namespace"; "native"; "new"; "null"; "package"; "private"; "protected"; | |
"public"; "return"; "short"; "static"; "super"; "switch"; "synchronized"; "this"; "throw"; "throws"; | |
"transient"; "true"; "try"; "typeof"; "use"; "var"; "void"; "volatile"; "while"; "with" | |
]; | |
h | |
let field s = if Hashtbl.mem kwds s then "[\"" ^ s ^ "\"]" else "." ^ s | |
let ident s = if Hashtbl.mem kwds s then "$" ^ s else s | |
let anon_field s = if Hashtbl.mem kwds s then "'" ^ s ^ "'" else s | |
let spr ctx s = ctx.separator <- false; Buffer.add_string ctx.buf s | |
let print ctx = ctx.separator <- false; Printf.kprintf (fun s -> Buffer.add_string ctx.buf s) | |
let unsupported p = error "This expression cannot be compiled to Javascript" p | |
let newline ctx = | |
match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with | |
| '}' | '{' | ':' when not ctx.separator -> print ctx "\n%s" ctx.tabs | |
| _ -> print ctx ";\n%s" ctx.tabs | |
let newprop ctx = | |
match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with | |
| '{' -> print ctx "\n%s" ctx.tabs | |
| _ -> print ctx "\n%s," ctx.tabs | |
let semicolon ctx = | |
match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with | |
| '}' when not ctx.separator -> () | |
| _ -> spr ctx ";" | |
let rec concat ctx s f = function | |
| [] -> () | |
| [x] -> f x | |
| x :: l -> | |
f x; | |
spr ctx s; | |
concat ctx s f l | |
let fun_block ctx f p = | |
let e = List.fold_left (fun e (a,c) -> | |
match c with | |
| None | Some TNull -> e | |
| Some c -> Codegen.concat (Codegen.set_default ctx.com a c p) e | |
) f.tf_expr f.tf_args in | |
if ctx.com.debug then | |
Codegen.stack_block ctx.stack ctx.current (fst ctx.curmethod) e | |
else | |
e | |
let open_block ctx = | |
let oldt = ctx.tabs in | |
ctx.tabs <- "\t" ^ ctx.tabs; | |
(fun() -> ctx.tabs <- oldt) | |
let rec has_return e = | |
match e.eexpr with | |
| TBlock [] -> false | |
| TBlock el -> has_return (List.hd (List.rev el)) | |
| TReturn _ -> true | |
| _ -> false | |
let rec iter_switch_break in_switch e = | |
match e.eexpr with | |
| TFunction _ | TWhile _ | TFor _ -> () | |
| TSwitch _ | TMatch _ when not in_switch -> iter_switch_break true e | |
| TBreak when in_switch -> raise Exit | |
| _ -> iter (iter_switch_break in_switch) e | |
let handle_break ctx e = | |
let old = ctx.in_loop, ctx.handle_break in | |
ctx.in_loop <- true; | |
try | |
iter_switch_break false e; | |
ctx.handle_break <- false; | |
(fun() -> | |
ctx.in_loop <- fst old; | |
ctx.handle_break <- snd old; | |
) | |
with | |
Exit -> | |
spr ctx "try {"; | |
let b = open_block ctx in | |
newline ctx; | |
ctx.handle_break <- true; | |
(fun() -> | |
b(); | |
ctx.in_loop <- fst old; | |
ctx.handle_break <- snd old; | |
newline ctx; | |
spr ctx "} catch( e ) { if( e != \"__break__\" ) throw e; }"; | |
) | |
let this ctx = match ctx.in_value with None -> "this" | Some _ -> "$this" | |
let gen_constant ctx p = function | |
| TInt i -> print ctx "%ld" i | |
| TFloat s -> spr ctx s | |
| TString s -> | |
if String.contains s '\000' then error "A String cannot contain \\0 characters" p; | |
print ctx "\"%s\"" (Ast.s_escape s) | |
| TBool b -> spr ctx (if b then "true" else "false") | |
| TNull -> spr ctx "null" | |
| TThis -> spr ctx (this ctx) | |
| TSuper -> assert false | |
let rec gen_call ctx e el = | |
match e.eexpr , el with | |
| TConst TSuper , params -> | |
(match ctx.current.cl_super with | |
| None -> error "Missing setDebugInfos current class" e.epos | |
| Some (c,_) -> | |
print ctx "%s.call(%s" (ctx.type_accessor (TClassDecl c)) (this ctx); | |
List.iter (fun p -> print ctx ","; gen_value ctx p) params; | |
spr ctx ")"; | |
); | |
| TField ({ eexpr = TConst TSuper },name) , params -> | |
(match ctx.current.cl_super with | |
| None -> error "Missing setDebugInfos current class" e.epos | |
| Some (c,_) -> | |
print ctx "%s.prototype%s.call(%s" (ctx.type_accessor (TClassDecl c)) (field name) (this ctx); | |
List.iter (fun p -> print ctx ","; gen_value ctx p) params; | |
spr ctx ")"; | |
); | |
| TCall (x,_) , el when (match x.eexpr with TLocal { v_name = "__js__" } -> false | _ -> true) -> | |
spr ctx "("; | |
gen_value ctx e; | |
spr ctx ")"; | |
spr ctx "("; | |
concat ctx "," (gen_value ctx) el; | |
spr ctx ")"; | |
| TLocal { v_name = "__new__" }, { eexpr = TConst (TString cl) } :: params -> | |
print ctx "new %s(" cl; | |
concat ctx "," (gen_value ctx) params; | |
spr ctx ")"; | |
| TLocal { v_name = "__new__" }, e :: params -> | |
spr ctx "new "; | |
gen_value ctx e; | |
spr ctx "("; | |
concat ctx "," (gen_value ctx) params; | |
spr ctx ")"; | |
| TLocal { v_name = "__js__" }, [{ eexpr = TConst (TString code) }] -> | |
spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n")) | |
| TLocal { v_name = "__resources__" }, [] -> | |
spr ctx "["; | |
concat ctx "," (fun (name,data) -> | |
spr ctx "{ "; | |
spr ctx "name : "; | |
gen_constant ctx e.epos (TString name); | |
spr ctx ", data : "; | |
gen_constant ctx e.epos (TString (Codegen.bytes_serialize data)); | |
spr ctx "}" | |
) (Hashtbl.fold (fun name data acc -> (name,data) :: acc) ctx.com.resources []); | |
spr ctx "]"; | |
| _ -> | |
gen_value ctx e; | |
spr ctx "("; | |
concat ctx "," (gen_value ctx) el; | |
spr ctx ")" | |
and gen_expr ctx e = | |
match e.eexpr with | |
| TConst c -> gen_constant ctx e.epos c | |
| TLocal v -> spr ctx (ident v.v_name) | |
| TEnumField (e,s) -> | |
print ctx "%s%s" (ctx.type_accessor (TEnumDecl e)) (field s) | |
| TArray (e1,e2) -> | |
gen_value ctx e1; | |
spr ctx "["; | |
gen_value ctx e2; | |
spr ctx "]"; | |
| TBinop (op,e1,e2) -> | |
gen_value ctx e1; | |
print ctx " %s " (Ast.s_binop op); | |
gen_value ctx e2; | |
| TField (x,s) -> | |
gen_value ctx x; | |
spr ctx (field s) | |
| TClosure ({ eexpr = TTypeExpr _ } as x,s) -> | |
gen_value ctx x; | |
spr ctx (field s) | |
| TClosure (x,s) -> | |
(match x.eexpr with | |
| TConst _ | TLocal _ -> | |
gen_value ctx x; | |
print ctx ".%s.$bind(" s; | |
gen_value ctx x; | |
print ctx ")" | |
| _ -> | |
print ctx "($_="; | |
gen_value ctx x; | |
print ctx ",$_.%s.$bind($_))" s) | |
| TTypeExpr t -> | |
spr ctx (ctx.type_accessor t) | |
| TParenthesis e -> | |
spr ctx "("; | |
gen_value ctx e; | |
spr ctx ")"; | |
| TReturn eo -> | |
if ctx.in_value <> None then unsupported e.epos; | |
(match eo with | |
| None -> | |
spr ctx "return" | |
| Some e -> | |
spr ctx "return "; | |
gen_value ctx e); | |
| TBreak -> | |
if not ctx.in_loop then unsupported e.epos; | |
if ctx.handle_break then spr ctx "throw \"__break__\"" else spr ctx "break" | |
| TContinue -> | |
if not ctx.in_loop then unsupported e.epos; | |
spr ctx "continue" | |
| TBlock el -> | |
print ctx "{"; | |
let bend = open_block ctx in | |
List.iter (gen_block ctx) el; | |
bend(); | |
newline ctx; | |
print ctx "}"; | |
| TFunction f -> | |
let old = ctx.in_value, ctx.in_loop in | |
let old_meth = ctx.curmethod in | |
ctx.in_value <- None; | |
ctx.in_loop <- false; | |
if snd ctx.curmethod then | |
ctx.curmethod <- (fst ctx.curmethod ^ "@" ^ string_of_int (Lexer.get_error_line e.epos), true) | |
else | |
ctx.curmethod <- (fst ctx.curmethod, true); | |
print ctx "function(%s) " (String.concat "," (List.map ident (List.map arg_name f.tf_args))); | |
gen_expr ctx (fun_block ctx f e.epos); | |
ctx.curmethod <- old_meth; | |
ctx.in_value <- fst old; | |
ctx.in_loop <- snd old; | |
ctx.separator <- true | |
| TCall (e,el) -> | |
gen_call ctx e el | |
| TArrayDecl el -> | |
spr ctx "["; | |
concat ctx "," (gen_value ctx) el; | |
spr ctx "]" | |
| TThrow e -> | |
spr ctx "throw "; | |
gen_value ctx e; | |
| TVars [] -> | |
() | |
| TVars vl -> | |
spr ctx "var "; | |
concat ctx ", " (fun (v,e) -> | |
spr ctx (ident v.v_name); | |
match e with | |
| None -> () | |
| Some e -> | |
spr ctx " = "; | |
gen_value ctx e | |
) vl; | |
| TNew (c,_,el) -> | |
print ctx "new %s(" (ctx.type_accessor (TClassDecl c)); | |
concat ctx "," (gen_value ctx) el; | |
spr ctx ")" | |
| TIf (cond,e,eelse) -> | |
spr ctx "if"; | |
gen_value ctx cond; | |
spr ctx " "; | |
gen_expr ctx e; | |
(match eelse with | |
| None -> () | |
| Some e2 -> | |
(match e.eexpr with | |
| TObjectDecl _ -> ctx.separator <- false | |
| _ -> ()); | |
semicolon ctx; | |
spr ctx " else "; | |
gen_expr ctx e2); | |
| TUnop (op,Ast.Prefix,e) -> | |
spr ctx (Ast.s_unop op); | |
gen_value ctx e | |
| TUnop (op,Ast.Postfix,e) -> | |
gen_value ctx e; | |
spr ctx (Ast.s_unop op) | |
| TWhile (cond,e,Ast.NormalWhile) -> | |
let handle_break = handle_break ctx e in | |
spr ctx "while"; | |
gen_value ctx cond; | |
spr ctx " "; | |
gen_expr ctx e; | |
handle_break(); | |
| TWhile (cond,e,Ast.DoWhile) -> | |
let handle_break = handle_break ctx e in | |
spr ctx "do "; | |
gen_expr ctx e; | |
semicolon ctx; | |
spr ctx " while"; | |
gen_value ctx cond; | |
handle_break(); | |
| TObjectDecl fields -> | |
spr ctx "{ "; | |
concat ctx ", " (fun (f,e) -> print ctx "%s : " (anon_field f); gen_value ctx e) fields; | |
spr ctx "}"; | |
ctx.separator <- true | |
| TFor (v,it,e) -> | |
let handle_break = handle_break ctx e in | |
let it = (match it.eexpr with | |
| TLocal v -> v.v_name | |
| _ -> | |
let id = ctx.id_counter in | |
ctx.id_counter <- ctx.id_counter + 1; | |
let name = "$it" ^ string_of_int id in | |
print ctx "var %s = " name; | |
gen_value ctx it; | |
newline ctx; | |
name | |
) in | |
print ctx "while( %s.hasNext() ) {" it; | |
let bend = open_block ctx in | |
newline ctx; | |
print ctx "var %s = %s.next()" (ident v.v_name) it; | |
gen_block ctx e; | |
bend(); | |
newline ctx; | |
spr ctx "}"; | |
handle_break(); | |
| TTry (e,catchs) -> | |
spr ctx "try "; | |
gen_expr ctx e; | |
let vname = (match catchs with [(v,_)] -> v.v_name | _ -> | |
let id = ctx.id_counter in | |
ctx.id_counter <- ctx.id_counter + 1; | |
"$e" ^ string_of_int id | |
) in | |
print ctx " catch( %s ) {" vname; | |
let bend = open_block ctx in | |
let last = ref false in | |
let else_block = ref false in | |
List.iter (fun (v,e) -> | |
if !last then () else | |
let t = (match follow v.v_type with | |
| TEnum (e,_) -> Some (TEnumDecl e) | |
| TInst (c,_) -> Some (TClassDecl c) | |
| TFun _ | |
| TLazy _ | |
| TType _ | |
| TAnon _ -> | |
assert false | |
| TMono _ | |
| TDynamic _ -> | |
None | |
) in | |
match t with | |
| None -> | |
last := true; | |
if !else_block then print ctx "{"; | |
if vname <> v.v_name then begin | |
newline ctx; | |
print ctx "var %s = %s" v.v_name vname; | |
end; | |
gen_block ctx e; | |
if !else_block then begin | |
newline ctx; | |
print ctx "}"; | |
end | |
| Some t -> | |
if not !else_block then newline ctx; | |
print ctx "if( %s.__instanceof(%s," (ctx.type_accessor (TClassDecl { null_class with cl_path = ["js"],"Boot" })) vname; | |
gen_value ctx (mk (TTypeExpr t) (mk_mono()) e.epos); | |
spr ctx ") ) {"; | |
let bend = open_block ctx in | |
if vname <> v.v_name then begin | |
newline ctx; | |
print ctx "var %s = %s" v.v_name vname; | |
end; | |
gen_block ctx e; | |
bend(); | |
newline ctx; | |
spr ctx "} else "; | |
else_block := true | |
) catchs; | |
if not !last then print ctx "throw(%s)" vname; | |
bend(); | |
newline ctx; | |
spr ctx "}"; | |
| TMatch (e,(estruct,_),cases,def) -> | |
let evar = (if List.for_all (fun (_,pl,_) -> pl = None) cases then begin | |
spr ctx "switch( "; | |
gen_value ctx (if Optimizer.need_parent e then Codegen.mk_parent e else e); | |
spr ctx "[1] ) {"; | |
"???" | |
end else begin | |
let v = (match e.eexpr with | |
| TLocal v -> v.v_name | |
| _ -> | |
spr ctx "var $e = "; | |
gen_value ctx e; | |
newline ctx; | |
"$e" | |
) in | |
print ctx "switch( %s[1] ) {" v; | |
v | |
end) in | |
List.iter (fun (cl,params,e) -> | |
List.iter (fun c -> | |
newline ctx; | |
print ctx "case %d:" c; | |
) cl; | |
let bend = open_block ctx in | |
(match params with | |
| None -> () | |
| Some l -> | |
let n = ref 1 in | |
let l = List.fold_left (fun acc v -> incr n; match v with None -> acc | Some v -> (v.v_name,!n) :: acc) [] l in | |
newline ctx; | |
spr ctx "var "; | |
concat ctx ", " (fun (v,n) -> | |
print ctx "%s = %s[%d]" v evar n; | |
) l); | |
gen_block ctx e; | |
if not (has_return e) then begin | |
newline ctx; | |
print ctx "break"; | |
end; | |
bend(); | |
) cases; | |
(match def with | |
| None -> () | |
| Some e -> | |
newline ctx; | |
spr ctx "default:"; | |
let bend = open_block ctx in | |
gen_block ctx e; | |
bend(); | |
); | |
newline ctx; | |
spr ctx "}" | |
| TSwitch (e,cases,def) -> | |
spr ctx "switch"; | |
gen_value ctx e; | |
spr ctx " {"; | |
newline ctx; | |
List.iter (fun (el,e2) -> | |
List.iter (fun e -> | |
match e.eexpr with | |
| TConst(c) when c = TNull -> | |
spr ctx "case null: case undefined:"; | |
| _ -> | |
spr ctx "case "; | |
gen_value ctx e; | |
spr ctx ":" | |
) el; | |
let bend = open_block ctx in | |
gen_block ctx e2; | |
if not (has_return e2) then begin | |
newline ctx; | |
print ctx "break"; | |
end; | |
bend(); | |
newline ctx; | |
) cases; | |
(match def with | |
| None -> () | |
| Some e -> | |
spr ctx "default:"; | |
let bend = open_block ctx in | |
gen_block ctx e; | |
bend(); | |
newline ctx; | |
); | |
spr ctx "}" | |
| TCast (e,None) -> | |
gen_expr ctx e | |
| TCast (e1,Some t) -> | |
gen_expr ctx (Codegen.default_cast ctx.com e1 t e.etype e.epos) | |
and gen_block ctx e = | |
match e.eexpr with | |
| TBlock el -> List.iter (gen_block ctx) el | |
| _ -> newline ctx; gen_expr ctx e | |
and gen_value ctx e = | |
let assign e = | |
mk (TBinop (Ast.OpAssign, | |
mk (TLocal (match ctx.in_value with None -> assert false | Some v -> v)) t_dynamic e.epos, | |
e | |
)) e.etype e.epos | |
in | |
let value() = | |
let old = ctx.in_value, ctx.in_loop in | |
let r = alloc_var "$r" t_dynamic in | |
ctx.in_value <- Some r; | |
ctx.in_loop <- false; | |
spr ctx "(function($this) "; | |
spr ctx "{"; | |
let b = open_block ctx in | |
newline ctx; | |
spr ctx "var $r"; | |
newline ctx; | |
(fun() -> | |
newline ctx; | |
spr ctx "return $r"; | |
b(); | |
newline ctx; | |
spr ctx "}"; | |
ctx.in_value <- fst old; | |
ctx.in_loop <- snd old; | |
print ctx "(%s))" (this ctx) | |
) | |
in | |
match e.eexpr with | |
| TConst _ | |
| TLocal _ | |
| TEnumField _ | |
| TArray _ | |
| TBinop _ | |
| TField _ | |
| TClosure _ | |
| TTypeExpr _ | |
| TParenthesis _ | |
| TObjectDecl _ | |
| TArrayDecl _ | |
| TCall _ | |
| TNew _ | |
| TUnop _ | |
| TFunction _ -> | |
gen_expr ctx e | |
| TReturn _ | |
| TBreak | |
| TContinue -> | |
unsupported e.epos | |
| TCast (e1,t) -> | |
gen_value ctx (match t with None -> e1 | Some t -> Codegen.default_cast ctx.com e1 t e.etype e.epos) | |
| TVars _ | |
| TFor _ | |
| TWhile _ | |
| TThrow _ -> | |
(* value is discarded anyway *) | |
let v = value() in | |
gen_expr ctx e; | |
v() | |
| TBlock [e] -> | |
gen_value ctx e | |
| TBlock el -> | |
let v = value() in | |
let rec loop = function | |
| [] -> | |
spr ctx "return null"; | |
| [e] -> | |
gen_expr ctx (assign e); | |
| e :: l -> | |
gen_expr ctx e; | |
newline ctx; | |
loop l | |
in | |
loop el; | |
v(); | |
| TIf (cond,e,eo) -> | |
(* remove parenthesis unless it's an operation with higher precedence than ?: *) | |
let cond = (match cond.eexpr with | |
| TParenthesis { eexpr = TBinop ((Ast.OpAssign | Ast.OpAssignOp _),_,_) } -> cond | |
| TParenthesis e -> e | |
| _ -> cond | |
) in | |
gen_value ctx cond; | |
spr ctx "?"; | |
gen_value ctx e; | |
spr ctx ":"; | |
(match eo with | |
| None -> spr ctx "null" | |
| Some e -> gen_value ctx e); | |
| TSwitch (cond,cases,def) -> | |
let v = value() in | |
gen_expr ctx (mk (TSwitch (cond, | |
List.map (fun (e1,e2) -> (e1,assign e2)) cases, | |
match def with None -> None | Some e -> Some (assign e) | |
)) e.etype e.epos); | |
v() | |
| TMatch (cond,enum,cases,def) -> | |
let v = value() in | |
gen_expr ctx (mk (TMatch (cond,enum, | |
List.map (fun (constr,params,e) -> (constr,params,assign e)) cases, | |
match def with None -> None | Some e -> Some (assign e) | |
)) e.etype e.epos); | |
v() | |
| TTry (b,catchs) -> | |
let v = value() in | |
let block e = mk (TBlock [e]) e.etype e.epos in | |
gen_expr ctx (mk (TTry (block (assign b), | |
List.map (fun (v,e) -> v, block (assign e)) catchs | |
)) e.etype e.epos); | |
v() | |
let generate_package_create ctx (p,_) = | |
let rec loop acc = function | |
| [] -> () | |
| p :: l when Hashtbl.mem ctx.packages (p :: acc) -> loop (p :: acc) l | |
| p :: l -> | |
Hashtbl.add ctx.packages (p :: acc) (); | |
(match acc with | |
| [] -> | |
(* ++patch++ *) | |
print ctx "var %s = {}" p; | |
(* --patch-- *) | |
| _ -> | |
let p = String.concat "." (List.rev acc) ^ (field p) in | |
print ctx "%s = {}" p); | |
newline ctx; | |
loop (p :: acc) l | |
in | |
match p with | |
| [] -> print ctx "var " | |
| _ -> loop [] p | |
let check_field_name c f = | |
match f.cf_name with | |
| "prototype" | "__proto__" | "constructor" -> | |
error ("The field name '" ^ f.cf_name ^ "' is not allowed in JS") (match f.cf_expr with None -> c.cl_pos | Some e -> e.epos); | |
| _ -> () | |
let gen_class_static_field ctx c f = | |
check_field_name c f; | |
match f.cf_expr with | |
| None -> | |
print ctx "%s%s = null" (s_path ctx c.cl_path) (field f.cf_name); | |
newline ctx | |
| Some e -> | |
match e.eexpr with | |
| TFunction _ -> | |
ctx.curmethod <- (f.cf_name,false); | |
ctx.id_counter <- 0; | |
print ctx "%s%s = " (s_path ctx c.cl_path) (field f.cf_name); | |
gen_value ctx e; | |
ctx.separator <- false; | |
newline ctx | |
| _ -> | |
ctx.statics <- (c,f.cf_name,e) :: ctx.statics | |
let gen_class_field ctx c f = | |
check_field_name c f; | |
newprop ctx; | |
print ctx "%s: " (anon_field f.cf_name); | |
match f.cf_expr with | |
| None -> | |
print ctx "null"; | |
| Some e -> | |
ctx.curmethod <- (f.cf_name,false); | |
ctx.id_counter <- 0; | |
gen_value ctx e; | |
ctx.separator <- false | |
let gen_constructor ctx e = | |
match e.eexpr with | |
| TFunction f -> | |
let args = List.map arg_name f.tf_args in | |
print ctx "function(%s) {" (String.concat "," (List.map ident args)); | |
let bend = open_block ctx in | |
gen_block ctx (fun_block ctx f e.epos); | |
bend(); | |
newline ctx; | |
print ctx "}"; | |
| _ -> assert false | |
let generate_class ctx c = | |
ctx.current <- c; | |
ctx.curmethod <- ("new",true); | |
ctx.id_counter <- 0; | |
let p = s_path ctx c.cl_path in | |
generate_package_create ctx c.cl_path; | |
print ctx "%s = " p; | |
(match c.cl_constructor with | |
| Some { cf_expr = Some e } -> gen_constructor ctx e | |
| _ -> print ctx "function() {}"); | |
newline ctx; | |
(* ++patch++ *) | |
print ctx "$hxClasses[\"%s\"] = %s" p p; | |
newline ctx; | |
(* --patch-- *) | |
print ctx "%s.__name__ = [%s]" p (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst c.cl_path @ [snd c.cl_path]))); | |
newline ctx; | |
(match c.cl_implements with | |
| [] -> () | |
| l -> | |
print ctx "%s.__interfaces__ = [%s]" p (String.concat "," (List.map (fun (i,_) -> s_path ctx i.cl_path) l)); | |
newline ctx; | |
); | |
List.iter (gen_class_static_field ctx c) c.cl_ordered_statics; | |
(match c.cl_super with | |
| None -> print ctx "%s.prototype = {" p; | |
| Some (csup,_) -> | |
let psup = s_path ctx csup.cl_path in | |
print ctx "%s.__super__ = %s" p psup; | |
newline ctx; | |
print ctx "%s.prototype = $extend(%s.prototype,{" p psup; | |
); | |
let bend = open_block ctx in | |
List.iter (fun f -> match f.cf_kind with Var { v_read = AccResolve } -> () | _ -> gen_class_field ctx c f) c.cl_ordered_fields; | |
newprop ctx; | |
print ctx "__class__: %s" p; | |
bend(); | |
print ctx "\n}"; | |
(match c.cl_super with None -> () | _ -> print ctx ")"); | |
newline ctx | |
let generate_enum ctx e = | |
let p = s_path ctx e.e_path in | |
generate_package_create ctx e.e_path; | |
let ename = List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst e.e_path @ [snd e.e_path]) in | |
print ctx "%s = { __ename__ : [%s], __constructs__ : [%s] }" p (String.concat "," ename) (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" s) e.e_names)); | |
newline ctx; | |
(* ++patch++ *) | |
print ctx "$hxClasses[\"%s\"] = %s" p p; | |
newline ctx; | |
(* --patch-- *) | |
List.iter (fun n -> | |
let f = PMap.find n e.e_constrs in | |
print ctx "%s%s = " p (field f.ef_name); | |
(match f.ef_type with | |
| TFun (args,_) -> | |
let sargs = String.concat "," (List.map (fun (n,_,_) -> n) args) in | |
print ctx "function(%s) { var $x = [\"%s\",%d,%s]; $x.__enum__ = %s; $x.toString = $estr; return $x; }" sargs f.ef_name f.ef_index sargs p; | |
| _ -> | |
print ctx "[\"%s\",%d]" f.ef_name f.ef_index; | |
newline ctx; | |
print ctx "%s%s.toString = $estr" p (field f.ef_name); | |
newline ctx; | |
print ctx "%s%s.__enum__ = %s" p (field f.ef_name) p; | |
); | |
newline ctx | |
) e.e_names; | |
match Codegen.build_metadata ctx.com (TEnumDecl e) with | |
| None -> () | |
| Some e -> | |
print ctx "%s.__meta__ = " p; | |
gen_expr ctx e; | |
newline ctx | |
let generate_static ctx (c,f,e) = | |
print ctx "%s%s = " (s_path ctx c.cl_path) (field f); | |
gen_value ctx e; | |
newline ctx | |
let generate_type ctx = function | |
| TClassDecl c -> | |
(match c.cl_init with | |
| None -> () | |
| Some e -> ctx.inits <- e :: ctx.inits); | |
if not c.cl_extern then generate_class ctx c | |
| TEnumDecl e when e.e_extern -> | |
() | |
| TEnumDecl e -> generate_enum ctx e | |
| TTypeDecl _ -> () | |
let alloc_ctx com = | |
let ctx = { | |
com = com; | |
stack = Codegen.stack_init com false; | |
buf = Buffer.create 16000; | |
packages = Hashtbl.create 0; | |
namespace = com.js_namespace; | |
statics = []; | |
inits = []; | |
current = null_class; | |
tabs = ""; | |
in_value = None; | |
in_loop = false; | |
handle_break = false; | |
id_counter = 0; | |
curmethod = ("",false); | |
type_accessor = (fun _ -> assert false); | |
separator = false; | |
} in | |
ctx.type_accessor <- (fun t -> s_path ctx (t_path t)); | |
ctx | |
let gen_single_expr ctx e constr = | |
if constr then gen_constructor ctx e else gen_value ctx e; | |
let str = Buffer.contents ctx.buf in | |
Buffer.reset ctx.buf; | |
ctx.id_counter <- 0; | |
str | |
let set_debug_infos ctx c m s = | |
ctx.current <- c; | |
ctx.curmethod <- (m,s) | |
let generate com = | |
let t = Common.timer "generate js" in | |
(match com.js_gen with | |
| Some g -> g() | |
| None -> | |
let ctx = alloc_ctx com in | |
(* ++patch++ *) | |
print ctx "(function(context) {\n"; | |
(* --patch-- *) | |
print ctx "var $_, $hxClasses = {}, $estr = function() { return js.Boot.__string_rec(this,''); } | |
function $extend(from, fields) { | |
function inherit() {}; inherit.prototype = from; var proto = new inherit(); | |
for (var name in fields) proto[name] = fields[name]; | |
return proto; | |
}"; | |
newline ctx; | |
(match ctx.namespace with | |
| None -> () | |
| Some ns -> | |
(* ++patch++ *) | |
print ctx "var %s = {}" ns; | |
(* --patch-- *) | |
newline ctx); | |
List.iter (generate_type ctx) com.types; | |
print ctx "js.Boot.__res = {}"; | |
newline ctx; | |
(match ctx.namespace with | |
| None -> () | |
| Some ns -> | |
print ctx "js.Boot.__ns = '%s'" ns; | |
newline ctx); | |
if com.debug then begin | |
print ctx "%s = []" ctx.stack.Codegen.stack_var; | |
newline ctx; | |
print ctx "%s = []" ctx.stack.Codegen.stack_exc_var; | |
newline ctx; | |
end; | |
print ctx "js.Boot.__init()"; | |
newline ctx; | |
(* static __init__ method creation *) | |
List.iter (fun e -> | |
gen_expr ctx e; | |
newline ctx; | |
) (List.rev ctx.inits); | |
List.iter (generate_static ctx) (List.rev ctx.statics); | |
(match com.main with | |
| None -> () | |
| Some e -> gen_expr ctx e); | |
(* ++patch++ *) | |
newline ctx; | |
print ctx "context[\"haxe\"] = haxe"; | |
newline ctx; | |
print ctx "})(window);"; | |
(* --patch-- *) | |
let ch = open_out_bin com.file in | |
output_string ch (Buffer.contents ctx.buf); | |
close_out ch); | |
t() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- E:/haxe-svn/genjs.ml Wed Oct 19 21:46:12 2011 | |
+++ C:/Users/Skial/Dropbox/dev/Example_New_Javascript/genjs.ml Thu Oct 20 16:30:41 2011 | |
@@ -646,10 +646,13 @@ | |
Hashtbl.add ctx.packages (p :: acc) (); | |
(match acc with | |
| [] -> | |
- print ctx "if(typeof %s=='undefined') var %s = {}" p p; | |
+ (* ++patch++ *) | |
+ print ctx "var %s = {}" p; | |
+ | |
+ (* --patch-- *) | |
| _ -> | |
let p = String.concat "." (List.rev acc) ^ (field p) in | |
- print ctx "if(!%s) %s = {}" p p); | |
+ print ctx "%s = {}" p); | |
newline ctx; | |
loop (p :: acc) l | |
in | |
@@ -715,8 +718,12 @@ | |
print ctx "%s = " p; | |
(match c.cl_constructor with | |
| Some { cf_expr = Some e } -> gen_constructor ctx e | |
- | _ -> print ctx "function() { }"); | |
+ | _ -> print ctx "function() {}"); | |
+ newline ctx; | |
+ (* ++patch++ *) | |
+ print ctx "$hxClasses[\"%s\"] = %s" p p; | |
newline ctx; | |
+ (* --patch-- *) | |
print ctx "%s.__name__ = [%s]" p (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst c.cl_path @ [snd c.cl_path]))); | |
newline ctx; | |
(match c.cl_implements with | |
@@ -743,7 +750,10 @@ | |
print ctx "__class__: %s" p; | |
bend(); | |
- print ctx "\n}"; | |
+ (* ++patch++ *) | |
+ print ctx "\n%s" ctx.tabs; | |
+ print ctx "}"; | |
+ (* --patch-- *) | |
(match c.cl_super with None -> () | _ -> print ctx ")"); | |
newline ctx | |
@@ -753,6 +763,10 @@ | |
let ename = List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst e.e_path @ [snd e.e_path]) in | |
print ctx "%s = { __ename__ : [%s], __constructs__ : [%s] }" p (String.concat "," ename) (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" s) e.e_names)); | |
newline ctx; | |
+ (* ++patch++ *) | |
+ print ctx "$hxClasses[\"%s\"] = %s" p p; | |
+ newline ctx; | |
+ (* --patch-- *) | |
List.iter (fun n -> | |
let f = PMap.find n e.e_constrs in | |
print ctx "%s%s = " p (field f.ef_name); | |
@@ -831,17 +845,25 @@ | |
| Some g -> g() | |
| None -> | |
let ctx = alloc_ctx com in | |
- print ctx "var $_, $estr = function() { return js.Boot.__string_rec(this,''); } | |
-function $extend(from, fields) { | |
- function inherit() {}; inherit.prototype = from; var proto = new inherit(); | |
- for (var name in fields) proto[name] = fields[name]; | |
- return proto; | |
-}"; | |
+ | |
+ (* ++patch++ *) | |
+ print ctx "(function (context) {\n"; | |
+ ctx.tabs <- "\t"; | |
+ (* --patch-- *) | |
+ | |
+ print ctx "\tvar $_, $hxClasses = {}, $estr = function() { return js.Boot.__string_rec(this, ''); }; | |
+ function $extend(from, fields) { | |
+ function inherit() {}; inherit.prototype = from; var proto = new inherit(); | |
+ for (var name in fields) proto[name] = fields[name]; | |
+ return proto; | |
+ }"; | |
newline ctx; | |
(match ctx.namespace with | |
| None -> () | |
| Some ns -> | |
- print ctx "if(typeof %s=='undefined') var %s = {}" ns ns; | |
+ (* ++patch++ *) | |
+ print ctx "var %s = {}" ns; | |
+ (* --patch-- *) | |
newline ctx); | |
List.iter (generate_type ctx) com.types; | |
print ctx "js.Boot.__res = {}"; | |
@@ -859,14 +881,26 @@ | |
end; | |
print ctx "js.Boot.__init()"; | |
newline ctx; | |
+ | |
+ (* static __init__ method creation *) | |
List.iter (fun e -> | |
gen_expr ctx e; | |
newline ctx; | |
) (List.rev ctx.inits); | |
+ | |
List.iter (generate_static ctx) (List.rev ctx.statics); | |
(match com.main with | |
| None -> () | |
| Some e -> gen_expr ctx e); | |
+ | |
+ (* ++patch++ *) | |
+ newline ctx; | |
+ print ctx "context[\"haxe\"] = haxe;"; | |
+ print ctx "\n"; | |
+ ctx.tabs <- ""; | |
+ print ctx "})(window);"; | |
+ (* --patch-- *) | |
+ | |
let ch = open_out_bin com.file in | |
output_string ch (Buffer.contents ctx.buf); | |
close_out ch); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2005, The haXe Project Contributors | |
* All rights reserved. | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* - Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* - Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY | |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR | |
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
* DAMAGE. | |
*/ | |
enum ValueType { | |
TNull; | |
TInt; | |
TFloat; | |
TBool; | |
TObject; | |
TFunction; | |
TClass( c : Class<Dynamic> ); | |
TEnum( e : Enum<Dynamic> ); | |
TUnknown; | |
} | |
@:core_api class Type { | |
public static function getClass<T>( o : T ) : Class<T> untyped { | |
if( o == null ) | |
return null; | |
if( o.__enum__ != null ) | |
return null; | |
return o.__class__; | |
} | |
public static function getEnum( o : Dynamic ) : Enum<Dynamic> untyped { | |
if( o == null ) | |
return null; | |
return o.__enum__; | |
} | |
public static function getSuperClass( c : Class<Dynamic> ) : Class<Dynamic> untyped { | |
return c.__super__; | |
} | |
public static function getClassName( c : Class<Dynamic> ) : String { | |
var a : Array<String> = untyped c.__name__; | |
return a.join("."); | |
} | |
public static function getEnumName( e : Enum<Dynamic> ) : String { | |
var a : Array<String> = untyped e.__ename__; | |
return a.join("."); | |
} | |
public static function resolveClass( name : String ) : Class<Dynamic> untyped { | |
var cl : Class<Dynamic>; | |
try { | |
#if js_namespace | |
if (name.indexOf('.') < 0) | |
cl = eval(js.Boot.__ns + '.' + name); | |
else | |
cl = eval(name); | |
#else | |
cl = $hxClasses[name]; | |
#end | |
} catch( e : Dynamic ) { | |
cl = null; | |
} | |
// ensure that this is a class | |
if( cl == null || cl.__name__ == null ) | |
return null; | |
return cl; | |
} | |
public static function resolveEnum( name : String ) : Enum<Dynamic> untyped { | |
var e : Dynamic; | |
try { | |
#if js_namespace | |
if (name.indexOf('.') < 0) | |
e = eval(js.Boot.__ns + '.' + name); | |
else | |
e = eval(name); | |
#else | |
e = $hxClasses(name); | |
#end | |
} catch( err : Dynamic ) { | |
e = null; | |
} | |
// ensure that this is an enum | |
if( e == null || e.__ename__ == null ) | |
return null; | |
return e; | |
} | |
public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T untyped { | |
if( args.length <= 3 ) | |
return __new__(cl,args[0],args[1],args[2]); | |
if( args.length > 8 ) | |
throw "Too many arguments"; | |
return __new__(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]); | |
} | |
public static function createEmptyInstance<T>( cl : Class<T> ) : T untyped { | |
__js__("function empty() {}; empty.prototype = cl.prototype"); | |
return __js__("new empty()"); | |
} | |
public static function createEnum<T>( e : Enum<T>, constr : String, ?params : Array<Dynamic> ) : T { | |
var f = Reflect.field(e,constr); | |
if( f == null ) throw "No such constructor "+constr; | |
if( Reflect.isFunction(f) ) { | |
if( params == null ) throw "Constructor "+constr+" need parameters"; | |
return Reflect.callMethod(e,f,params); | |
} | |
if( params != null && params.length != 0 ) | |
throw "Constructor "+constr+" does not need parameters"; | |
return f; | |
} | |
public static function createEnumIndex<T>( e : Enum<T>, index : Int, ?params : Array<Dynamic> ) : T { | |
var c : String = (untyped e.__constructs__)[index]; | |
if( c == null ) throw index+" is not a valid enum constructor index"; | |
return createEnum(e,c,params); | |
} | |
public static function getInstanceFields( c : Class<Dynamic> ) : Array<String> { | |
var a = []; | |
untyped __js__("for(var i in c.prototype) a.push(i)"); | |
a.remove("__class__"); | |
return a; | |
} | |
public static function getClassFields( c : Class<Dynamic> ) : Array<String> { | |
var a = Reflect.fields(c); | |
a.remove(__unprotect__("__name__")); | |
a.remove(__unprotect__("__interfaces__")); | |
a.remove(__unprotect__("__super__")); | |
a.remove("prototype"); | |
return a; | |
} | |
public static function getEnumConstructs( e : Enum<Dynamic> ) : Array<String> { | |
var a : Array<String> = untyped e.__constructs__; | |
return a.copy(); | |
} | |
public static function typeof( v : Dynamic ) : ValueType untyped { | |
switch( __js__("typeof")(v) ) { | |
case "boolean": return TBool; | |
case "string": return TClass(String); | |
case "number": | |
// this should handle all cases : NaN, +/-Inf and Floats outside range | |
if( Math.ceil(v) == v%2147483648.0 ) | |
return TInt; | |
return TFloat; | |
case "object": | |
if( v == null ) | |
return TNull; | |
var e = v.__enum__; | |
if( e != null ) | |
return TEnum(e); | |
var c = v.__class__; | |
if( c != null ) | |
return TClass(c); | |
return TObject; | |
case "function": | |
if( v.__name__ != null ) | |
return TObject; | |
return TFunction; | |
case "undefined": | |
return TNull; | |
default: | |
return TUnknown; | |
} | |
} | |
public static function enumEq<T>( a : T, b : T ) : Bool untyped { | |
if( a == b ) | |
return true; | |
try { | |
if( a[0] != b[0] ) | |
return false; | |
for( i in 2...a.length ) | |
if( !enumEq(a[i],b[i]) ) | |
return false; | |
var e = a.__enum__; | |
if( e != b.__enum__ || e == null ) | |
return false; | |
} catch( e : Dynamic ) { | |
return false; | |
} | |
return true; | |
} | |
public inline static function enumConstructor( e : Dynamic ) : String { | |
return e[0]; | |
} | |
public inline static function enumParameters( e : Dynamic ) : Array<Dynamic> { | |
return e.slice(2); | |
} | |
public inline static function enumIndex( e : Dynamic ) : Int { | |
return e[1]; | |
} | |
public static function allEnums<T>( e : Enum<T> ) : Array<T> { | |
var all = []; | |
var cst : Array<String> = untyped e.__constructs__; | |
for( c in cst ) { | |
var v = Reflect.field(e,c); | |
if( !Reflect.isFunction(v) ) | |
all.push(v); | |
} | |
return all; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment