|
@@ -29,8 +29,6 @@ open Printf
|
|
open Option
|
|
open Option
|
|
open ExtString
|
|
open ExtString
|
|
|
|
|
|
-module SS = Set.Make(String)
|
|
|
|
-
|
|
|
|
let is_boxed_type t = match follow t with
|
|
let is_boxed_type t = match follow t with
|
|
| TInst ({ cl_path = (["java";"lang"], "Boolean") }, [])
|
|
| TInst ({ cl_path = (["java";"lang"], "Boolean") }, [])
|
|
| TInst ({ cl_path = (["java";"lang"], "Double") }, [])
|
|
| TInst ({ cl_path = (["java";"lang"], "Double") }, [])
|
|
@@ -2474,21 +2472,6 @@ let configure gen =
|
|
|
|
|
|
(* end of configure function *)
|
|
(* end of configure function *)
|
|
|
|
|
|
-let before_generate con =
|
|
|
|
- let java_ver = try
|
|
|
|
- int_of_string (PMap.find "java_ver" con.defines)
|
|
|
|
- with | Not_found ->
|
|
|
|
- Common.define_value con Define.JavaVer "7";
|
|
|
|
- 7
|
|
|
|
- in
|
|
|
|
- if java_ver < 5 then failwith ("Java version is defined to target Java " ^ string_of_int java_ver ^ ", but the compiler can only output code to versions equal or superior to Java 5");
|
|
|
|
- let rec loop i =
|
|
|
|
- Common.raw_define con ("java" ^ (string_of_int i));
|
|
|
|
- if i > 0 then loop (i - 1)
|
|
|
|
- in
|
|
|
|
- loop java_ver;
|
|
|
|
- ()
|
|
|
|
-
|
|
|
|
let generate con =
|
|
let generate con =
|
|
let exists = ref false in
|
|
let exists = ref false in
|
|
con.java_libs <- List.map (fun (file,std,close,la,gr) ->
|
|
con.java_libs <- List.map (fun (file,std,close,la,gr) ->
|
|
@@ -2521,1120 +2504,3 @@ let generate con =
|
|
configure gen
|
|
configure gen
|
|
with | TypeNotFound path -> con.error ("Error. Module '" ^ (s_type_path path) ^ "' is required and was not included in build.") null_pos);
|
|
with | TypeNotFound path -> con.error ("Error. Module '" ^ (s_type_path path) ^ "' is required and was not included in build.") null_pos);
|
|
debug_mode := false
|
|
debug_mode := false
|
|
-
|
|
|
|
-(** Java lib *)
|
|
|
|
-
|
|
|
|
-open JData
|
|
|
|
-
|
|
|
|
-type java_lib_ctx = {
|
|
|
|
- jcom : Common.context;
|
|
|
|
- (* current tparams context *)
|
|
|
|
- mutable jtparams : jtypes list;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-exception ConversionError of string * pos
|
|
|
|
-
|
|
|
|
-let error s p = raise (ConversionError (s, p))
|
|
|
|
-
|
|
|
|
-let is_haxe_keyword = function
|
|
|
|
- | "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true
|
|
|
|
- | _ -> false
|
|
|
|
-
|
|
|
|
-let jname_to_hx name =
|
|
|
|
- let name =
|
|
|
|
- if name <> "" && (String.get name 0 < 'A' || String.get name 0 > 'Z') then
|
|
|
|
- Char.escaped (Char.uppercase (String.get name 0)) ^ String.sub name 1 (String.length name - 1)
|
|
|
|
- else
|
|
|
|
- name
|
|
|
|
- in
|
|
|
|
- let name = String.concat "__" (String.nsplit name "_") in
|
|
|
|
- String.map (function | '$' -> '_' | c -> c) name
|
|
|
|
-
|
|
|
|
-let normalize_pack pack =
|
|
|
|
- List.map (function
|
|
|
|
- | "" -> ""
|
|
|
|
- | str when String.get str 0 >= 'A' && String.get str 0 <= 'Z' ->
|
|
|
|
- String.lowercase str
|
|
|
|
- | str -> str
|
|
|
|
- ) pack
|
|
|
|
-
|
|
|
|
-let jpath_to_hx (pack,name) = match pack, name with
|
|
|
|
- | ["haxe";"root"], name -> [], name
|
|
|
|
- | "com" :: ("oracle" | "sun") :: _, _
|
|
|
|
- | "javax" :: _, _
|
|
|
|
- | "org" :: ("ietf" | "jcp" | "omg" | "w3c" | "xml") :: _, _
|
|
|
|
- | "sun" :: _, _
|
|
|
|
- | "sunw" :: _, _ -> "java" :: normalize_pack pack, jname_to_hx name
|
|
|
|
- | pack, name -> normalize_pack pack, jname_to_hx name
|
|
|
|
-
|
|
|
|
-let real_java_path ctx (pack,name) =
|
|
|
|
- s_type_path (pack, name)
|
|
|
|
-
|
|
|
|
-let lookup_jclass com path =
|
|
|
|
- let path = jpath_to_hx path in
|
|
|
|
- List.fold_right (fun (_,_,_,_,get_raw_class) acc ->
|
|
|
|
- match acc with
|
|
|
|
- | None -> get_raw_class path
|
|
|
|
- | Some p -> Some p
|
|
|
|
- ) com.java_libs None
|
|
|
|
-
|
|
|
|
-let mk_type_path ctx path params =
|
|
|
|
- let name, sub = try
|
|
|
|
- let p, _ = String.split (snd path) "$" in
|
|
|
|
- jname_to_hx p, Some (jname_to_hx (snd path))
|
|
|
|
- with | Invalid_string ->
|
|
|
|
- jname_to_hx (snd path), None
|
|
|
|
- in
|
|
|
|
- let pack = fst (jpath_to_hx path) in
|
|
|
|
- let pack, sub, name = match path with
|
|
|
|
- | [], ("Float" as c)
|
|
|
|
- | [], ("Int" as c)
|
|
|
|
- | [], ("Single" as c)
|
|
|
|
- | [], ("Bool" as c)
|
|
|
|
- | [], ("Dynamic" as c)
|
|
|
|
- | [], ("Iterator" as c)
|
|
|
|
- | [], ("ArrayAccess" as c)
|
|
|
|
- | [], ("Iterable" as c) ->
|
|
|
|
- [], Some c, "StdTypes"
|
|
|
|
- | [], ("String" as c) ->
|
|
|
|
- ["std"], None, c
|
|
|
|
- | _ ->
|
|
|
|
- pack, sub, name
|
|
|
|
- in
|
|
|
|
- CTPath {
|
|
|
|
- tpackage = pack;
|
|
|
|
- tname = name;
|
|
|
|
- tparams = params;
|
|
|
|
- tsub = sub;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-let has_tparam name params = List.exists(fun (n,_,_) -> n = name) params
|
|
|
|
-
|
|
|
|
-let rec convert_arg ctx p arg =
|
|
|
|
- match arg with
|
|
|
|
- | TAny | TType (WSuper, _) -> TPType (mk_type_path ctx ([], "Dynamic") [],null_pos)
|
|
|
|
- | TType (_, jsig) -> TPType (convert_signature ctx p jsig,null_pos)
|
|
|
|
-
|
|
|
|
-and convert_signature ctx p jsig =
|
|
|
|
- match jsig with
|
|
|
|
- | TByte -> mk_type_path ctx (["java"; "types"], "Int8") []
|
|
|
|
- | TChar -> mk_type_path ctx (["java"; "types"], "Char16") []
|
|
|
|
- | TDouble -> mk_type_path ctx ([], "Float") []
|
|
|
|
- | TFloat -> mk_type_path ctx ([], "Single") []
|
|
|
|
- | TInt -> mk_type_path ctx ([], "Int") []
|
|
|
|
- | TLong -> mk_type_path ctx (["haxe"], "Int64") []
|
|
|
|
- | TShort -> mk_type_path ctx (["java"; "types"], "Int16") []
|
|
|
|
- | TBool -> mk_type_path ctx ([], "Bool") []
|
|
|
|
- | TObject ( (["haxe";"root"], name), args ) -> mk_type_path ctx ([], name) (List.map (convert_arg ctx p) args)
|
|
|
|
- (** nullable types *)
|
|
|
|
- (* replaced from Null<Type> to the actual abstract type to fix #2738 *)
|
|
|
|
- (* | TObject ( (["java";"lang"], "Integer"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Int") []) ] *)
|
|
|
|
- (* | TObject ( (["java";"lang"], "Double"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Float") []) ] *)
|
|
|
|
- (* | TObject ( (["java";"lang"], "Float"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Single") []) ] *)
|
|
|
|
- (* | TObject ( (["java";"lang"], "Boolean"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Bool") []) ] *)
|
|
|
|
- (* | TObject ( (["java";"lang"], "Byte"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int8") []) ] *)
|
|
|
|
- (* | TObject ( (["java";"lang"], "Character"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Char16") []) ] *)
|
|
|
|
- (* | TObject ( (["java";"lang"], "Short"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int16") []) ] *)
|
|
|
|
- (* | TObject ( (["java";"lang"], "Long"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["haxe"], "Int64") []) ] *)
|
|
|
|
- (** other std types *)
|
|
|
|
- | TObject ( (["java";"lang"], "Object"), [] ) -> mk_type_path ctx ([], "Dynamic") []
|
|
|
|
- | TObject ( (["java";"lang"], "String"), [] ) -> mk_type_path ctx ([], "String") []
|
|
|
|
- | TObject ( (["java";"lang"], "Enum"), [_] ) -> mk_type_path ctx ([], "EnumValue") []
|
|
|
|
- (** other types *)
|
|
|
|
- | TObject ( path, [] ) ->
|
|
|
|
- (match lookup_jclass ctx.jcom path with
|
|
|
|
- | Some (jcl, _, _) -> mk_type_path ctx path (List.map (fun _ -> convert_arg ctx p TAny) jcl.ctypes)
|
|
|
|
- | None -> mk_type_path ctx path [])
|
|
|
|
- | TObject ( path, args ) -> mk_type_path ctx path (List.map (convert_arg ctx p) args)
|
|
|
|
- | TObjectInner (pack, (name, params) :: inners) ->
|
|
|
|
- let actual_param = match List.rev inners with
|
|
|
|
- | (_, p) :: _ -> p
|
|
|
|
- | _ -> assert false in
|
|
|
|
- mk_type_path ctx (pack, name ^ "$" ^ String.concat "$" (List.map fst inners)) (List.map (fun param -> convert_arg ctx p param) actual_param)
|
|
|
|
- | TObjectInner (pack, inners) -> assert false
|
|
|
|
- | TArray (jsig, _) -> mk_type_path ctx (["java"], "NativeArray") [ TPType (convert_signature ctx p jsig,null_pos) ]
|
|
|
|
- | TMethod _ -> JReader.error "TMethod cannot be converted directly into Complex Type"
|
|
|
|
- | TTypeParameter s -> (match ctx.jtparams with
|
|
|
|
- | cur :: others ->
|
|
|
|
- if has_tparam s cur then
|
|
|
|
- mk_type_path ctx ([], s) []
|
|
|
|
- else begin
|
|
|
|
- if ctx.jcom.verbose && not(List.exists (has_tparam s) others) then print_endline ("Type parameter " ^ s ^ " was not found while building type!");
|
|
|
|
- mk_type_path ctx ([], "Dynamic") []
|
|
|
|
- end
|
|
|
|
- | _ ->
|
|
|
|
- if ctx.jcom.verbose then print_endline ("Empty type parameter stack!");
|
|
|
|
- mk_type_path ctx ([], "Dynamic") [])
|
|
|
|
-
|
|
|
|
-let convert_constant ctx p const =
|
|
|
|
- Option.map_default (function
|
|
|
|
- | ConstString s -> Some (EConst (String s), p)
|
|
|
|
- | ConstInt i -> Some (EConst (Int (Printf.sprintf "%ld" i)), p)
|
|
|
|
- | ConstFloat f | ConstDouble f -> Some (EConst (Float (Printf.sprintf "%E" f)), p)
|
|
|
|
- | _ -> None) None const
|
|
|
|
-
|
|
|
|
-let rec same_sig parent jsig =
|
|
|
|
- match jsig with
|
|
|
|
- | TObject (p,targs) -> parent = p || List.exists (function | TType (_,s) -> same_sig parent s | _ -> false) targs
|
|
|
|
- | TObjectInner(p, ntargs) ->
|
|
|
|
- parent = (p, String.concat "$" (List.map fst ntargs)) ||
|
|
|
|
- List.exists (fun (_,targs) -> List.exists (function | TType(_,s) -> same_sig parent s | _ -> false) targs) ntargs
|
|
|
|
- | TArray(s,_) -> same_sig parent s
|
|
|
|
- | _ -> false
|
|
|
|
-
|
|
|
|
-let convert_param ctx p parent param =
|
|
|
|
- let name, constraints = match param with
|
|
|
|
- | (name, Some extends_sig, implem_sig) ->
|
|
|
|
- name, extends_sig :: implem_sig
|
|
|
|
- | (name, None, implemem_sig) ->
|
|
|
|
- name, implemem_sig
|
|
|
|
- in
|
|
|
|
- let constraints = List.map (fun s -> if same_sig parent s then (TObject( (["java";"lang"], "Object"), [])) else s) constraints in
|
|
|
|
- {
|
|
|
|
- tp_name = name,null_pos;
|
|
|
|
- tp_params = [];
|
|
|
|
- tp_constraints = List.map (fun t -> convert_signature ctx p t,null_pos) constraints;
|
|
|
|
- tp_meta = [];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-let get_type_path ctx ct = match ct with | CTPath p -> p | _ -> assert false
|
|
|
|
-
|
|
|
|
-let is_override field =
|
|
|
|
- List.exists (function | AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), _ ) }] -> true | _ -> false) field.jf_attributes
|
|
|
|
-
|
|
|
|
-let mk_override field =
|
|
|
|
- { field with jf_attributes = ((AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), [] ); ann_elements = [] }]) :: field.jf_attributes) }
|
|
|
|
-
|
|
|
|
-let del_override field =
|
|
|
|
- { field with jf_attributes = List.filter (fun a -> not (is_override_attrib a)) field.jf_attributes }
|
|
|
|
-
|
|
|
|
-let get_canonical ctx p pack name =
|
|
|
|
- (Meta.JavaCanonical, [EConst (String (String.concat "." pack)), p; EConst (String name), p], p)
|
|
|
|
-
|
|
|
|
-let convert_java_enum ctx p pe =
|
|
|
|
- let meta = ref (get_canonical ctx p (fst pe.cpath) (snd pe.cpath) :: [Meta.Native, [EConst (String (real_java_path ctx pe.cpath) ), p], p ]) in
|
|
|
|
- let data = ref [] in
|
|
|
|
- List.iter (fun f ->
|
|
|
|
- (* if List.mem JEnum f.jf_flags then *)
|
|
|
|
- match f.jf_vmsignature with
|
|
|
|
- | TObject( path, [] ) when path = pe.cpath && List.mem JStatic f.jf_flags && List.mem JFinal f.jf_flags ->
|
|
|
|
- data := { ec_name = f.jf_name,null_pos; ec_doc = None; ec_meta = []; ec_args = []; ec_pos = p; ec_params = []; ec_type = None; } :: !data;
|
|
|
|
- | _ -> ()
|
|
|
|
- ) pe.cfields;
|
|
|
|
-
|
|
|
|
- EEnum {
|
|
|
|
- d_name = jname_to_hx (snd pe.cpath),null_pos;
|
|
|
|
- d_doc = None;
|
|
|
|
- d_params = []; (* enums never have type parameters *)
|
|
|
|
- d_meta = !meta;
|
|
|
|
- d_flags = [EExtern];
|
|
|
|
- d_data = List.rev !data;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let convert_java_field ctx p jc field =
|
|
|
|
- let p = { p with pfile = p.pfile ^" (" ^field.jf_name ^")" } in
|
|
|
|
- let cff_doc = None in
|
|
|
|
- let cff_pos = p in
|
|
|
|
- let cff_meta = ref [] in
|
|
|
|
- let cff_access = ref [] in
|
|
|
|
- let cff_name = match field.jf_name with
|
|
|
|
- | "<init>" -> "new"
|
|
|
|
- | "<clinit>"-> raise Exit (* __init__ field *)
|
|
|
|
- | name when String.length name > 5 ->
|
|
|
|
- (match String.sub name 0 5 with
|
|
|
|
- | "__hx_" | "this$" -> raise Exit
|
|
|
|
- | _ -> name)
|
|
|
|
- | name -> name
|
|
|
|
- in
|
|
|
|
- let jf_constant = ref field.jf_constant in
|
|
|
|
- let readonly = ref false in
|
|
|
|
-
|
|
|
|
- List.iter (function
|
|
|
|
- | JPublic -> cff_access := APublic :: !cff_access
|
|
|
|
- | JPrivate -> raise Exit (* private instances aren't useful on externs *)
|
|
|
|
- | JProtected -> cff_access := APrivate :: !cff_access
|
|
|
|
- | JStatic -> cff_access := AStatic :: !cff_access
|
|
|
|
- | JFinal ->
|
|
|
|
- cff_meta := (Meta.Final, [], p) :: !cff_meta;
|
|
|
|
- (match field.jf_kind, field.jf_vmsignature, field.jf_constant with
|
|
|
|
- | JKField, TObject _, _ ->
|
|
|
|
- jf_constant := None
|
|
|
|
- | JKField, _, Some _ ->
|
|
|
|
- readonly := true;
|
|
|
|
- jf_constant := None;
|
|
|
|
- | _ -> jf_constant := None)
|
|
|
|
- (* | JSynchronized -> cff_meta := (Meta.Synchronized, [], p) :: !cff_meta *)
|
|
|
|
- | JVolatile -> cff_meta := (Meta.Volatile, [], p) :: !cff_meta
|
|
|
|
- | JTransient -> cff_meta := (Meta.Transient, [], p) :: !cff_meta
|
|
|
|
- (* | JVarArgs -> cff_meta := (Meta.VarArgs, [], p) :: !cff_meta *)
|
|
|
|
- | _ -> ()
|
|
|
|
- ) field.jf_flags;
|
|
|
|
-
|
|
|
|
- List.iter (function
|
|
|
|
- | AttrDeprecated when jc.cpath <> (["java";"util"],"Date") -> cff_meta := (Meta.Deprecated, [], p) :: !cff_meta
|
|
|
|
- (* TODO: pass anotations as @:meta *)
|
|
|
|
- | AttrVisibleAnnotations ann ->
|
|
|
|
- List.iter (function
|
|
|
|
- | { ann_type = TObject( (["java";"lang"], "Override"), [] ) } ->
|
|
|
|
- cff_access := AOverride :: !cff_access
|
|
|
|
- | _ -> ()
|
|
|
|
- ) ann
|
|
|
|
- | _ -> ()
|
|
|
|
- ) field.jf_attributes;
|
|
|
|
-
|
|
|
|
- List.iter (fun jsig ->
|
|
|
|
- match convert_signature ctx p jsig with
|
|
|
|
- | CTPath path ->
|
|
|
|
- cff_meta := (Meta.Throws, [Ast.EConst (Ast.String (s_type_path (path.tpackage,path.tname))), p],p) :: !cff_meta
|
|
|
|
- | _ -> ()
|
|
|
|
- ) field.jf_throws;
|
|
|
|
-
|
|
|
|
- let kind = match field.jf_kind with
|
|
|
|
- | JKField when !readonly ->
|
|
|
|
- FProp (("default",null_pos), ("null",null_pos), Some (convert_signature ctx p field.jf_signature,null_pos), None)
|
|
|
|
- | JKField ->
|
|
|
|
- FVar (Some (convert_signature ctx p field.jf_signature,null_pos), None)
|
|
|
|
- | JKMethod ->
|
|
|
|
- match field.jf_signature with
|
|
|
|
- | TMethod (args, ret) ->
|
|
|
|
- let old_types = ctx.jtparams in
|
|
|
|
- (match ctx.jtparams with
|
|
|
|
- | c :: others -> ctx.jtparams <- (c @ field.jf_types) :: others
|
|
|
|
- | [] -> ctx.jtparams <- field.jf_types :: []);
|
|
|
|
- let i = ref 0 in
|
|
|
|
- let args = List.map (fun s ->
|
|
|
|
- incr i;
|
|
|
|
- ("param" ^ string_of_int !i,null_pos), false, [], Some(convert_signature ctx p s,null_pos), None
|
|
|
|
- ) args in
|
|
|
|
- let t = Option.map_default (convert_signature ctx p) (mk_type_path ctx ([], "Void") []) ret in
|
|
|
|
- cff_meta := (Meta.Overload, [], p) :: !cff_meta;
|
|
|
|
-
|
|
|
|
- let types = List.map (function
|
|
|
|
- | (name, Some ext, impl) ->
|
|
|
|
- {
|
|
|
|
- tp_name = name,null_pos;
|
|
|
|
- tp_params = [];
|
|
|
|
- tp_constraints = List.map (fun t -> convert_signature ctx p t,null_pos) (ext :: impl);
|
|
|
|
- tp_meta = [];
|
|
|
|
- }
|
|
|
|
- | (name, None, impl) ->
|
|
|
|
- {
|
|
|
|
- tp_name = name,null_pos;
|
|
|
|
- tp_params = [];
|
|
|
|
- tp_constraints = List.map (fun t -> convert_signature ctx p t,null_pos) (impl);
|
|
|
|
- tp_meta = [];
|
|
|
|
- }
|
|
|
|
- ) field.jf_types in
|
|
|
|
- ctx.jtparams <- old_types;
|
|
|
|
-
|
|
|
|
- FFun ({
|
|
|
|
- f_params = types;
|
|
|
|
- f_args = args;
|
|
|
|
- f_type = Some (t,null_pos);
|
|
|
|
- f_expr = None
|
|
|
|
- })
|
|
|
|
- | _ -> error "Method signature was expected" p
|
|
|
|
- in
|
|
|
|
- let cff_name, cff_meta =
|
|
|
|
- match String.get cff_name 0 with
|
|
|
|
- | '%' ->
|
|
|
|
- let name = (String.sub cff_name 1 (String.length cff_name - 1)) in
|
|
|
|
- if not (is_haxe_keyword name) then
|
|
|
|
- cff_meta := (Meta.Deprecated, [EConst(String(
|
|
|
|
- "This static field `_" ^ name ^ "` is deprecated and will be removed in later versions. Please use `" ^ name ^ "` instead")
|
|
|
|
- ),p], p) :: !cff_meta;
|
|
|
|
- "_" ^ name,
|
|
|
|
- (Meta.Native, [EConst (String (name) ), cff_pos], cff_pos) :: !cff_meta
|
|
|
|
- | _ ->
|
|
|
|
- match String.nsplit cff_name "$" with
|
|
|
|
- | [ no_dollar ] ->
|
|
|
|
- cff_name, !cff_meta
|
|
|
|
- | parts ->
|
|
|
|
- String.concat "_" parts,
|
|
|
|
- (Meta.Native, [EConst (String (cff_name) ), cff_pos], cff_pos) :: !cff_meta
|
|
|
|
- in
|
|
|
|
- if PMap.mem "java_loader_debug" ctx.jcom.defines then
|
|
|
|
- Printf.printf "\t%s%sfield %s : %s\n" (if List.mem AStatic !cff_access then "static " else "") (if List.mem AOverride !cff_access then "override " else "") cff_name (s_sig field.jf_signature);
|
|
|
|
-
|
|
|
|
- {
|
|
|
|
- cff_name = cff_name,null_pos;
|
|
|
|
- cff_doc = cff_doc;
|
|
|
|
- cff_pos = cff_pos;
|
|
|
|
- cff_meta = cff_meta;
|
|
|
|
- cff_access = !cff_access;
|
|
|
|
- cff_kind = kind
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let rec japply_params params jsig = match params with
|
|
|
|
- | [] -> jsig
|
|
|
|
- | _ -> match jsig with
|
|
|
|
- | TTypeParameter s -> (try
|
|
|
|
- List.assoc s params
|
|
|
|
- with | Not_found -> jsig)
|
|
|
|
- | TObject(p,tl) ->
|
|
|
|
- TObject(p, args params tl)
|
|
|
|
- | TObjectInner(sl, stll) ->
|
|
|
|
- TObjectInner(sl, List.map (fun (s,tl) -> (s, args params tl)) stll)
|
|
|
|
- | TArray(s,io) ->
|
|
|
|
- TArray(japply_params params s, io)
|
|
|
|
- | TMethod(sl, sopt) ->
|
|
|
|
- TMethod(List.map (japply_params params) sl, Option.map (japply_params params) sopt)
|
|
|
|
- | _ -> jsig
|
|
|
|
-
|
|
|
|
- and args params tl = match params with
|
|
|
|
- | [] -> tl
|
|
|
|
- | _ -> List.map (function
|
|
|
|
- | TAny -> TAny
|
|
|
|
- | TType(w,s) -> TType(w,japply_params params s)) tl
|
|
|
|
-
|
|
|
|
- let mk_params jtypes = List.map (fun (s,_,_) -> (s,TTypeParameter s)) jtypes
|
|
|
|
-
|
|
|
|
- let convert_java_class ctx p jc =
|
|
|
|
- match List.mem JEnum jc.cflags with
|
|
|
|
- | true -> (* is enum *)
|
|
|
|
- [convert_java_enum ctx p jc]
|
|
|
|
- | false ->
|
|
|
|
- let flags = ref [HExtern] in
|
|
|
|
- if PMap.mem "java_loader_debug" ctx.jcom.defines then begin
|
|
|
|
- let sup = jc.csuper :: jc.cinterfaces in
|
|
|
|
- print_endline ("converting " ^ (if List.mem JAbstract jc.cflags then "abstract " else "") ^ JData.path_s jc.cpath ^ " : " ^ (String.concat ", " (List.map s_sig sup)));
|
|
|
|
- end;
|
|
|
|
- (* todo: instead of JavaNative, use more specific definitions *)
|
|
|
|
- let meta = ref [Meta.JavaNative, [], p; Meta.Native, [EConst (String (real_java_path ctx jc.cpath) ), p], p; get_canonical ctx p (fst jc.cpath) (snd jc.cpath)] in
|
|
|
|
- let force_check = Common.defined ctx.jcom Define.ForceLibCheck in
|
|
|
|
- if not force_check then
|
|
|
|
- meta := (Meta.LibType,[],p) :: !meta;
|
|
|
|
-
|
|
|
|
- let is_interface = ref false in
|
|
|
|
- List.iter (fun f -> match f with
|
|
|
|
- | JFinal -> meta := (Meta.Final, [], p) :: !meta
|
|
|
|
- | JInterface ->
|
|
|
|
- is_interface := true;
|
|
|
|
- flags := HInterface :: !flags
|
|
|
|
- | JAbstract -> meta := (Meta.Abstract, [], p) :: !meta
|
|
|
|
- | JAnnotation -> meta := (Meta.Annotation, [], p) :: !meta
|
|
|
|
- | _ -> ()
|
|
|
|
- ) jc.cflags;
|
|
|
|
-
|
|
|
|
- (match jc.csuper with
|
|
|
|
- | TObject( (["java";"lang"], "Object"), _ ) -> ()
|
|
|
|
- | TObject( (["haxe";"lang"], "HxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta
|
|
|
|
- | _ -> flags := HExtends (get_type_path ctx (convert_signature ctx p jc.csuper),null_pos) :: !flags
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- List.iter (fun i ->
|
|
|
|
- match i with
|
|
|
|
- | TObject ( (["haxe";"lang"], "IHxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta
|
|
|
|
- | _ -> flags :=
|
|
|
|
- if !is_interface then
|
|
|
|
- HExtends (get_type_path ctx (convert_signature ctx p i),null_pos) :: !flags
|
|
|
|
- else
|
|
|
|
- HImplements (get_type_path ctx (convert_signature ctx p i),null_pos) :: !flags
|
|
|
|
- ) jc.cinterfaces;
|
|
|
|
-
|
|
|
|
- let fields = ref [] in
|
|
|
|
- let jfields = ref [] in
|
|
|
|
-
|
|
|
|
- if jc.cpath <> (["java";"lang"], "CharSequence") then
|
|
|
|
- List.iter (fun f ->
|
|
|
|
- try
|
|
|
|
- if !is_interface && List.mem JStatic f.jf_flags then
|
|
|
|
- ()
|
|
|
|
- else begin
|
|
|
|
- fields := convert_java_field ctx p jc f :: !fields;
|
|
|
|
- jfields := f :: !jfields
|
|
|
|
- end
|
|
|
|
- with
|
|
|
|
- | Exit -> ()
|
|
|
|
- ) (jc.cfields @ jc.cmethods);
|
|
|
|
-
|
|
|
|
- (* make sure the throws types are imported correctly *)
|
|
|
|
- let imports = List.concat (List.map (fun f ->
|
|
|
|
- List.map (fun jsig ->
|
|
|
|
- match convert_signature ctx p jsig with
|
|
|
|
- | CTPath path ->
|
|
|
|
- let pos = { p with pfile = p.pfile ^ " (" ^ f.jf_name ^" @:throws)" } in
|
|
|
|
- EImport( List.map (fun s -> s,pos) (path.tpackage @ [path.tname]), INormal )
|
|
|
|
- | _ -> assert false
|
|
|
|
- ) f.jf_throws
|
|
|
|
- ) jc.cmethods) in
|
|
|
|
-
|
|
|
|
- (EClass {
|
|
|
|
- d_name = jname_to_hx (snd jc.cpath),null_pos;
|
|
|
|
- d_doc = None;
|
|
|
|
- d_params = List.map (convert_param ctx p jc.cpath) jc.ctypes;
|
|
|
|
- d_meta = !meta;
|
|
|
|
- d_flags = !flags;
|
|
|
|
- d_data = !fields;
|
|
|
|
- }) :: imports
|
|
|
|
-
|
|
|
|
- let create_ctx com =
|
|
|
|
- {
|
|
|
|
- jcom = com;
|
|
|
|
- jtparams = [];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let rec has_type_param = function
|
|
|
|
- | TTypeParameter _ -> true
|
|
|
|
- | TMethod (lst, opt) -> List.exists has_type_param lst || Option.map_default has_type_param false opt
|
|
|
|
- | TArray (s,_) -> has_type_param s
|
|
|
|
- | TObjectInner (_, stpl) -> List.exists (fun (_,sigs) -> List.exists has_type_param_arg sigs) stpl
|
|
|
|
- | TObject(_, pl) -> List.exists has_type_param_arg pl
|
|
|
|
- | _ -> false
|
|
|
|
-
|
|
|
|
- and has_type_param_arg = function | TType(_,s) -> has_type_param s | _ -> false
|
|
|
|
-
|
|
|
|
-let rec japply_params jparams jsig = match jparams with
|
|
|
|
- | [] -> jsig
|
|
|
|
- | _ ->
|
|
|
|
- match jsig with
|
|
|
|
- | TObject(path,p) ->
|
|
|
|
- TObject(path, List.map (japply_params_tp jparams ) p)
|
|
|
|
- | TObjectInner(sl,stargl) ->
|
|
|
|
- TObjectInner(sl,List.map (fun (s,targ) -> (s, List.map (japply_params_tp jparams) targ)) stargl)
|
|
|
|
- | TArray(jsig,io) ->
|
|
|
|
- TArray(japply_params jparams jsig,io)
|
|
|
|
- | TMethod(args,ret) ->
|
|
|
|
- TMethod(List.map (japply_params jparams ) args, Option.map (japply_params jparams ) ret)
|
|
|
|
- | TTypeParameter s -> (try
|
|
|
|
- List.assoc s jparams
|
|
|
|
- with | Not_found -> jsig)
|
|
|
|
- | _ -> jsig
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-and japply_params_tp jparams jtype_argument = match jtype_argument with
|
|
|
|
- | TAny -> TAny
|
|
|
|
- | TType(w,jsig) -> TType(w,japply_params jparams jsig)
|
|
|
|
-
|
|
|
|
-let mk_jparams jtypes params = match jtypes, params with
|
|
|
|
- | [], [] -> []
|
|
|
|
- | _, [] -> List.map (fun (s,_,_) -> s, TObject( (["java";"lang"], "Object"), [] ) ) jtypes
|
|
|
|
- | _ -> List.map2 (fun (s,_,_) jt -> match jt with
|
|
|
|
- | TAny -> s, TObject((["java";"lang"],"Object"),[])
|
|
|
|
- | TType(_,jsig) -> s, jsig) jtypes params
|
|
|
|
-
|
|
|
|
-let rec compatible_signature_arg ?arg_test f1 f2 =
|
|
|
|
- let arg_test = match arg_test with
|
|
|
|
- | None -> (fun _ _ -> true)
|
|
|
|
- | Some a -> a
|
|
|
|
- in
|
|
|
|
- if f1 = f2 then
|
|
|
|
- true
|
|
|
|
- else match f1, f2 with
|
|
|
|
- | TObject(p,a), TObject(p2,a2) -> p = p2 && arg_test a a2
|
|
|
|
- | TObjectInner(sl, stal), TObjectInner(sl2, stal2) -> sl = sl2 && List.map fst stal = List.map fst stal2
|
|
|
|
- | TArray(s,_) , TArray(s2,_) -> compatible_signature_arg s s2
|
|
|
|
- | TTypeParameter t1 , TTypeParameter t2 -> t1 = t2
|
|
|
|
- | _ -> false
|
|
|
|
-
|
|
|
|
-let rec compatible_param p1 p2 = match p1, p2 with
|
|
|
|
- | TType (_,s1), TType(_,s2) -> compatible_signature_arg ~arg_test:compatible_tparams s1 s2
|
|
|
|
- | TAny, TType(_, TObject( (["java";"lang"],"Object"), _ )) -> true
|
|
|
|
- | TType(_, TObject( (["java";"lang"],"Object"), _ )), TAny -> true
|
|
|
|
- | _ -> false
|
|
|
|
-
|
|
|
|
-and compatible_tparams p1 p2 = try match p1, p2 with
|
|
|
|
- | [], [] -> true
|
|
|
|
- | _, [] ->
|
|
|
|
- let p2 = List.map (fun _ -> TAny) p1 in
|
|
|
|
- List.for_all2 compatible_param p1 p2
|
|
|
|
- | [], _ ->
|
|
|
|
- let p1 = List.map (fun _ -> TAny) p2 in
|
|
|
|
- List.for_all2 compatible_param p1 p2
|
|
|
|
- | _, _ ->
|
|
|
|
- List.for_all2 compatible_param p1 p2
|
|
|
|
- with | Invalid_argument("List.for_all2") -> false
|
|
|
|
-
|
|
|
|
-let get_adapted_sig f f2 = match f.jf_types with
|
|
|
|
- | [] ->
|
|
|
|
- f.jf_signature
|
|
|
|
- | _ ->
|
|
|
|
- let jparams = mk_jparams f.jf_types (List.map (fun (s,_,_) -> TType(WNone, TTypeParameter s)) f2.jf_types) in
|
|
|
|
- japply_params jparams f.jf_signature
|
|
|
|
-
|
|
|
|
-let compatible_methods f1 f2 =
|
|
|
|
- if List.length f1.jf_types <> List.length f2.jf_types then
|
|
|
|
- false
|
|
|
|
- else match (get_adapted_sig f1 f2), f2.jf_signature with
|
|
|
|
- | TMethod(a1,_), TMethod(a2,_) when List.length a1 = List.length a2 ->
|
|
|
|
- List.for_all2 compatible_signature_arg a1 a2
|
|
|
|
- | _ -> false
|
|
|
|
-
|
|
|
|
-let jcl_from_jsig com jsig =
|
|
|
|
- let path, params = match jsig with
|
|
|
|
- | TObject(path, params) ->
|
|
|
|
- path,params
|
|
|
|
- | TObjectInner(sl, stll) ->
|
|
|
|
- let last_params = ref [] in
|
|
|
|
- let real_path = sl, String.concat "$" (List.map (fun (s,p) -> last_params := p; s) stll) in
|
|
|
|
- real_path, !last_params
|
|
|
|
- | _ -> raise Not_found
|
|
|
|
- in
|
|
|
|
- match lookup_jclass com path with
|
|
|
|
- | None -> raise Not_found
|
|
|
|
- | Some(c,_,_) -> c,params
|
|
|
|
-
|
|
|
|
-let jclass_with_params com cls params = try
|
|
|
|
- match cls.ctypes with
|
|
|
|
- | [] -> cls
|
|
|
|
- | _ ->
|
|
|
|
- let jparams = mk_jparams cls.ctypes params in
|
|
|
|
- { cls with
|
|
|
|
- cfields = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cfields;
|
|
|
|
- cmethods = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cmethods;
|
|
|
|
- csuper = japply_params jparams cls.csuper;
|
|
|
|
- cinterfaces = List.map (japply_params jparams) cls.cinterfaces;
|
|
|
|
- }
|
|
|
|
- with Invalid_argument("List.map2") ->
|
|
|
|
- if com.verbose then prerr_endline ("Differing parameters for class: " ^ s_type_path cls.cpath);
|
|
|
|
- cls
|
|
|
|
-
|
|
|
|
-let is_object = function | TObject( (["java";"lang"], "Object"), [] ) -> true | _ -> false
|
|
|
|
-
|
|
|
|
-let is_tobject = function | TObject _ | TObjectInner _ -> true | _ -> false
|
|
|
|
-
|
|
|
|
-let simplify_args args =
|
|
|
|
- if List.for_all (function | TAny -> true | _ -> false) args then [] else args
|
|
|
|
-
|
|
|
|
-let compare_type com s1 s2 =
|
|
|
|
- if s1 = s2 then
|
|
|
|
- 0
|
|
|
|
- else if not (is_tobject s1) then
|
|
|
|
- if is_tobject s2 then (* Dynamic *)
|
|
|
|
- 1
|
|
|
|
- else if compatible_signature_arg s1 s2 then
|
|
|
|
- 0
|
|
|
|
- else
|
|
|
|
- raise Exit
|
|
|
|
- else if not (is_tobject s2) then
|
|
|
|
- -1
|
|
|
|
- else begin
|
|
|
|
- let rec loop ?(first_error=true) s1 s2 : bool =
|
|
|
|
- if is_object s1 then
|
|
|
|
- s1 = s2
|
|
|
|
- else if compatible_signature_arg s1 s2 then begin
|
|
|
|
- let p1, p2 = match s1, s2 with
|
|
|
|
- | TObject(_, p1), TObject(_,p2) ->
|
|
|
|
- p1, p2
|
|
|
|
- | TObjectInner(_, npl1), TObjectInner(_, npl2) ->
|
|
|
|
- snd (List.hd (List.rev npl1)), snd (List.hd (List.rev npl2))
|
|
|
|
- | _ -> assert false (* not tobject *)
|
|
|
|
- in
|
|
|
|
- let p1, p2 = simplify_args p1, simplify_args p2 in
|
|
|
|
- let lp1 = List.length p1 in
|
|
|
|
- let lp2 = List.length p2 in
|
|
|
|
- if lp1 > lp2 then
|
|
|
|
- true
|
|
|
|
- else if lp2 > lp1 then
|
|
|
|
- false
|
|
|
|
- else begin
|
|
|
|
- (* if compatible tparams, it's fine *)
|
|
|
|
- if not (compatible_tparams p1 p2) then
|
|
|
|
- raise Exit; (* meaning: found, but incompatible type parameters *)
|
|
|
|
- true
|
|
|
|
- end
|
|
|
|
- end else try
|
|
|
|
- let c, p = jcl_from_jsig com s1 in
|
|
|
|
- let jparams = mk_jparams c.ctypes p in
|
|
|
|
- let super = japply_params jparams c.csuper in
|
|
|
|
- let implements = List.map (japply_params jparams) c.cinterfaces in
|
|
|
|
- loop ~first_error:first_error super s2 || List.exists (fun super -> loop ~first_error:first_error super s2) implements
|
|
|
|
- with | Not_found ->
|
|
|
|
- prerr_endline ("-java-lib: The type " ^ (s_sig s1) ^ " is referred but was not found. Compilation may not occur correctly.");
|
|
|
|
- prerr_endline "Did you forget to include a needed lib?";
|
|
|
|
- if first_error then
|
|
|
|
- not (loop ~first_error:false s2 s1)
|
|
|
|
- else
|
|
|
|
- false
|
|
|
|
- in
|
|
|
|
- if loop s1 s2 then
|
|
|
|
- if loop s2 s1 then
|
|
|
|
- 0
|
|
|
|
- else
|
|
|
|
- 1
|
|
|
|
- else
|
|
|
|
- if loop s2 s1 then
|
|
|
|
- -1
|
|
|
|
- else
|
|
|
|
- -2
|
|
|
|
- end
|
|
|
|
-
|
|
|
|
-(* given a list of same overload functions, choose the best (or none) *)
|
|
|
|
-let select_best com flist =
|
|
|
|
- let rec loop cur_best = function
|
|
|
|
- | [] ->
|
|
|
|
- Some cur_best
|
|
|
|
- | f :: flist -> match get_adapted_sig f cur_best, cur_best.jf_signature with
|
|
|
|
- | TMethod(_,Some r), TMethod(_, Some r2) -> (try
|
|
|
|
- match compare_type com r r2 with
|
|
|
|
- | 0 -> (* same type - select any of them *)
|
|
|
|
- loop cur_best flist
|
|
|
|
- | 1 ->
|
|
|
|
- loop f flist
|
|
|
|
- | -1 ->
|
|
|
|
- loop cur_best flist
|
|
|
|
- | -2 -> (* error - no type is compatible *)
|
|
|
|
- if com.verbose then prerr_endline (f.jf_name ^ ": The types " ^ (s_sig r) ^ " and " ^ (s_sig r2) ^ " are incompatible");
|
|
|
|
- (* bet that the current best has "beaten" other types *)
|
|
|
|
- loop cur_best flist
|
|
|
|
- | _ -> assert false
|
|
|
|
- with | Exit -> (* incompatible type parameters *)
|
|
|
|
- (* error mode *)
|
|
|
|
- if com.verbose then prerr_endline (f.jf_name ^ ": Incompatible argument return signatures: " ^ (s_sig r) ^ " and " ^ (s_sig r2));
|
|
|
|
- None)
|
|
|
|
- | TMethod _, _ -> (* select the method *)
|
|
|
|
- loop f flist
|
|
|
|
- | _ ->
|
|
|
|
- loop cur_best flist
|
|
|
|
- in
|
|
|
|
- match loop (List.hd flist) (List.tl flist) with
|
|
|
|
- | Some f ->
|
|
|
|
- Some f
|
|
|
|
- | None -> match List.filter (fun f -> not (is_override f)) flist with
|
|
|
|
- (* error mode; take off all override methods *)
|
|
|
|
- | [] -> None
|
|
|
|
- | f :: [] -> Some f
|
|
|
|
- | f :: flist -> Some f (* pick one *)
|
|
|
|
-
|
|
|
|
-(**** begin normalize_jclass helpers ****)
|
|
|
|
-
|
|
|
|
-let fix_overrides_jclass com cls =
|
|
|
|
- let force_check = Common.defined com Define.ForceLibCheck in
|
|
|
|
- let methods = if force_check then List.map (fun f -> del_override f) cls.cmethods else cls.cmethods in
|
|
|
|
- let cmethods = methods in
|
|
|
|
- let super_fields = [] in
|
|
|
|
- let super_methods = [] in
|
|
|
|
- let nonstatics = List.filter (fun f -> not (List.mem JStatic f.jf_flags)) (cls.cfields @ cls.cmethods) in
|
|
|
|
-
|
|
|
|
- let is_pub = fun f -> List.exists (function | JPublic | JProtected -> true | _ -> false) f.jf_flags in
|
|
|
|
- let cmethods, super_fields = if not (List.mem JInterface cls.cflags) then
|
|
|
|
- List.filter is_pub cmethods,
|
|
|
|
- List.filter is_pub super_fields
|
|
|
|
- else
|
|
|
|
- cmethods,super_fields
|
|
|
|
- in
|
|
|
|
-
|
|
|
|
- let rec loop cls super_methods super_fields cmethods nonstatics = try
|
|
|
|
- match cls.csuper with
|
|
|
|
- | TObject((["java";"lang"],"Object"),_) ->
|
|
|
|
- super_methods,super_fields,cmethods,nonstatics
|
|
|
|
- | _ ->
|
|
|
|
- let cls, params = jcl_from_jsig com cls.csuper in
|
|
|
|
- let cls = jclass_with_params com cls params in
|
|
|
|
- let nonstatics = (List.filter (fun f -> (List.mem JStatic f.jf_flags)) (cls.cfields @ cls.cmethods)) @ nonstatics in
|
|
|
|
- let super_methods = cls.cmethods @ super_methods in
|
|
|
|
- let super_fields = cls.cfields @ super_fields in
|
|
|
|
- let cmethods = if force_check then begin
|
|
|
|
- let overriden = ref [] in
|
|
|
|
- let cmethods = List.map (fun jm ->
|
|
|
|
- (* TODO rewrite/standardize empty spaces *)
|
|
|
|
- if not (is_override jm) && not (List.mem JStatic jm.jf_flags) && List.exists (fun msup ->
|
|
|
|
- let ret = msup.jf_name = jm.jf_name && not(List.mem JStatic msup.jf_flags) && compatible_methods msup jm in
|
|
|
|
- if ret then begin
|
|
|
|
- let f = mk_override msup in
|
|
|
|
- overriden := { f with jf_flags = jm.jf_flags } :: !overriden
|
|
|
|
- end;
|
|
|
|
- ret
|
|
|
|
- ) cls.cmethods then
|
|
|
|
- mk_override jm
|
|
|
|
- else
|
|
|
|
- jm
|
|
|
|
- ) cmethods in
|
|
|
|
- !overriden @ cmethods
|
|
|
|
- end else
|
|
|
|
- cmethods
|
|
|
|
- in
|
|
|
|
- loop cls super_methods super_fields cmethods nonstatics
|
|
|
|
- with | Not_found ->
|
|
|
|
- super_methods,super_fields,cmethods,nonstatics
|
|
|
|
- in
|
|
|
|
- loop cls super_methods super_fields cmethods nonstatics
|
|
|
|
-
|
|
|
|
-let normalize_jclass com cls =
|
|
|
|
- (* after adding the noCheck metadata, this option will annotate what changes were needed *)
|
|
|
|
- (* and that are now deprecated *)
|
|
|
|
- let force_check = Common.defined com Define.ForceLibCheck in
|
|
|
|
- (* fix overrides *)
|
|
|
|
- let super_methods, super_fields, cmethods, nonstatics = fix_overrides_jclass com cls in
|
|
|
|
- let all_methods = cmethods @ super_methods in
|
|
|
|
-
|
|
|
|
- (* look for interfaces and add missing implementations (may happen on abstracts or by vmsig differences *)
|
|
|
|
- (* (libType): even with libType enabled, we need to add these missing fields - otherwise we won't be able to use them from Haxe *)
|
|
|
|
- let added_interface_fields = ref [] in
|
|
|
|
- let rec loop_interface abstract cls iface = try
|
|
|
|
- match iface with
|
|
|
|
- | TObject ((["java";"lang"],"Object"), _) -> ()
|
|
|
|
- | TObject (path,_) when path = cls.cpath -> ()
|
|
|
|
- | _ ->
|
|
|
|
- let cif, params = jcl_from_jsig com iface in
|
|
|
|
- let cif = jclass_with_params com cif params in
|
|
|
|
- List.iter (fun jf ->
|
|
|
|
- if not(List.mem JStatic jf.jf_flags) && not (List.exists (fun jf2 -> jf.jf_name = jf2.jf_name && not (List.mem JStatic jf2.jf_flags) && jf.jf_signature = jf2.jf_signature) all_methods) then begin
|
|
|
|
- let jf = if abstract && force_check then del_override jf else jf in
|
|
|
|
- let jf = { jf with jf_flags = JPublic :: jf.jf_flags } in (* interfaces implementations are always public *)
|
|
|
|
-
|
|
|
|
- added_interface_fields := jf :: !added_interface_fields;
|
|
|
|
- end
|
|
|
|
- ) cif.cmethods;
|
|
|
|
- (* we don't need to loop again in the interface unless we are in an abstract class, since these interfaces are already normalized *)
|
|
|
|
- if abstract then List.iter (loop_interface abstract cif) cif.cinterfaces;
|
|
|
|
- with Not_found -> ()
|
|
|
|
- in
|
|
|
|
- List.iter (loop_interface (List.mem JAbstract cls.cflags) cls) cls.cinterfaces;
|
|
|
|
- let nonstatics = !added_interface_fields @ nonstatics in
|
|
|
|
- let cmethods = !added_interface_fields @ cmethods in
|
|
|
|
-
|
|
|
|
- (* for each added field in the interface, lookup in super_methods possible methods to include *)
|
|
|
|
- (* so we can choose the better method still *)
|
|
|
|
- let cmethods = if not force_check then
|
|
|
|
- cmethods
|
|
|
|
- else
|
|
|
|
- List.fold_left (fun cmethods im ->
|
|
|
|
- (* see if any of the added_interface_fields need to be declared as override *)
|
|
|
|
- let f = List.find_all (fun jf -> jf.jf_name = im.jf_name && compatible_methods jf im) super_methods in
|
|
|
|
- let f = List.map mk_override f in
|
|
|
|
- f @ cmethods
|
|
|
|
- ) cmethods !added_interface_fields;
|
|
|
|
- in
|
|
|
|
-
|
|
|
|
- (* take off equals, hashCode and toString from interface *)
|
|
|
|
- let cmethods = if List.mem JInterface cls.cflags then List.filter (fun jf -> match jf.jf_name, jf.jf_vmsignature with
|
|
|
|
- | "equals", TMethod([TObject( (["java";"lang"],"Object"), _)],_)
|
|
|
|
- | "hashCode", TMethod([], _)
|
|
|
|
- | "toString", TMethod([], _) -> false
|
|
|
|
- | _ -> true
|
|
|
|
- ) cmethods
|
|
|
|
- else
|
|
|
|
- cmethods
|
|
|
|
- in
|
|
|
|
-
|
|
|
|
- (* change field name to not collide with haxe keywords and with static/non-static members *)
|
|
|
|
- let fold_field acc f =
|
|
|
|
- let change, both = match f.jf_name with
|
|
|
|
- | _ when List.mem JStatic f.jf_flags && List.exists (fun f2 -> f.jf_name = f2.jf_name) nonstatics -> true, true
|
|
|
|
- | _ -> is_haxe_keyword f.jf_name, false
|
|
|
|
- in
|
|
|
|
- let f2 = if change then
|
|
|
|
- { f with jf_name = "%" ^ f.jf_name }
|
|
|
|
- else
|
|
|
|
- f
|
|
|
|
- in
|
|
|
|
- if both then f :: f2 :: acc else f2 :: acc
|
|
|
|
- in
|
|
|
|
-
|
|
|
|
- (* change static fields that have the same name as methods *)
|
|
|
|
- let cfields = List.fold_left fold_field [] cls.cfields in
|
|
|
|
- let cmethods = List.fold_left fold_field [] cmethods in
|
|
|
|
- (* take off variable fields that have the same name as methods *)
|
|
|
|
- (* and take off variables that already have been declared *)
|
|
|
|
- let filter_field f f2 = f != f2 && (List.mem JStatic f.jf_flags = List.mem JStatic f2.jf_flags) && f.jf_name = f2.jf_name && f2.jf_kind <> f.jf_kind in
|
|
|
|
- let cfields = List.filter (fun f ->
|
|
|
|
- if List.mem JStatic f.jf_flags then
|
|
|
|
- not (List.exists (filter_field f) cmethods)
|
|
|
|
- else
|
|
|
|
- not (List.exists (filter_field f) nonstatics) && not (List.exists (fun f2 -> f != f2 && f.jf_name = f2.jf_name && not (List.mem JStatic f2.jf_flags)) super_fields) ) cfields
|
|
|
|
- in
|
|
|
|
- (* now filter any method that clashes with a field - on a superclass *)
|
|
|
|
- let cmethods = if force_check then List.filter (fun f ->
|
|
|
|
- if List.mem JStatic f.jf_flags then
|
|
|
|
- true
|
|
|
|
- else
|
|
|
|
- not (List.exists (filter_field f) super_fields) ) cmethods
|
|
|
|
- else
|
|
|
|
- cmethods
|
|
|
|
- in
|
|
|
|
- (* removing duplicate fields. They are there because of return type covariance in Java *)
|
|
|
|
- (* Also, if a method overrides a previous definition, and changes a type parameters' variance, *)
|
|
|
|
- (* we will take it off *)
|
|
|
|
- (* this means that some rare codes will never compile on Haxe, but unless Haxe adds variance support *)
|
|
|
|
- (* I can't see how this can be any different *)
|
|
|
|
- let rec loop acc = function
|
|
|
|
- | [] -> acc
|
|
|
|
- | f :: cmeths ->
|
|
|
|
- match List.partition (fun f2 -> f.jf_name = f2.jf_name && compatible_methods f f2) cmeths with
|
|
|
|
- | [], cmeths ->
|
|
|
|
- loop (f :: acc) cmeths
|
|
|
|
- | flist, cmeths -> match select_best com (f :: flist) with
|
|
|
|
- | None ->
|
|
|
|
- loop acc cmeths
|
|
|
|
- | Some f ->
|
|
|
|
- loop (f :: acc) cmeths
|
|
|
|
- in
|
|
|
|
- (* last pass: take off all cfields that are internal / private (they won't be accessible anyway) *)
|
|
|
|
- let cfields = List.filter(fun f -> List.exists (fun f -> f = JPublic || f = JProtected) f.jf_flags) cfields in
|
|
|
|
- let cmethods = loop [] cmethods in
|
|
|
|
- { cls with cfields = cfields; cmethods = cmethods }
|
|
|
|
-
|
|
|
|
-(**** end normalize_jclass helpers ****)
|
|
|
|
-
|
|
|
|
-let get_classes_zip zip =
|
|
|
|
- let ret = ref [] in
|
|
|
|
- List.iter (function
|
|
|
|
- | { Zip.is_directory = false; Zip.filename = f } when (String.sub (String.uncapitalize f) (String.length f - 6) 6) = ".class" && not (String.exists f "$") ->
|
|
|
|
- (match List.rev (String.nsplit f "/") with
|
|
|
|
- | clsname :: pack ->
|
|
|
|
- if not (String.contains clsname '$') then begin
|
|
|
|
- let path = jpath_to_hx (List.rev pack, String.sub clsname 0 (String.length clsname - 6)) in
|
|
|
|
- ret := path :: !ret
|
|
|
|
- end
|
|
|
|
- | _ ->
|
|
|
|
- ret := ([], jname_to_hx f) :: !ret)
|
|
|
|
- | _ -> ()
|
|
|
|
- ) (Zip.entries zip);
|
|
|
|
- !ret
|
|
|
|
-
|
|
|
|
-let add_java_lib com file std =
|
|
|
|
- let file = if Sys.file_exists file then
|
|
|
|
- file
|
|
|
|
- else try Common.find_file com file with
|
|
|
|
- | Not_found -> try Common.find_file com (file ^ ".jar") with
|
|
|
|
- | Not_found ->
|
|
|
|
- failwith ("Java lib " ^ file ^ " not found")
|
|
|
|
- in
|
|
|
|
- let hxpack_to_jpack = Hashtbl.create 16 in
|
|
|
|
- let get_raw_class, close, list_all_files =
|
|
|
|
- (* check if it is a directory or jar file *)
|
|
|
|
- match (Unix.stat file).st_kind with
|
|
|
|
- | S_DIR -> (* open classes directly from directory *)
|
|
|
|
- let all = ref [] in
|
|
|
|
- let rec iter_files pack dir path = try
|
|
|
|
- let file = Unix.readdir dir in
|
|
|
|
- let filepath = path ^ "/" ^ file in
|
|
|
|
- (if String.ends_with file ".class" && not (String.exists file "$") then
|
|
|
|
- let file = String.sub file 0 (String.length file - 6) in
|
|
|
|
- let path = jpath_to_hx (pack,file) in
|
|
|
|
- all := path :: !all;
|
|
|
|
- Hashtbl.add hxpack_to_jpack path (pack,file)
|
|
|
|
- else if (Unix.stat filepath).st_kind = S_DIR && file <> "." && file <> ".." then
|
|
|
|
- let pack = pack @ [file] in
|
|
|
|
- iter_files (pack) (Unix.opendir filepath) filepath);
|
|
|
|
- iter_files pack dir path
|
|
|
|
- with | End_of_file | Unix.Unix_error _ ->
|
|
|
|
- Unix.closedir dir
|
|
|
|
- in
|
|
|
|
- iter_files [] (Unix.opendir file) file;
|
|
|
|
- let all = !all in
|
|
|
|
-
|
|
|
|
- (fun (pack, name) ->
|
|
|
|
- let real_path = file ^ "/" ^ (String.concat "/" pack) ^ "/" ^ (name ^ ".class") in
|
|
|
|
- try
|
|
|
|
- let data = Std.input_file ~bin:true real_path in
|
|
|
|
- Some(JReader.parse_class (IO.input_string data), real_path, real_path)
|
|
|
|
- with
|
|
|
|
- | _ -> None), (fun () -> ()), (fun () -> all)
|
|
|
|
- | _ -> (* open zip file *)
|
|
|
|
- let closed = ref false in
|
|
|
|
- let zip = ref (Zip.open_in file) in
|
|
|
|
- let check_open () =
|
|
|
|
- if !closed then begin
|
|
|
|
- prerr_endline ("JAR file " ^ file ^ " already closed"); (* if this happens, find when *)
|
|
|
|
- zip := Zip.open_in file;
|
|
|
|
- closed := false
|
|
|
|
- end
|
|
|
|
- in
|
|
|
|
- List.iter (function
|
|
|
|
- | { Zip.is_directory = false; Zip.filename = filename } when String.ends_with filename ".class" ->
|
|
|
|
- let pack = String.nsplit filename "/" in
|
|
|
|
- (match List.rev pack with
|
|
|
|
- | [] -> ()
|
|
|
|
- | name :: pack ->
|
|
|
|
- let name = String.sub name 0 (String.length name - 6) in
|
|
|
|
- let pack = List.rev pack in
|
|
|
|
- Hashtbl.add hxpack_to_jpack (jpath_to_hx (pack,name)) (pack,name))
|
|
|
|
- | _ -> ()
|
|
|
|
- ) (Zip.entries !zip);
|
|
|
|
- (fun (pack, name) ->
|
|
|
|
- check_open();
|
|
|
|
- try
|
|
|
|
- let location = (String.concat "/" (pack @ [name]) ^ ".class") in
|
|
|
|
- let entry = Zip.find_entry !zip location in
|
|
|
|
- let data = Zip.read_entry !zip entry in
|
|
|
|
- Some(JReader.parse_class (IO.input_string data), file, file ^ "@" ^ location)
|
|
|
|
- with
|
|
|
|
- | Not_found ->
|
|
|
|
- None),
|
|
|
|
- (fun () -> if not !closed then begin closed := true; Zip.close_in !zip end),
|
|
|
|
- (fun () -> check_open(); get_classes_zip !zip)
|
|
|
|
- in
|
|
|
|
- let cached_types = Hashtbl.create 12 in
|
|
|
|
- let get_raw_class path =
|
|
|
|
- try
|
|
|
|
- Hashtbl.find cached_types path
|
|
|
|
- with | Not_found -> try
|
|
|
|
- let pack, name = Hashtbl.find hxpack_to_jpack path in
|
|
|
|
- let try_file (pack,name) =
|
|
|
|
- match get_raw_class (pack,name) with
|
|
|
|
- | None ->
|
|
|
|
- Hashtbl.add cached_types path None;
|
|
|
|
- None
|
|
|
|
- | Some (i, p1, p2) ->
|
|
|
|
- Hashtbl.add cached_types path (Some(i,p1,p2)); (* type loop normalization *)
|
|
|
|
- let ret = Some (normalize_jclass com i, p1, p2) in
|
|
|
|
- Hashtbl.replace cached_types path ret;
|
|
|
|
- ret
|
|
|
|
- in
|
|
|
|
- try_file (pack,name)
|
|
|
|
- with Not_found ->
|
|
|
|
- None
|
|
|
|
- in
|
|
|
|
- let replace_canonical_name p pack name_original name_replace decl =
|
|
|
|
- let mk_meta name = (Meta.JavaCanonical, [EConst (String (String.concat "." pack)), p; EConst(String name), p], p) in
|
|
|
|
- let add_meta name metas =
|
|
|
|
- if Meta.has Meta.JavaCanonical metas then
|
|
|
|
- List.map (function
|
|
|
|
- | (Meta.JavaCanonical,[EConst (String cpack), _; EConst(String cname), _],_) ->
|
|
|
|
- let did_replace,name = String.replace cname name_original name_replace in
|
|
|
|
- if not did_replace then print_endline (cname ^ " -> " ^ name_original ^ " -> " ^ name_replace);
|
|
|
|
- mk_meta name
|
|
|
|
- | m -> m
|
|
|
|
- ) metas
|
|
|
|
- else
|
|
|
|
- mk_meta name :: metas
|
|
|
|
- in
|
|
|
|
- match decl with
|
|
|
|
- | EClass c ->
|
|
|
|
- EClass { c with d_meta = add_meta (fst c.d_name) c.d_meta }
|
|
|
|
- | EEnum e ->
|
|
|
|
- EEnum { e with d_meta = add_meta (fst e.d_name) e.d_meta }
|
|
|
|
- | EAbstract a ->
|
|
|
|
- EAbstract { a with d_meta = add_meta (fst a.d_name) a.d_meta }
|
|
|
|
- | d -> d
|
|
|
|
- in
|
|
|
|
- let rec build ctx path p types =
|
|
|
|
- try
|
|
|
|
- if List.mem path !types then
|
|
|
|
- None
|
|
|
|
- else begin
|
|
|
|
- let first = match !types with
|
|
|
|
- | [ ["java";"lang"], "String" ] | [] -> true
|
|
|
|
- | p :: _ ->
|
|
|
|
- false
|
|
|
|
- in
|
|
|
|
- types := path :: !types;
|
|
|
|
- match get_raw_class path, path with
|
|
|
|
- | None, ([], c) -> build ctx (["haxe";"root"], c) p types
|
|
|
|
- | None, _ -> None
|
|
|
|
- | Some (cls, real_path, pos_path), _ ->
|
|
|
|
- let is_disallowed_inner = first && String.exists (snd cls.cpath) "$" in
|
|
|
|
- let is_disallowed_inner = if is_disallowed_inner then begin
|
|
|
|
- let outer, inner = String.split (snd cls.cpath) "$" in
|
|
|
|
- match get_raw_class (fst path, outer) with
|
|
|
|
- | None -> false
|
|
|
|
- | _ -> true
|
|
|
|
- end else
|
|
|
|
- false
|
|
|
|
- in
|
|
|
|
- if is_disallowed_inner then
|
|
|
|
- None
|
|
|
|
- else begin
|
|
|
|
- if com.verbose then print_endline ("Parsed Java class " ^ (s_type_path cls.cpath));
|
|
|
|
- let old_types = ctx.jtparams in
|
|
|
|
- ctx.jtparams <- cls.ctypes :: ctx.jtparams;
|
|
|
|
-
|
|
|
|
- let pos = { pfile = pos_path; pmin = 0; pmax = 0; } in
|
|
|
|
-
|
|
|
|
- let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
|
|
|
|
-
|
|
|
|
- let ppath = Hashtbl.find hxpack_to_jpack path in
|
|
|
|
- let inner = List.fold_left (fun acc (path,out,_,_) ->
|
|
|
|
- let path = jpath_to_hx path in
|
|
|
|
- (if out <> Some ppath then
|
|
|
|
- acc
|
|
|
|
- else match build ctx path p types with
|
|
|
|
- | Some(_,(_, classes)) ->
|
|
|
|
- let base = snd ppath ^ "$" in
|
|
|
|
- (List.map (fun (def,p) ->
|
|
|
|
- replace_canonical_name p (fst ppath) base (snd ppath ^ ".") def, p) classes) @ acc
|
|
|
|
- | _ -> acc);
|
|
|
|
- ) [] cls.cinner_types in
|
|
|
|
-
|
|
|
|
- (* add _Statics class *)
|
|
|
|
- let inner = try
|
|
|
|
- if not (List.mem JInterface cls.cflags) then raise Not_found;
|
|
|
|
- let smethods = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cmethods in
|
|
|
|
- let sfields = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cfields in
|
|
|
|
- if not (smethods <> [] || sfields <> []) then raise Not_found;
|
|
|
|
- let obj = TObject( (["java";"lang"],"Object"), []) in
|
|
|
|
- let ncls = convert_java_class ctx pos { cls with cmethods = smethods; cfields = sfields; cflags = []; csuper = obj; cinterfaces = []; cinner_types = []; ctypes = [] } in
|
|
|
|
- match ncls with
|
|
|
|
- | EClass c :: imports ->
|
|
|
|
- (EClass { c with d_name = (fst c.d_name ^ "_Statics"),snd c.d_name }, pos) :: inner @ List.map (fun i -> i,pos) imports
|
|
|
|
- | _ -> assert false
|
|
|
|
- with | Not_found ->
|
|
|
|
- inner
|
|
|
|
- in
|
|
|
|
- let inner_alias = ref SS.empty in
|
|
|
|
- List.iter (fun x ->
|
|
|
|
- match fst x with
|
|
|
|
- | EClass c ->
|
|
|
|
- inner_alias := SS.add (fst c.d_name) !inner_alias;
|
|
|
|
- | _ -> ()
|
|
|
|
- ) inner;
|
|
|
|
- let alias_list = ref [] in
|
|
|
|
- List.iter (fun x ->
|
|
|
|
- match x with
|
|
|
|
- | (EClass c, pos) -> begin
|
|
|
|
- let parts = String.nsplit (fst c.d_name) "_24" in
|
|
|
|
- match parts with
|
|
|
|
- | _ :: _ ->
|
|
|
|
- let alias_name = String.concat "_" parts in
|
|
|
|
- if (not (SS.mem alias_name !inner_alias)) && (not (String.exists (snd path) "_24")) then begin
|
|
|
|
- let alias_def = ETypedef {
|
|
|
|
- d_name = alias_name,null_pos;
|
|
|
|
- d_doc = None;
|
|
|
|
- d_params = c.d_params;
|
|
|
|
- d_meta = [];
|
|
|
|
- d_flags = [];
|
|
|
|
- d_data = CTPath {
|
|
|
|
- tpackage = pack;
|
|
|
|
- tname = snd path;
|
|
|
|
- tparams = List.map (fun tp ->
|
|
|
|
- TPType (CTPath {
|
|
|
|
- tpackage = [];
|
|
|
|
- tname = fst tp.tp_name;
|
|
|
|
- tparams = [];
|
|
|
|
- tsub = None;
|
|
|
|
- },null_pos)
|
|
|
|
- ) c.d_params;
|
|
|
|
- tsub = Some(fst c.d_name);
|
|
|
|
- },null_pos;
|
|
|
|
- } in
|
|
|
|
- inner_alias := SS.add alias_name !inner_alias;
|
|
|
|
- alias_list := (alias_def, pos) :: !alias_list;
|
|
|
|
- end
|
|
|
|
- | _ -> ()
|
|
|
|
- end
|
|
|
|
- | _ -> ()
|
|
|
|
- ) inner;
|
|
|
|
- let inner = List.concat [!alias_list ; inner] in
|
|
|
|
- let classes = List.map (fun t -> t,pos) (convert_java_class ctx pos cls) in
|
|
|
|
- let imports, defs = List.partition (function | (EImport(_),_) -> true | _ -> false) (classes @ inner) in
|
|
|
|
- let ret = Some ( real_path, (pack, imports @ defs) ) in
|
|
|
|
- ctx.jtparams <- old_types;
|
|
|
|
- ret
|
|
|
|
- end
|
|
|
|
- end
|
|
|
|
- with
|
|
|
|
- | JReader.Error_message msg ->
|
|
|
|
- prerr_endline ("Class reader failed: " ^ msg);
|
|
|
|
- None
|
|
|
|
- | e ->
|
|
|
|
- if com.verbose then begin
|
|
|
|
- (* prerr_endline (Printexc.get_backtrace ()); requires ocaml 3.11 *)
|
|
|
|
- prerr_endline (Printexc.to_string e)
|
|
|
|
- end;
|
|
|
|
- None
|
|
|
|
- in
|
|
|
|
- let build path p = build (create_ctx com) path p (ref [["java";"lang"], "String"]) in
|
|
|
|
- let cached_files = ref None in
|
|
|
|
- let list_all_files () = match !cached_files with
|
|
|
|
- | None ->
|
|
|
|
- let ret = list_all_files () in
|
|
|
|
- cached_files := Some ret;
|
|
|
|
- ret
|
|
|
|
- | Some r -> r
|
|
|
|
- in
|
|
|
|
-
|
|
|
|
- (* TODO: add_dependency m mdep *)
|
|
|
|
- com.load_extern_type <- com.load_extern_type @ [build];
|
|
|
|
- com.java_libs <- (file, std, close, list_all_files, get_raw_class) :: com.java_libs
|
|
|