java.ml 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279
  1. (*
  2. The Haxe Compiler
  3. Copyright (C) 2005-2019 Haxe Foundation
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  15. *)
  16. open Unix
  17. open ExtString
  18. open NativeLibraries
  19. open Common
  20. open Globals
  21. open Ast
  22. open JData
  23. (** Java lib *)
  24. module SS = Set.Make(String)
  25. type java_lib_ctx = {
  26. jcom : Common.context;
  27. (* current tparams context *)
  28. mutable jtparams : jtypes list;
  29. is_std : bool;
  30. }
  31. exception ConversionError of located
  32. let error s p = raise (ConversionError (located s p))
  33. let is_haxe_keyword = function
  34. | "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true
  35. | _ -> false
  36. let jname_to_hx name =
  37. let name =
  38. if name <> "" && (String.get name 0 < 'A' || String.get name 0 > 'Z') then
  39. Char.escaped (Char.uppercase_ascii (String.get name 0)) ^ String.sub name 1 (String.length name - 1)
  40. else
  41. name
  42. in
  43. let name = String.concat "__" (String.nsplit name "_") in
  44. String.map (function | '$' -> '_' | c -> c) name
  45. let normalize_pack pack =
  46. List.map (function
  47. | "" -> ""
  48. | str when String.get str 0 >= 'A' && String.get str 0 <= 'Z' ->
  49. String.lowercase str
  50. | str -> str
  51. ) pack
  52. let jpath_to_hx (pack,name) = match pack, name with
  53. | ["haxe";"root"], name -> [], name
  54. | "com" :: ("oracle" | "sun") :: _, _
  55. | "javax" :: _, _
  56. | "org" :: ("ietf" | "jcp" | "omg" | "w3c" | "xml") :: _, _
  57. | "sun" :: _, _
  58. | "sunw" :: _, _ -> "java" :: normalize_pack pack, jname_to_hx name
  59. | pack, name -> normalize_pack pack, jname_to_hx name
  60. let real_java_path ctx (pack,name) =
  61. s_type_path (pack, name)
  62. let lookup_jclass com path =
  63. let path = jpath_to_hx path in
  64. List.fold_right (fun java_lib acc ->
  65. match acc with
  66. | None -> java_lib#lookup path
  67. | Some p -> Some p
  68. ) com.native_libs.java_libs None
  69. let mk_type_path ctx path params =
  70. let name, sub = try
  71. let p, _ = String.split (snd path) "$" in
  72. jname_to_hx p, Some (jname_to_hx (snd path))
  73. with | Invalid_string ->
  74. jname_to_hx (snd path), None
  75. in
  76. let pack = fst (jpath_to_hx path) in
  77. let pack, sub, name = match path with
  78. | [], ("Float" as c)
  79. | [], ("Int" as c)
  80. | [], ("Single" as c)
  81. | [], ("Bool" as c)
  82. | [], ("Dynamic" as c)
  83. | [], ("Iterator" as c)
  84. | [], ("ArrayAccess" as c)
  85. | [], ("Iterable" as c) ->
  86. [], Some c, "StdTypes"
  87. | [], ("String" as c) ->
  88. ["std"], None, c
  89. | _ ->
  90. pack, sub, name
  91. in
  92. CTPath {
  93. tpackage = pack;
  94. tname = name;
  95. tparams = params;
  96. tsub = sub;
  97. }
  98. let has_tparam name params = List.exists(fun (n,_,_) -> n = name) params
  99. let rec convert_arg ctx p arg =
  100. match arg with
  101. | TAny | TType (WSuper, _) -> TPType (mk_type_path ctx ([], "Dynamic") [],null_pos)
  102. | TType (_, jsig) -> TPType (convert_signature ctx p jsig,null_pos)
  103. and convert_signature ctx p jsig =
  104. match jsig with
  105. | TByte -> mk_type_path ctx (["java"; "types"], "Int8") []
  106. | TChar -> mk_type_path ctx (["java"; "types"], "Char16") []
  107. | TDouble -> mk_type_path ctx ([], "Float") []
  108. | TFloat -> mk_type_path ctx ([], "Single") []
  109. | TInt -> mk_type_path ctx ([], "Int") []
  110. | TLong -> mk_type_path ctx (["haxe"], "Int64") []
  111. | TShort -> mk_type_path ctx (["java"; "types"], "Int16") []
  112. | TBool -> mk_type_path ctx ([], "Bool") []
  113. | TObject ( (["haxe";"root"], name), args ) -> mk_type_path ctx ([], name) (List.map (convert_arg ctx p) args)
  114. (** nullable types *)
  115. (* replaced from Null<Type> to the actual abstract type to fix #2738 *)
  116. (* | TObject ( (["java";"lang"], "Integer"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Int") []) ] *)
  117. (* | TObject ( (["java";"lang"], "Double"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Float") []) ] *)
  118. (* | TObject ( (["java";"lang"], "Float"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Single") []) ] *)
  119. (* | TObject ( (["java";"lang"], "Boolean"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Bool") []) ] *)
  120. (* | TObject ( (["java";"lang"], "Byte"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int8") []) ] *)
  121. (* | TObject ( (["java";"lang"], "Character"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Char16") []) ] *)
  122. (* | TObject ( (["java";"lang"], "Short"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int16") []) ] *)
  123. (* | TObject ( (["java";"lang"], "Long"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["haxe"], "Int64") []) ] *)
  124. (** other std types *)
  125. | TObject ( (["java";"lang"], "Object"), [] ) -> mk_type_path ctx ([], "Dynamic") []
  126. | TObject ( (["java";"lang"], "String"), [] ) -> mk_type_path ctx ([], "String") []
  127. | TObject ( (["java";"lang"], "Enum"), [_] ) -> mk_type_path ctx ([], "EnumValue") []
  128. (** other types *)
  129. | TObject ( path, [] ) ->
  130. (match lookup_jclass ctx.jcom path with
  131. | Some (jcl, _, _) -> mk_type_path ctx path (List.map (fun _ -> convert_arg ctx p TAny) jcl.ctypes)
  132. | None -> mk_type_path ctx path [])
  133. | TObject ( path, args ) -> mk_type_path ctx path (List.map (convert_arg ctx p) args)
  134. | TObjectInner (pack, (name, params) :: inners) ->
  135. let actual_param = match List.rev inners with
  136. | (_, p) :: _ -> p
  137. | _ -> die "" __LOC__ in
  138. mk_type_path ctx (pack, name ^ "$" ^ String.concat "$" (List.map fst inners)) (List.map (fun param -> convert_arg ctx p param) actual_param)
  139. | TObjectInner (pack, inners) -> die "" __LOC__
  140. | TArray (jsig, _) -> mk_type_path ctx (["java"], "NativeArray") [ TPType (convert_signature ctx p jsig,null_pos) ]
  141. | TMethod _ -> JReader.error "TMethod cannot be converted directly into Complex Type"
  142. | TTypeParameter s -> (match ctx.jtparams with
  143. | cur :: others ->
  144. if has_tparam s cur then
  145. mk_type_path ctx ([], s) []
  146. else begin
  147. if ctx.jcom.verbose && not(List.exists (has_tparam s) others) then print_endline ("Type parameter " ^ s ^ " was not found while building type!");
  148. mk_type_path ctx ([], "Dynamic") []
  149. end
  150. | _ ->
  151. if ctx.jcom.verbose then print_endline ("Empty type parameter stack!");
  152. mk_type_path ctx ([], "Dynamic") [])
  153. let convert_constant ctx p const =
  154. Option.map_default (function
  155. | ConstString s -> Some (EConst (String(s,SDoubleQuotes)), p)
  156. | ConstInt i -> Some (EConst (Int (Printf.sprintf "%ld" i, None)), p)
  157. | ConstFloat f | ConstDouble f -> Some (EConst (Float (Printf.sprintf "%E" f, None)), p)
  158. | _ -> None) None const
  159. let convert_constraints ctx p tl = match tl with
  160. | [] -> None
  161. | [t] -> Some (convert_signature ctx p t,null_pos)
  162. | tl -> Some (CTIntersection(List.map (fun t -> convert_signature ctx p t,null_pos) tl),null_pos)
  163. let convert_param ctx p parent param =
  164. let name, constraints = match param with
  165. | (name, Some extends_sig, implem_sig) ->
  166. name, extends_sig :: implem_sig
  167. | (name, None, implemem_sig) ->
  168. name, implemem_sig
  169. in
  170. {
  171. tp_name = jname_to_hx name,null_pos;
  172. tp_params = [];
  173. tp_constraints = convert_constraints ctx p constraints;
  174. tp_default = None;
  175. tp_meta = [];
  176. }
  177. let get_type_path ctx ct = match ct with | CTPath p -> p | _ -> die "" __LOC__
  178. let is_override field =
  179. List.exists (function | AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), _ ) }] -> true | _ -> false) field.jf_attributes
  180. let mk_override field =
  181. { field with jf_attributes = ((AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), [] ); ann_elements = [] }]) :: field.jf_attributes) }
  182. let del_override field =
  183. { field with jf_attributes = List.filter (fun a -> not (is_override_attrib a)) field.jf_attributes }
  184. let get_canonical ctx p pack name =
  185. (Meta.JavaCanonical, [EConst (String (String.concat "." pack,SDoubleQuotes)), p; EConst (String (name,SDoubleQuotes)), p], p)
  186. let show_in_completion ctx jc =
  187. if not ctx.is_std then true
  188. else match fst jc.cpath with
  189. | ("java" | "javax" | "org") :: _ -> true
  190. | _ -> false
  191. (**
  192. `haxe.Rest<T>` auto-boxes primitive types.
  193. That means we can't use it as varargs for extern methods.
  194. E.g externs with `int` varargs are represented as `int[]` at run time
  195. while `haxe.Rest<Int>` is actually `java.lang.Integer[]`.
  196. *)
  197. let is_eligible_for_haxe_rest_args arg_type =
  198. match arg_type with
  199. | TByte | TChar | TDouble | TFloat | TInt | TLong | TShort | TBool -> false
  200. | _ -> true
  201. let convert_java_enum ctx p pe =
  202. let meta = ref (get_canonical ctx p (fst pe.cpath) (snd pe.cpath) :: [Meta.Native, [EConst (String (real_java_path ctx pe.cpath,SDoubleQuotes) ), p], p ]) in
  203. let data = ref [] in
  204. List.iter (fun f ->
  205. (* if List.mem JEnum f.jf_flags then *)
  206. match f.jf_vmsignature with
  207. | TObject( path, [] ) when path = pe.cpath && List.mem JStatic f.jf_flags && List.mem JFinal f.jf_flags ->
  208. data := { ec_name = f.jf_name,null_pos; ec_doc = None; ec_meta = []; ec_args = []; ec_pos = p; ec_params = []; ec_type = None; } :: !data;
  209. | _ -> ()
  210. ) pe.cfields;
  211. if not (show_in_completion ctx pe) then meta := (Meta.NoCompletion,[],null_pos) :: !meta;
  212. EEnum {
  213. d_name = jname_to_hx (snd pe.cpath),null_pos;
  214. d_doc = None;
  215. d_params = []; (* enums never have type parameters *)
  216. d_meta = !meta;
  217. d_flags = [EExtern];
  218. d_data = List.rev !data;
  219. }
  220. let convert_java_field ctx p jc is_interface field =
  221. let p = { p with pfile = p.pfile ^" (" ^field.jf_name ^")" } in
  222. let cff_doc = None in
  223. let cff_pos = p in
  224. let cff_meta = ref [] in
  225. let cff_access = ref [] in
  226. let cff_name = match field.jf_name with
  227. | "<init>" -> "new"
  228. | "<clinit>"-> raise Exit (* __init__ field *)
  229. | name when String.length name > 5 ->
  230. (match String.sub name 0 5 with
  231. | "__hx_" | "this$" -> raise Exit
  232. | _ -> name)
  233. | name -> name
  234. in
  235. let jf_constant = ref field.jf_constant in
  236. let readonly = ref false in
  237. let is_varargs = ref false in
  238. List.iter (function
  239. | JPublic -> cff_access := (APublic,null_pos) :: !cff_access
  240. | JPrivate -> raise Exit (* private instances aren't useful on externs *)
  241. | JProtected ->
  242. cff_meta := (Meta.Protected, [], p) :: !cff_meta;
  243. cff_access := (APrivate,null_pos) :: !cff_access
  244. | JStatic -> cff_access := (AStatic,null_pos) :: !cff_access
  245. | JFinal ->
  246. cff_access := (AFinal, p) :: !cff_access;
  247. (match field.jf_kind, field.jf_vmsignature, field.jf_constant with
  248. | JKField, TObject _, _ ->
  249. jf_constant := None
  250. | JKField, _, Some _ ->
  251. readonly := true;
  252. jf_constant := None;
  253. | _ -> jf_constant := None)
  254. (* | JSynchronized -> cff_meta := (Meta.Synchronized, [], p) :: !cff_meta *)
  255. | JVolatile -> cff_meta := (Meta.Volatile, [], p) :: !cff_meta
  256. | JTransient -> cff_meta := (Meta.Transient, [], p) :: !cff_meta
  257. | JVarArgs -> is_varargs := true
  258. | JAbstract when not is_interface ->
  259. cff_access := (AAbstract, p) :: !cff_access
  260. | _ -> ()
  261. ) field.jf_flags;
  262. List.iter (function
  263. | AttrDeprecated when jc.cpath <> (["java";"util"],"Date") -> cff_meta := (Meta.Deprecated, [], p) :: !cff_meta
  264. (* TODO: pass anotations as @:meta *)
  265. | AttrVisibleAnnotations ann ->
  266. List.iter (function
  267. | { ann_type = TObject( (["java";"lang"], "Override"), [] ) } ->
  268. cff_access := (AOverride,null_pos) :: !cff_access
  269. | _ -> ()
  270. ) ann
  271. | _ -> ()
  272. ) field.jf_attributes;
  273. List.iter (fun jsig ->
  274. match convert_signature ctx p jsig with
  275. | CTPath path ->
  276. cff_meta := (Meta.Throws, [Ast.EConst (Ast.String (s_type_path (path.tpackage,path.tname),SDoubleQuotes)), p],p) :: !cff_meta
  277. | _ -> ()
  278. ) field.jf_throws;
  279. let extract_local_names () =
  280. let default i =
  281. "param" ^ string_of_int i
  282. in
  283. match field.jf_code with
  284. | None ->
  285. default
  286. | Some attribs -> try
  287. let rec loop attribs = match attribs with
  288. | AttrLocalVariableTable locals :: _ ->
  289. locals
  290. | _ :: attribs ->
  291. loop attribs
  292. | [] ->
  293. raise Not_found
  294. in
  295. let locals = loop attribs in
  296. let h = Hashtbl.create 0 in
  297. List.iter (fun local ->
  298. Hashtbl.replace h local.ld_index local.ld_name
  299. ) locals;
  300. (fun i ->
  301. try Hashtbl.find h (i - 1) (* they are 1-based *)
  302. with Not_found -> "param" ^ string_of_int i
  303. )
  304. with Not_found ->
  305. default
  306. in
  307. let kind = match field.jf_kind with
  308. | JKField when !readonly ->
  309. FProp (("default",null_pos), ("null",null_pos), Some (convert_signature ctx p field.jf_signature,null_pos), None)
  310. | JKField ->
  311. FVar (Some (convert_signature ctx p field.jf_signature,null_pos), None)
  312. | JKMethod ->
  313. match field.jf_signature with
  314. | TMethod (args, ret) ->
  315. let local_names = extract_local_names() in
  316. let old_types = ctx.jtparams in
  317. (match ctx.jtparams with
  318. | c :: others -> ctx.jtparams <- (c @ field.jf_types) :: others
  319. | [] -> ctx.jtparams <- field.jf_types :: []);
  320. let i = ref 0 in
  321. let args_count = List.length args in
  322. let args = List.map (fun s ->
  323. incr i;
  324. let hx_sig =
  325. match s with
  326. | TArray (s1,_) when !is_varargs && !i = args_count && is_eligible_for_haxe_rest_args s1 ->
  327. mk_type_path ctx (["haxe"], "Rest") [TPType (convert_signature ctx p s1,null_pos)]
  328. | _ ->
  329. convert_signature ctx null_pos s
  330. in
  331. (local_names !i,null_pos), false, [], Some(hx_sig,null_pos), None
  332. ) args in
  333. let t = Option.map_default (convert_signature ctx p) (mk_type_path ctx ([], "Void") []) ret in
  334. cff_access := (AOverload,p) :: !cff_access;
  335. let types = List.map (function
  336. | (name, Some ext, impl) ->
  337. {
  338. tp_name = name,null_pos;
  339. tp_params = [];
  340. tp_constraints = convert_constraints ctx p (ext :: impl);
  341. tp_default = None;
  342. tp_meta = [];
  343. }
  344. | (name, None, impl) ->
  345. {
  346. tp_name = name,null_pos;
  347. tp_params = [];
  348. tp_constraints = convert_constraints ctx p impl;
  349. tp_default = None;
  350. tp_meta = [];
  351. }
  352. ) field.jf_types in
  353. ctx.jtparams <- old_types;
  354. FFun ({
  355. f_params = types;
  356. f_args = args;
  357. f_type = Some (t,null_pos);
  358. f_expr = None
  359. })
  360. | _ -> error "Method signature was expected" p
  361. in
  362. if field.jf_code <> None && is_interface then cff_meta := (Meta.JavaDefault,[],cff_pos) :: !cff_meta;
  363. let cff_name, cff_meta =
  364. match String.get cff_name 0 with
  365. | '%' ->
  366. let name = (String.sub cff_name 1 (String.length cff_name - 1)) in
  367. if not (is_haxe_keyword name) then
  368. cff_meta := (Meta.Deprecated, [EConst(String(
  369. "This static field `_" ^ name ^ "` is deprecated and will be removed in later versions. Please use `" ^ name ^ "` instead",SDoubleQuotes)
  370. ),p], p) :: !cff_meta;
  371. "_" ^ name,
  372. (Meta.Native, [EConst (String (name,SDoubleQuotes) ), cff_pos], cff_pos) :: !cff_meta
  373. | _ ->
  374. match String.nsplit cff_name "$" with
  375. | [ no_dollar ] ->
  376. cff_name, !cff_meta
  377. | parts ->
  378. String.concat "_" parts,
  379. (Meta.Native, [EConst (String (cff_name,SDoubleQuotes) ), cff_pos], cff_pos) :: !cff_meta
  380. in
  381. if Common.raw_defined ctx.jcom "java_loader_debug" then
  382. Printf.printf "\t%s%sfield %s : %s\n" (if List.mem_assoc AStatic !cff_access then "static " else "") (if List.mem_assoc AOverride !cff_access then "override " else "") cff_name (s_sig field.jf_signature);
  383. {
  384. cff_name = cff_name,null_pos;
  385. cff_doc = cff_doc;
  386. cff_pos = cff_pos;
  387. cff_meta = cff_meta;
  388. cff_access = !cff_access;
  389. cff_kind = kind
  390. }
  391. let rec japply_params params jsig = match params with
  392. | [] -> jsig
  393. | _ -> match jsig with
  394. | TTypeParameter s -> (try
  395. List.assoc s params
  396. with | Not_found -> jsig)
  397. | TObject(p,tl) ->
  398. TObject(p, args params tl)
  399. | TObjectInner(sl, stll) ->
  400. TObjectInner(sl, List.map (fun (s,tl) -> (s, args params tl)) stll)
  401. | TArray(s,io) ->
  402. TArray(japply_params params s, io)
  403. | TMethod(sl, sopt) ->
  404. TMethod(List.map (japply_params params) sl, Option.map (japply_params params) sopt)
  405. | _ -> jsig
  406. and args params tl = match params with
  407. | [] -> tl
  408. | _ -> List.map (function
  409. | TAny -> TAny
  410. | TType(w,s) -> TType(w,japply_params params s)) tl
  411. let mk_params jtypes = List.map (fun (s,_,_) -> (s,TTypeParameter s)) jtypes
  412. let convert_java_class ctx p jc =
  413. match List.mem JEnum jc.cflags with
  414. | true -> (* is enum *)
  415. [convert_java_enum ctx p jc]
  416. | false ->
  417. let flags = ref [HExtern] in
  418. if Common.raw_defined ctx.jcom "java_loader_debug" then begin
  419. let sup = jc.csuper :: jc.cinterfaces in
  420. print_endline ("converting " ^ (if List.mem JAbstract jc.cflags then "abstract " else "") ^ JData.path_s jc.cpath ^ " : " ^ (String.concat ", " (List.map s_sig sup)));
  421. end;
  422. (* todo: instead of JavaNative, use more specific definitions *)
  423. let meta = ref [Meta.JavaNative, [], p; Meta.Native, [EConst (String (real_java_path ctx jc.cpath,SDoubleQuotes) ), p], p; get_canonical ctx p (fst jc.cpath) (snd jc.cpath)] in
  424. let force_check = Common.defined ctx.jcom Define.ForceLibCheck in
  425. if not force_check then
  426. meta := (Meta.LibType,[],p) :: !meta;
  427. let is_interface = ref false in
  428. let is_abstract = ref false in
  429. List.iter (fun f -> match f with
  430. | JFinal -> flags := HFinal :: !flags
  431. | JInterface ->
  432. is_interface := true;
  433. flags := HInterface :: !flags
  434. | JAbstract ->
  435. meta := (Meta.Abstract, [], p) :: !meta;
  436. is_abstract := true;
  437. | JAnnotation -> meta := (Meta.Annotation, [], p) :: !meta
  438. | _ -> ()
  439. ) jc.cflags;
  440. if !is_abstract && not !is_interface then flags := HAbstract :: !flags;
  441. (match jc.csuper with
  442. | TObject( (["java";"lang"], "Object"), _ ) -> ()
  443. | TObject( (["haxe";"lang"], "HxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta
  444. | _ -> flags := HExtends (get_type_path ctx (convert_signature ctx p jc.csuper),null_pos) :: !flags
  445. );
  446. List.iter (fun i ->
  447. match i with
  448. | TObject ( (["haxe";"lang"], "IHxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta
  449. | _ -> flags :=
  450. if !is_interface then
  451. HExtends (get_type_path ctx (convert_signature ctx p i),null_pos) :: !flags
  452. else
  453. HImplements (get_type_path ctx (convert_signature ctx p i),null_pos) :: !flags
  454. ) jc.cinterfaces;
  455. let fields = ref [] in
  456. let jfields = ref [] in
  457. if jc.cpath <> (["java";"lang"], "CharSequence") then
  458. List.iter (fun f ->
  459. try
  460. if !is_interface && List.mem JStatic f.jf_flags then
  461. ()
  462. else begin
  463. fields := convert_java_field ctx p jc !is_interface f :: !fields;
  464. jfields := f :: !jfields
  465. end
  466. with
  467. | Exit -> ()
  468. ) (jc.cfields @ jc.cmethods);
  469. (* make sure the throws types are imported correctly *)
  470. let imports = List.concat (List.map (fun f ->
  471. List.map (fun jsig ->
  472. match convert_signature ctx p jsig with
  473. | CTPath path ->
  474. let pos = { p with pfile = p.pfile ^ " (" ^ f.jf_name ^" @:throws)" } in
  475. EImport( List.map (fun s -> s,pos) (path.tpackage @ [path.tname]), INormal )
  476. | _ -> die "" __LOC__
  477. ) f.jf_throws
  478. ) jc.cmethods) in
  479. if not (show_in_completion ctx jc) then meta := (Meta.NoCompletion,[],null_pos) :: !meta;
  480. (EClass {
  481. d_name = jname_to_hx (snd jc.cpath),null_pos;
  482. d_doc = None;
  483. d_params = List.map (convert_param ctx p jc.cpath) jc.ctypes;
  484. d_meta = !meta;
  485. d_flags = !flags;
  486. d_data = !fields;
  487. }) :: imports
  488. let create_ctx com is_std =
  489. {
  490. jcom = com;
  491. jtparams = [];
  492. is_std = is_std;
  493. }
  494. let rec has_type_param = function
  495. | TTypeParameter _ -> true
  496. | TMethod (lst, opt) -> List.exists has_type_param lst || Option.map_default has_type_param false opt
  497. | TArray (s,_) -> has_type_param s
  498. | TObjectInner (_, stpl) -> List.exists (fun (_,sigs) -> List.exists has_type_param_arg sigs) stpl
  499. | TObject(_, pl) -> List.exists has_type_param_arg pl
  500. | _ -> false
  501. and has_type_param_arg = function | TType(_,s) -> has_type_param s | _ -> false
  502. let rec japply_params jparams jsig = match jparams with
  503. | [] -> jsig
  504. | _ ->
  505. match jsig with
  506. | TObject(path,p) ->
  507. TObject(path, List.map (japply_params_tp jparams ) p)
  508. | TObjectInner(sl,stargl) ->
  509. TObjectInner(sl,List.map (fun (s,targ) -> (s, List.map (japply_params_tp jparams) targ)) stargl)
  510. | TArray(jsig,io) ->
  511. TArray(japply_params jparams jsig,io)
  512. | TMethod(args,ret) ->
  513. TMethod(List.map (japply_params jparams ) args, Option.map (japply_params jparams ) ret)
  514. | TTypeParameter s -> (try
  515. List.assoc s jparams
  516. with | Not_found -> jsig)
  517. | _ -> jsig
  518. and japply_params_tp jparams jtype_argument = match jtype_argument with
  519. | TAny -> TAny
  520. | TType(w,jsig) -> TType(w,japply_params jparams jsig)
  521. let mk_jparams jtypes params = match jtypes, params with
  522. | [], [] -> []
  523. | _, [] -> List.map (fun (s,_,_) -> s, TObject( (["java";"lang"], "Object"), [] ) ) jtypes
  524. | _ -> List.map2 (fun (s,_,_) jt -> match jt with
  525. | TAny -> s, TObject((["java";"lang"],"Object"),[])
  526. | TType(_,jsig) -> s, jsig) jtypes params
  527. let rec compatible_signature_arg ?arg_test f1 f2 =
  528. let arg_test = match arg_test with
  529. | None -> (fun _ _ -> true)
  530. | Some a -> a
  531. in
  532. if f1 = f2 then
  533. true
  534. else match f1, f2 with
  535. | TObject(p,a), TObject(p2,a2) -> p = p2 && arg_test a a2
  536. | TObjectInner(sl, stal), TObjectInner(sl2, stal2) -> sl = sl2 && List.map fst stal = List.map fst stal2
  537. | TArray(s,_) , TArray(s2,_) -> compatible_signature_arg s s2
  538. | TTypeParameter t1 , TTypeParameter t2 -> t1 = t2
  539. | _ -> false
  540. let rec compatible_param p1 p2 = match p1, p2 with
  541. | TType (_,s1), TType(_,s2) -> compatible_signature_arg ~arg_test:compatible_tparams s1 s2
  542. | TAny, TType(_, TObject( (["java";"lang"],"Object"), _ )) -> true
  543. | TType(_, TObject( (["java";"lang"],"Object"), _ )), TAny -> true
  544. | _ -> false
  545. and compatible_tparams p1 p2 = try match p1, p2 with
  546. | [], [] -> true
  547. | _, [] ->
  548. let p2 = List.map (fun _ -> TAny) p1 in
  549. List.for_all2 compatible_param p1 p2
  550. | [], _ ->
  551. let p1 = List.map (fun _ -> TAny) p2 in
  552. List.for_all2 compatible_param p1 p2
  553. | _, _ ->
  554. List.for_all2 compatible_param p1 p2
  555. with | Invalid_argument _ -> false
  556. let get_adapted_sig f f2 = match f.jf_types with
  557. | [] ->
  558. f.jf_signature
  559. | _ ->
  560. let jparams = mk_jparams f.jf_types (List.map (fun (s,_,_) -> TType(WNone, TTypeParameter s)) f2.jf_types) in
  561. japply_params jparams f.jf_signature
  562. let compatible_methods f1 f2 =
  563. if List.length f1.jf_types <> List.length f2.jf_types then
  564. false
  565. else match (get_adapted_sig f1 f2), f2.jf_signature with
  566. | TMethod(a1,_), TMethod(a2,_) when List.length a1 = List.length a2 ->
  567. List.for_all2 compatible_signature_arg a1 a2
  568. | _ -> false
  569. let jcl_from_jsig com jsig =
  570. let path, params = match jsig with
  571. | TObject(path, params) ->
  572. path,params
  573. | TObjectInner(sl, stll) ->
  574. let last_params = ref [] in
  575. let real_path = sl, String.concat "$" (List.map (fun (s,p) -> last_params := p; s) stll) in
  576. real_path, !last_params
  577. | _ -> raise Not_found
  578. in
  579. match lookup_jclass com path with
  580. | None -> raise Not_found
  581. | Some(c,_,_) -> c,params
  582. let jclass_with_params com cls params = try
  583. match cls.ctypes with
  584. | [] -> cls
  585. | _ ->
  586. let jparams = mk_jparams cls.ctypes params in
  587. { cls with
  588. cfields = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cfields;
  589. cmethods = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cmethods;
  590. csuper = japply_params jparams cls.csuper;
  591. cinterfaces = List.map (japply_params jparams) cls.cinterfaces;
  592. }
  593. with Invalid_argument _ ->
  594. if com.verbose then print_endline ("Differing parameters for class: " ^ s_type_path cls.cpath);
  595. cls
  596. let is_object = function | TObject( (["java";"lang"], "Object"), [] ) -> true | _ -> false
  597. let is_tobject = function | TObject _ | TObjectInner _ -> true | _ -> false
  598. let simplify_args args =
  599. if List.for_all (function | TAny -> true | _ -> false) args then [] else args
  600. let compare_type com s1 s2 =
  601. if s1 = s2 then
  602. 0
  603. else if not (is_tobject s1) then
  604. if is_tobject s2 then (* Dynamic *)
  605. 1
  606. else if compatible_signature_arg s1 s2 then
  607. 0
  608. else
  609. raise Exit
  610. else if not (is_tobject s2) then
  611. -1
  612. else begin
  613. let rec loop ?(first_error=true) s1 s2 : bool =
  614. if is_object s1 then
  615. s1 = s2
  616. else if compatible_signature_arg s1 s2 then begin
  617. let p1, p2 = match s1, s2 with
  618. | TObject(_, p1), TObject(_,p2) ->
  619. p1, p2
  620. | TObjectInner(_, npl1), TObjectInner(_, npl2) ->
  621. snd (List.hd (List.rev npl1)), snd (List.hd (List.rev npl2))
  622. | _ -> die "" __LOC__ (* not tobject *)
  623. in
  624. let p1, p2 = simplify_args p1, simplify_args p2 in
  625. let lp1 = List.length p1 in
  626. let lp2 = List.length p2 in
  627. if lp1 > lp2 then
  628. true
  629. else if lp2 > lp1 then
  630. false
  631. else begin
  632. (* if compatible tparams, it's fine *)
  633. if not (compatible_tparams p1 p2) then
  634. raise Exit; (* meaning: found, but incompatible type parameters *)
  635. true
  636. end
  637. end else try
  638. let c, p = jcl_from_jsig com s1 in
  639. let jparams = mk_jparams c.ctypes p in
  640. let super = japply_params jparams c.csuper in
  641. let implements = List.map (japply_params jparams) c.cinterfaces in
  642. loop ~first_error:first_error super s2 || List.exists (fun super -> loop ~first_error:first_error super s2) implements
  643. with | Not_found ->
  644. print_endline ("--java-lib: The type " ^ (s_sig s1) ^ " is referred but was not found. Compilation may not occur correctly.");
  645. print_endline "Did you forget to include a needed lib?";
  646. if first_error then
  647. not (loop ~first_error:false s2 s1)
  648. else
  649. false
  650. in
  651. if loop s1 s2 then
  652. if loop s2 s1 then
  653. 0
  654. else
  655. 1
  656. else
  657. if loop s2 s1 then
  658. -1
  659. else
  660. -2
  661. end
  662. (* given a list of same overload functions, choose the best (or none) *)
  663. let select_best com flist =
  664. let rec loop cur_best = function
  665. | [] ->
  666. Some cur_best
  667. | f :: flist -> match get_adapted_sig f cur_best, cur_best.jf_signature with
  668. | TMethod(_,Some r), TMethod(_, Some r2) -> (try
  669. match compare_type com r r2 with
  670. | 0 -> (* same type - select any of them *)
  671. loop cur_best flist
  672. | 1 ->
  673. loop f flist
  674. | -1 ->
  675. loop cur_best flist
  676. | -2 -> (* error - no type is compatible *)
  677. if com.verbose then print_endline (f.jf_name ^ ": The types " ^ (s_sig r) ^ " and " ^ (s_sig r2) ^ " are incompatible");
  678. (* bet that the current best has "beaten" other types *)
  679. loop cur_best flist
  680. | _ -> die "" __LOC__
  681. with | Exit -> (* incompatible type parameters *)
  682. (* error mode *)
  683. if com.verbose then print_endline (f.jf_name ^ ": Incompatible argument return signatures: " ^ (s_sig r) ^ " and " ^ (s_sig r2));
  684. None)
  685. | TMethod _, _ -> (* select the method *)
  686. loop f flist
  687. | _ ->
  688. loop cur_best flist
  689. in
  690. match loop (List.hd flist) (List.tl flist) with
  691. | Some f ->
  692. Some f
  693. | None -> match List.filter (fun f -> not (is_override f)) flist with
  694. (* error mode; take off all override methods *)
  695. | [] -> None
  696. | f :: [] -> Some f
  697. | f :: flist -> Some f (* pick one *)
  698. (**** begin normalize_jclass helpers ****)
  699. let fix_overrides_jclass com cls =
  700. let force_check = Common.defined com Define.ForceLibCheck in
  701. let methods = if force_check then List.map (fun f -> del_override f) cls.cmethods else cls.cmethods in
  702. let cmethods = methods in
  703. let super_fields = [] in
  704. let super_methods = [] in
  705. let nonstatics = List.filter (fun f -> not (List.mem JStatic f.jf_flags)) (cls.cfields @ cls.cmethods) in
  706. let is_pub = fun f -> List.exists (function | JPublic | JProtected -> true | _ -> false) f.jf_flags in
  707. let cmethods, super_fields = if not (List.mem JInterface cls.cflags) then
  708. List.filter is_pub cmethods,
  709. List.filter is_pub super_fields
  710. else
  711. cmethods,super_fields
  712. in
  713. let rec loop cls super_methods super_fields cmethods nonstatics = try
  714. match cls.csuper with
  715. | TObject((["java";"lang"],"Object"),_) ->
  716. super_methods,super_fields,cmethods,nonstatics
  717. | _ ->
  718. let cls, params = jcl_from_jsig com cls.csuper in
  719. let cls = jclass_with_params com cls params in
  720. let nonstatics = (List.filter (fun f -> (List.mem JStatic f.jf_flags)) (cls.cfields @ cls.cmethods)) @ nonstatics in
  721. let super_methods = cls.cmethods @ super_methods in
  722. let super_fields = cls.cfields @ super_fields in
  723. let cmethods = if force_check then begin
  724. let overridden = ref [] in
  725. let cmethods = List.map (fun jm ->
  726. (* TODO rewrite/standardize empty spaces *)
  727. if not (is_override jm) && not (List.mem JStatic jm.jf_flags) && List.exists (fun msup ->
  728. let ret = msup.jf_name = jm.jf_name && not(List.mem JStatic msup.jf_flags) && compatible_methods msup jm in
  729. if ret then begin
  730. let f = mk_override msup in
  731. overridden := { f with jf_flags = jm.jf_flags } :: !overridden
  732. end;
  733. ret
  734. ) cls.cmethods then
  735. mk_override jm
  736. else
  737. jm
  738. ) cmethods in
  739. !overridden @ cmethods
  740. end else
  741. cmethods
  742. in
  743. loop cls super_methods super_fields cmethods nonstatics
  744. with | Not_found ->
  745. super_methods,super_fields,cmethods,nonstatics
  746. in
  747. loop cls super_methods super_fields cmethods nonstatics
  748. let normalize_jclass com cls =
  749. (* after adding the noCheck metadata, this option will annotate what changes were needed *)
  750. (* and that are now deprecated *)
  751. let force_check = Common.defined com Define.ForceLibCheck in
  752. (* fix overrides *)
  753. let super_methods, super_fields, cmethods, nonstatics = fix_overrides_jclass com cls in
  754. let all_methods = cmethods @ super_methods in
  755. (* look for interfaces and add missing implementations (may happen on abstracts or by vmsig differences *)
  756. (* (libType): even with libType enabled, we need to add these missing fields - otherwise we won't be able to use them from Haxe *)
  757. let added_interface_fields = ref [] in
  758. let rec loop_interface abstract cls iface = try
  759. match iface with
  760. | TObject ((["java";"lang"],"Object"), _) -> ()
  761. | TObject (path,_) when path = cls.cpath -> ()
  762. | _ ->
  763. let cif, params = jcl_from_jsig com iface in
  764. let cif = jclass_with_params com cif params in
  765. List.iter (fun jf ->
  766. 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
  767. let jf = if abstract && force_check then del_override jf else jf in
  768. let jf = if not (List.mem JPublic jf.jf_flags) then { jf with jf_flags = JPublic :: jf.jf_flags } else jf in (* interfaces implementations are always public *)
  769. added_interface_fields := jf :: !added_interface_fields;
  770. end
  771. ) cif.cmethods;
  772. (* we don't need to loop again in the interface unless we are in an abstract class, since these interfaces are already normalized *)
  773. if abstract then List.iter (loop_interface abstract cif) cif.cinterfaces;
  774. with Not_found -> ()
  775. in
  776. List.iter (loop_interface (List.mem JAbstract cls.cflags) cls) cls.cinterfaces;
  777. let nonstatics = !added_interface_fields @ nonstatics in
  778. let cmethods = !added_interface_fields @ cmethods in
  779. (* for each added field in the interface, lookup in super_methods possible methods to include *)
  780. (* so we can choose the better method still *)
  781. let cmethods = if not force_check then
  782. cmethods
  783. else
  784. List.fold_left (fun cmethods im ->
  785. (* see if any of the added_interface_fields need to be declared as override *)
  786. let f = List.find_all (fun jf -> jf.jf_name = im.jf_name && compatible_methods jf im) super_methods in
  787. let f = List.map mk_override f in
  788. f @ cmethods
  789. ) cmethods !added_interface_fields;
  790. in
  791. (* take off equals, hashCode and toString from interface *)
  792. let cmethods = if List.mem JInterface cls.cflags then List.filter (fun jf -> match jf.jf_name, jf.jf_vmsignature with
  793. | "equals", TMethod([TObject( (["java";"lang"],"Object"), _)],_)
  794. | "hashCode", TMethod([], _)
  795. | "toString", TMethod([], _) -> false
  796. | _ -> true
  797. ) cmethods
  798. else
  799. cmethods
  800. in
  801. (* change field name to not collide with haxe keywords and with static/non-static members *)
  802. let fold_field acc f =
  803. let change, both = match f.jf_name with
  804. | _ when List.mem JStatic f.jf_flags && List.exists (fun f2 -> f.jf_name = f2.jf_name) nonstatics -> true, true
  805. | _ -> is_haxe_keyword f.jf_name, false
  806. in
  807. let f2 = if change then
  808. { f with jf_name = "%" ^ f.jf_name }
  809. else
  810. f
  811. in
  812. if both then f :: f2 :: acc else f2 :: acc
  813. in
  814. (* change static fields that have the same name as methods *)
  815. let cfields = List.fold_left fold_field [] cls.cfields in
  816. let cmethods = List.fold_left fold_field [] cmethods in
  817. (* take off variable fields that have the same name as methods *)
  818. (* and take off variables that already have been declared *)
  819. 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
  820. let cfields = List.filter (fun f ->
  821. if List.mem JStatic f.jf_flags then
  822. not (List.exists (filter_field f) cmethods)
  823. else
  824. 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
  825. in
  826. (* now filter any method that clashes with a field - on a superclass *)
  827. let cmethods = if force_check then List.filter (fun f ->
  828. if List.mem JStatic f.jf_flags then
  829. true
  830. else
  831. not (List.exists (filter_field f) super_fields) ) cmethods
  832. else
  833. cmethods
  834. in
  835. (* removing duplicate fields. They are there because of return type covariance in Java *)
  836. (* Also, if a method overrides a previous definition, and changes a type parameters' variance, *)
  837. (* we will take it off *)
  838. (* this means that some rare codes will never compile on Haxe, but unless Haxe adds variance support *)
  839. (* I can't see how this can be any different *)
  840. let rec loop acc = function
  841. | [] -> acc
  842. | f :: cmeths ->
  843. match List.partition (fun f2 -> f.jf_name = f2.jf_name && compatible_methods f f2) cmeths with
  844. | [], cmeths ->
  845. loop (f :: acc) cmeths
  846. | flist, cmeths -> match select_best com (f :: flist) with
  847. | None ->
  848. loop acc cmeths
  849. | Some f ->
  850. loop (f :: acc) cmeths
  851. in
  852. (* last pass: take off all cfields that are internal / private (they won't be accessible anyway) *)
  853. let cfields = List.filter(fun f -> List.exists (fun f -> f = JPublic || f = JProtected) f.jf_flags) cfields in
  854. let cmethods = loop [] cmethods in
  855. { cls with cfields = cfields; cmethods = cmethods }
  856. (**** end normalize_jclass helpers ****)
  857. let get_classes_zip zip =
  858. let ret = ref [] in
  859. List.iter (function
  860. | { Zip.is_directory = false; Zip.filename = f } when (String.sub (String.uncapitalize f) (String.length f - 6) 6) = ".class" && not (String.exists f ~sub:"$") ->
  861. (match List.rev (String.nsplit f "/") with
  862. | clsname :: pack ->
  863. if not (String.contains clsname '$') then begin
  864. let path = jpath_to_hx (List.rev pack, String.sub clsname 0 (String.length clsname - 6)) in
  865. ret := path :: !ret
  866. end
  867. | _ ->
  868. ret := ([], jname_to_hx f) :: !ret)
  869. | _ -> ()
  870. ) (Zip.entries zip);
  871. !ret
  872. class virtual java_library com name file_path = object(self)
  873. inherit [java_lib_type,unit] native_library name file_path as super
  874. val hxpack_to_jpack = Hashtbl.create 16
  875. method convert_path (path : path) : path =
  876. Hashtbl.find hxpack_to_jpack path
  877. method private replace_canonical_name p pack name_original name_replace decl =
  878. let mk_meta name = (Meta.JavaCanonical, [EConst (String (String.concat "." pack,SDoubleQuotes)), p; EConst(String (name,SDoubleQuotes)), p], p) in
  879. let add_meta name metas =
  880. if Meta.has Meta.JavaCanonical metas then
  881. List.map (function
  882. | (Meta.JavaCanonical,[EConst (String(cpack,_)), _; EConst(String(cname,_)), _],_) ->
  883. let did_replace,name = String.replace ~str:cname ~sub:name_original ~by:name_replace in
  884. if not did_replace then print_endline (cname ^ " -> " ^ name_original ^ " -> " ^ name_replace);
  885. mk_meta name
  886. | m -> m
  887. ) metas
  888. else
  889. mk_meta name :: metas
  890. in
  891. match decl with
  892. | EClass c ->
  893. EClass { c with d_meta = add_meta (fst c.d_name) c.d_meta }
  894. | EEnum e ->
  895. EEnum { e with d_meta = add_meta (fst e.d_name) e.d_meta }
  896. | EAbstract a ->
  897. EAbstract { a with d_meta = add_meta (fst a.d_name) a.d_meta }
  898. | d -> d
  899. method build path (p : pos) : Ast.package option =
  900. let rec build ctx path p types =
  901. try
  902. if List.mem path !types then
  903. None
  904. else begin
  905. let first = match !types with
  906. | [ ["java";"lang"], "String" ] | [] -> true
  907. | p :: _ ->
  908. false
  909. in
  910. types := path :: !types;
  911. match self#lookup path, path with
  912. | None, ([], c) -> build ctx (["haxe";"root"], c) p types
  913. | None, _ -> None
  914. | Some (cls, real_path, pos_path), _ ->
  915. let is_disallowed_inner = first && String.exists (snd cls.cpath) ~sub:"$" in
  916. let is_disallowed_inner = if is_disallowed_inner then begin
  917. let outer, inner = String.split (snd cls.cpath) "$" in
  918. match self#lookup (fst path, outer) with
  919. | None -> false
  920. | _ -> true
  921. end else
  922. false
  923. in
  924. if is_disallowed_inner then
  925. None
  926. else begin
  927. if ctx.jcom.verbose then print_endline ("Parsed Java class " ^ (s_type_path cls.cpath));
  928. let old_types = ctx.jtparams in
  929. ctx.jtparams <- cls.ctypes :: ctx.jtparams;
  930. let pos = { pfile = pos_path; pmin = 0; pmax = 0; } in
  931. let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
  932. let ppath = self#convert_path path in
  933. let inner = List.fold_left (fun acc (path,out,_,_) ->
  934. let path = jpath_to_hx path in
  935. (if out <> Some ppath then
  936. acc
  937. else match build ctx path p types with
  938. | Some(_, classes) ->
  939. let base = snd ppath ^ "$" in
  940. (List.map (fun (def,p) ->
  941. self#replace_canonical_name p (fst ppath) base (snd ppath ^ ".") def, p) classes) @ acc
  942. | _ -> acc);
  943. ) [] cls.cinner_types in
  944. (* add _Statics class *)
  945. let inner = try
  946. if not (List.mem JInterface cls.cflags) then raise Not_found;
  947. let smethods = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cmethods in
  948. let sfields = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cfields in
  949. if not (smethods <> [] || sfields <> []) then raise Not_found;
  950. let obj = TObject( (["java";"lang"],"Object"), []) in
  951. let ncls = convert_java_class ctx pos { cls with cmethods = smethods; cfields = sfields; cflags = []; csuper = obj; cinterfaces = []; cinner_types = []; ctypes = [] } in
  952. match ncls with
  953. | EClass c :: imports ->
  954. (EClass { c with d_name = (fst c.d_name ^ "_Statics"),snd c.d_name }, pos) :: inner @ List.map (fun i -> i,pos) imports
  955. | _ -> die "" __LOC__
  956. with | Not_found ->
  957. inner
  958. in
  959. let inner_alias = ref SS.empty in
  960. List.iter (fun x ->
  961. match fst x with
  962. | EClass c ->
  963. inner_alias := SS.add (fst c.d_name) !inner_alias;
  964. | _ -> ()
  965. ) inner;
  966. let alias_list = ref [] in
  967. List.iter (fun x ->
  968. match x with
  969. | (EClass c, pos) -> begin
  970. let parts = String.nsplit (fst c.d_name) "_24" in
  971. match parts with
  972. | _ :: _ ->
  973. let alias_name = String.concat "_" parts in
  974. if (not (SS.mem alias_name !inner_alias)) && (not (String.exists (snd path) ~sub:"_24")) then begin
  975. let alias_def = ETypedef {
  976. d_name = alias_name,null_pos;
  977. d_doc = None;
  978. d_params = c.d_params;
  979. d_meta = [];
  980. d_flags = [];
  981. d_data = CTPath {
  982. tpackage = pack;
  983. tname = snd path;
  984. tparams = List.map (fun tp ->
  985. TPType (CTPath {
  986. tpackage = [];
  987. tname = fst tp.tp_name;
  988. tparams = [];
  989. tsub = None;
  990. },null_pos)
  991. ) c.d_params;
  992. tsub = Some(fst c.d_name);
  993. },null_pos;
  994. } in
  995. inner_alias := SS.add alias_name !inner_alias;
  996. alias_list := (alias_def, pos) :: !alias_list;
  997. end
  998. | _ -> ()
  999. end
  1000. | _ -> ()
  1001. ) inner;
  1002. let inner = List.concat [!alias_list ; inner] in
  1003. let classes = List.map (fun t -> t,pos) (convert_java_class ctx pos cls) in
  1004. let imports, defs = List.partition (function | (EImport(_),_) -> true | _ -> false) (classes @ inner) in
  1005. let ret = Some (pack, imports @ defs) in
  1006. ctx.jtparams <- old_types;
  1007. ret
  1008. end
  1009. end
  1010. with
  1011. | JReader.Error_message msg ->
  1012. print_endline ("Class reader failed: " ^ msg);
  1013. None
  1014. | e ->
  1015. if ctx.jcom.verbose then begin
  1016. (* print_endline (Printexc.get_backtrace ()); requires ocaml 3.11 *)
  1017. print_endline (Printexc.to_string e)
  1018. end;
  1019. None
  1020. in
  1021. build (create_ctx com (self#has_flag FlagIsStd)) path p (ref [["java";"lang"], "String"])
  1022. method get_data = ()
  1023. end
  1024. class java_library_jar com name file_path = object(self)
  1025. inherit java_library com name file_path
  1026. val zip = lazy (Zip.open_in file_path)
  1027. val mutable cached_files = None
  1028. val cached_types = Hashtbl.create 12
  1029. val mutable loaded = false
  1030. val mutable closed = false
  1031. method load =
  1032. if not loaded then begin
  1033. loaded <- true;
  1034. List.iter (function
  1035. | { Zip.is_directory = false; Zip.filename = filename } when String.ends_with filename ~suffix:".class" ->
  1036. let pack = String.nsplit filename "/" in
  1037. (match List.rev pack with
  1038. | [] -> ()
  1039. | name :: pack ->
  1040. let name = String.sub name 0 (String.length name - 6) in
  1041. let pack = List.rev pack in
  1042. Hashtbl.add hxpack_to_jpack (jpath_to_hx (pack,name)) (pack,name))
  1043. | _ -> ()
  1044. ) (Zip.entries (Lazy.force zip))
  1045. end
  1046. method private lookup' ((pack,name) : path) : java_lib_type =
  1047. try
  1048. let zip = Lazy.force zip in
  1049. let location = (String.concat "/" (pack @ [name]) ^ ".class") in
  1050. let entry = Zip.find_entry zip location in
  1051. let data = Zip.read_entry zip entry in
  1052. Some(JReader.parse_class (IO.input_string data), file_path, file_path ^ "@" ^ location)
  1053. with
  1054. | Not_found ->
  1055. None
  1056. method lookup (path : path) : java_lib_type =
  1057. try
  1058. Hashtbl.find cached_types path
  1059. with | Not_found -> try
  1060. self#load;
  1061. let pack, name = self#convert_path path in
  1062. let try_file (pack,name) =
  1063. match self#lookup' (pack,name) with
  1064. | None ->
  1065. Hashtbl.add cached_types path None;
  1066. None
  1067. | Some (i, p1, p2) ->
  1068. Hashtbl.add cached_types path (Some(i,p1,p2)); (* type loop normalization *)
  1069. let ret = Some (normalize_jclass com i, p1, p2) in
  1070. Hashtbl.replace cached_types path ret;
  1071. ret
  1072. in
  1073. try_file (pack,name)
  1074. with Not_found ->
  1075. None
  1076. method close =
  1077. if not closed then begin
  1078. closed <- true;
  1079. Zip.close_in (Lazy.force zip)
  1080. end
  1081. method private list_modules' : path list =
  1082. let ret = ref [] in
  1083. List.iter (function
  1084. | { Zip.is_directory = false; Zip.filename = f } when (String.sub (String.uncapitalize f) (String.length f - 6) 6) = ".class" && not (String.exists f ~sub:"$") ->
  1085. (match List.rev (String.nsplit f "/") with
  1086. | clsname :: pack ->
  1087. if not (String.contains clsname '$') then begin
  1088. let path = jpath_to_hx (List.rev pack, String.sub clsname 0 (String.length clsname - 6)) in
  1089. ret := path :: !ret
  1090. end
  1091. | _ ->
  1092. ret := ([], jname_to_hx f) :: !ret)
  1093. | _ -> ()
  1094. ) (Zip.entries (Lazy.force zip));
  1095. !ret
  1096. method list_modules : path list = match cached_files with
  1097. | None ->
  1098. let ret = self#list_modules' in
  1099. cached_files <- Some ret;
  1100. ret
  1101. | Some r ->
  1102. r
  1103. end
  1104. class java_library_dir com name file_path = object(self)
  1105. inherit java_library com name file_path
  1106. val mutable files = []
  1107. method load =
  1108. let all = ref [] in
  1109. let rec iter_files pack dir path = try
  1110. let file = Unix.readdir dir in
  1111. let filepath = path ^ "/" ^ file in
  1112. (if String.ends_with file ~suffix:".class" then
  1113. let name = String.sub file 0 (String.length file - 6) in
  1114. let path = jpath_to_hx (pack,name) in
  1115. if not (String.exists file ~sub:"$") then all := path :: !all;
  1116. Hashtbl.add hxpack_to_jpack path (pack,name)
  1117. else if (Unix.stat filepath).st_kind = S_DIR && file <> "." && file <> ".." then
  1118. let pack = pack @ [file] in
  1119. iter_files (pack) (Unix.opendir filepath) filepath);
  1120. iter_files pack dir path
  1121. with | End_of_file | Unix.Unix_error _ ->
  1122. Unix.closedir dir
  1123. in
  1124. iter_files [] (Unix.opendir file_path) file_path;
  1125. files <- !all
  1126. method close =
  1127. ()
  1128. method list_modules =
  1129. files
  1130. method lookup (pack,name) : java_lib_type =
  1131. let real_path = file_path ^ "/" ^ (String.concat "/" pack) ^ "/" ^ (name ^ ".class") in
  1132. try
  1133. let data = Std.input_file ~bin:true real_path in
  1134. Some(JReader.parse_class (IO.input_string data), real_path, real_path)
  1135. with
  1136. | _ -> None
  1137. end
  1138. let add_java_lib com name std extern modern =
  1139. let file = if Sys.file_exists name then
  1140. name
  1141. else try Common.find_file com name with
  1142. | Not_found -> try Common.find_file com (name ^ ".jar") with
  1143. | Not_found ->
  1144. failwith ("Java lib " ^ name ^ " not found")
  1145. in
  1146. let java_lib =
  1147. if modern then
  1148. (new JavaModern.java_library_modern com name file :> (java_lib_type,unit) native_library)
  1149. else match (Unix.stat file).st_kind with
  1150. | S_DIR ->
  1151. (new java_library_dir com name file :> (java_lib_type,unit) native_library)
  1152. | _ ->
  1153. (new java_library_jar com name file :> (java_lib_type,unit) native_library)
  1154. in
  1155. if std then java_lib#add_flag FlagIsStd;
  1156. if extern then java_lib#add_flag FlagIsExtern;
  1157. com.native_libs.java_libs <- (java_lib :> (java_lib_type,unit) native_library) :: com.native_libs.java_libs;
  1158. CommonCache.handle_native_lib com java_lib
  1159. let before_generate con =
  1160. let java_ver = try
  1161. int_of_string (Common.defined_value con Define.JavaVer)
  1162. with | Not_found ->
  1163. Common.define_value con Define.JavaVer "7";
  1164. 7
  1165. in
  1166. 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");
  1167. let rec loop i =
  1168. Common.raw_define con ("java" ^ (string_of_int i));
  1169. if i > 0 then loop (i - 1)
  1170. in
  1171. loop java_ver