javaModern.ml 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. open Globals
  2. open Ast
  3. open ExtString
  4. open NativeLibraries
  5. module AccessFlags = struct
  6. type t =
  7. | MPublic
  8. | MPrivate
  9. | MProtected
  10. | MStatic
  11. | MFinal
  12. | MSynchronized
  13. | MBridge
  14. | MVarargs
  15. | MNative
  16. | MInterface
  17. | MAbstract
  18. | MStrict
  19. | MSynthetic
  20. | MAnnotation
  21. | MEnum
  22. let to_int = function
  23. | MPublic -> 0x1
  24. | MPrivate -> 0x2
  25. | MProtected -> 0x4
  26. | MStatic -> 0x8
  27. | MFinal -> 0x10
  28. | MSynchronized -> 0x20
  29. | MBridge -> 0x40
  30. | MVarargs -> 0x80
  31. | MNative -> 0x100
  32. | MInterface -> 0x200
  33. | MAbstract -> 0x400
  34. | MStrict -> 0x800
  35. | MSynthetic -> 0x1000
  36. | MAnnotation -> 0x2000
  37. | MEnum -> 0x4000
  38. let has_flag b flag =
  39. b land (to_int flag) <> 0
  40. end
  41. module JDataHoldovers = struct
  42. type jwildcard =
  43. | WExtends (* + *)
  44. | WSuper (* - *)
  45. | WNone
  46. type jtype_argument =
  47. | TType of jwildcard * jsignature
  48. | TAny (* * *)
  49. and jsignature =
  50. | TByte (* B *)
  51. | TChar (* C *)
  52. | TDouble (* D *)
  53. | TFloat (* F *)
  54. | TInt (* I *)
  55. | TLong (* J *)
  56. | TShort (* S *)
  57. | TBool (* Z *)
  58. | TObject of path * jtype_argument list (* L Classname *)
  59. | TObjectInner of (string list) * (string * jtype_argument list) list (* L Classname ClassTypeSignatureSuffix *)
  60. | TArray of jsignature * int option (* [ *)
  61. | TMethod of jmethod_signature (* ( *)
  62. | TTypeParameter of string (* T *)
  63. (* ( jsignature list ) ReturnDescriptor (| V | jsignature) *)
  64. and jmethod_signature = jsignature list * jsignature option
  65. type jtypes = (string * jsignature option * jsignature list) list
  66. type jannotation = {
  67. ann_type : jsignature;
  68. ann_elements : (string * jannotation_value) list;
  69. }
  70. and jannotation_value =
  71. | ValConst of jsignature * int
  72. | ValEnum of jsignature * string (* e *)
  73. | ValClass of jsignature (* c *) (* V -> Void *)
  74. | ValAnnotation of jannotation (* @ *)
  75. | ValArray of jannotation_value list (* [ *)
  76. end
  77. open JDataHoldovers
  78. module JReaderHoldovers = struct
  79. open JDataHoldovers
  80. let rec parse_type_parameter_part s = match s.[0] with
  81. | '*' -> TAny, 1
  82. | c ->
  83. let wildcard, i = match c with
  84. | '+' -> WExtends, 1
  85. | '-' -> WSuper, 1
  86. | _ -> WNone, 0
  87. in
  88. let jsig, l = parse_signature_part (String.sub s i (String.length s - 1)) in
  89. (TType (wildcard, jsig), l + i)
  90. and parse_signature_part s =
  91. let len = String.length s in
  92. if len = 0 then raise Exit;
  93. match s.[0] with
  94. | 'B' -> TByte, 1
  95. | 'C' -> TChar, 1
  96. | 'D' -> TDouble, 1
  97. | 'F' -> TFloat, 1
  98. | 'I' -> TInt, 1
  99. | 'J' -> TLong, 1
  100. | 'S' -> TShort, 1
  101. | 'Z' -> TBool, 1
  102. | 'L' ->
  103. (try
  104. let orig_s = s in
  105. let rec loop start i acc =
  106. match s.[i] with
  107. | '/' -> loop (i + 1) (i + 1) (String.sub s start (i - start) :: acc)
  108. | ';' | '.' -> List.rev acc, (String.sub s start (i - start)), [], (i)
  109. | '<' ->
  110. let name = String.sub s start (i - start) in
  111. let rec loop_params i acc =
  112. let s = String.sub s i (len - i) in
  113. match s.[0] with
  114. | '>' -> List.rev acc, i + 1
  115. | _ ->
  116. let tp, l = parse_type_parameter_part s in
  117. loop_params (l + i) (tp :: acc)
  118. in
  119. let params, _end = loop_params (i + 1) [] in
  120. List.rev acc, name, params, (_end)
  121. | _ -> loop start (i+1) acc
  122. in
  123. let pack, name, params, _end = loop 1 1 [] in
  124. let rec loop_inner i acc =
  125. match s.[i] with
  126. | '.' ->
  127. let pack, name, params, _end = loop (i+1) (i+1) [] in
  128. if pack <> [] then failwith ("Inner types must not define packages. For '" ^ orig_s ^ "'.");
  129. loop_inner _end ( (name,params) :: acc )
  130. | ';' -> List.rev acc, i + 1
  131. | c -> failwith ("End of complex type signature expected after type parameter. Got '" ^ Char.escaped c ^ "' for '" ^ orig_s ^ "'." );
  132. in
  133. let inners, _end = loop_inner _end [] in
  134. match inners with
  135. | [] -> TObject((pack,name), params), _end
  136. | _ -> TObjectInner( pack, (name,params) :: inners ), _end
  137. with
  138. Invalid_string -> raise Exit)
  139. | '[' ->
  140. let p = ref 1 in
  141. while !p < String.length s && s.[!p] >= '0' && s.[!p] <= '9' do
  142. incr p;
  143. done;
  144. let size = (if !p > 1 then Some (int_of_string (String.sub s 1 (!p - 1))) else None) in
  145. let s , l = parse_signature_part (String.sub s !p (String.length s - !p)) in
  146. TArray (s,size) , l + !p
  147. | '(' ->
  148. let p = ref 1 in
  149. let args = ref [] in
  150. while !p < String.length s && s.[!p] <> ')' do
  151. let a , l = parse_signature_part (String.sub s !p (String.length s - !p)) in
  152. args := a :: !args;
  153. p := !p + l;
  154. done;
  155. incr p;
  156. if !p >= String.length s then raise Exit;
  157. let ret , l = (match s.[!p] with 'V' -> None , 1 | _ ->
  158. let s, l = parse_signature_part (String.sub s !p (String.length s - !p)) in
  159. Some s, l
  160. ) in
  161. TMethod (List.rev !args,ret) , !p + l
  162. | 'T' ->
  163. (try
  164. let s1 , _ = String.split s ";" in
  165. let len = String.length s1 in
  166. TTypeParameter (String.sub s1 1 (len - 1)) , len + 1
  167. with
  168. Invalid_string -> raise Exit)
  169. | _ ->
  170. raise Exit
  171. let parse_signature s =
  172. try
  173. let sign , l = parse_signature_part s in
  174. if String.length s <> l then raise Exit;
  175. sign
  176. with
  177. Exit -> failwith ("Invalid signature '" ^ s ^ "'")
  178. let parse_method_signature s =
  179. match parse_signature s with
  180. | (TMethod m) -> m
  181. | _ -> failwith ("Unexpected signature '" ^ s ^ "'. Expecting method")
  182. let parse_formal_type_params s = match s.[0] with
  183. | '<' ->
  184. let rec read_id i = match s.[i] with
  185. | ':' | '>' -> i
  186. | _ -> read_id (i + 1)
  187. in
  188. let len = String.length s in
  189. let rec parse_params idx acc =
  190. let idi = read_id (idx + 1) in
  191. let id = String.sub s (idx + 1) (idi - idx - 1) in
  192. (* next must be a : *)
  193. (match s.[idi] with | ':' -> () | _ -> failwith ("Invalid formal type signature character: " ^ Char.escaped s.[idi] ^ " ; from " ^ s));
  194. let ext, l = match s.[idi + 1] with
  195. | ':' | '>' ->
  196. None, idi + 1
  197. | _ ->
  198. let sgn, l = parse_signature_part (String.sub s (idi + 1) (len - idi - 1)) in
  199. Some sgn, l + idi + 1
  200. in
  201. let rec loop idx acc =
  202. match s.[idx] with
  203. | ':' ->
  204. let ifacesig, ifacei = parse_signature_part (String.sub s (idx + 1) (len - idx - 1)) in
  205. loop (idx + ifacei + 1) (ifacesig :: acc)
  206. | _ ->
  207. acc, idx
  208. in
  209. let ifaces, idx = loop l [] in
  210. let acc = (id, ext, ifaces) :: acc in
  211. if s.[idx] = '>' then List.rev acc, idx + 1 else parse_params (idx - 1) acc
  212. in
  213. parse_params 0 []
  214. | _ -> [], 0
  215. let parse_throws s =
  216. let len = String.length s in
  217. let rec loop idx acc =
  218. if idx > len then raise Exit
  219. else if idx = len then acc, idx
  220. else match s.[idx] with
  221. | '^' ->
  222. let tsig, l = parse_signature_part (String.sub s (idx+1) (len - idx - 1)) in
  223. loop (idx + l + 1) (tsig :: acc)
  224. | _ -> acc, idx
  225. in
  226. loop 0 []
  227. let parse_complete_method_signature s =
  228. try
  229. let len = String.length s in
  230. let tparams, i = parse_formal_type_params s in
  231. let sign, l = parse_signature_part (String.sub s i (len - i)) in
  232. let throws, l2 = parse_throws (String.sub s (i+l) (len - i - l)) in
  233. if (i + l + l2) <> len then raise Exit;
  234. match sign with
  235. | TMethod msig -> tparams, msig, throws
  236. | _ -> raise Exit
  237. with
  238. Exit -> failwith ("Invalid method extended signature '" ^ s ^ "'")
  239. end
  240. module JReaderModern = struct
  241. open IO
  242. open IO.BigEndian
  243. open JReaderHoldovers
  244. type constant_pool = {
  245. strings : string array;
  246. paths : path array;
  247. name_and_types : (string * string) array;
  248. }
  249. type jlocal = {
  250. ld_start_pc : int;
  251. ld_length : int;
  252. ld_name : string;
  253. ld_descriptor : string;
  254. ld_index : int;
  255. }
  256. type jattribute =
  257. | AttrCode of jattribute list
  258. | AttrDeprecated
  259. | AttrLocalVariableTable of jlocal list
  260. | AttrMethodParameters of (string * int) list
  261. | AttrSignature of string
  262. | AttrVisibleAnnotations of jannotation list
  263. | AttrOther
  264. type jfield = {
  265. jf_name : string;
  266. jf_flags : int;
  267. jf_types : jtypes;
  268. jf_descriptor : jsignature;
  269. jf_attributes : jattribute list;
  270. jf_code : jattribute list option;
  271. }
  272. type jclass = {
  273. jc_path : path;
  274. jc_flags : int;
  275. jc_super : jsignature;
  276. jc_interfaces : jsignature list;
  277. jc_types : jtypes;
  278. jc_fields : jfield list;
  279. jc_methods : jfield list;
  280. jc_attributes : jattribute list;
  281. }
  282. let read_constant_pool ch =
  283. let count = read_ui16 ch in
  284. let strings = Array.make count "" in
  285. let paths = Array.make count 0 in
  286. let name_and_types = Array.make count (0,0) in
  287. let i = ref 1 in
  288. while !i < count do
  289. begin match read_byte ch with
  290. | 1 ->
  291. strings.(!i) <- nread_string ch (read_ui16 ch)
  292. | 3 ->
  293. ignore(read_real_i32 ch)
  294. | 4 ->
  295. ignore(read_float32 ch)
  296. | 5 ->
  297. incr i;
  298. ignore(read_i64 ch)
  299. | 6 ->
  300. incr i;
  301. ignore(read_double ch)
  302. | 7 ->
  303. paths.(!i) <- read_ui16 ch
  304. | 8 ->
  305. ignore(read_ui16 ch)
  306. | 9 | 10 | 11 ->
  307. ignore(read_ui16 ch);
  308. ignore(read_ui16 ch);
  309. | 12 ->
  310. let name = read_ui16 ch in
  311. let t = read_ui16 ch in
  312. name_and_types.(!i) <- (name,t);
  313. | 15 ->
  314. ignore(read_byte ch);
  315. ignore(read_ui16 ch);
  316. | 16 ->
  317. ignore(read_ui16 ch);
  318. | 17 | 18 ->
  319. ignore(read_ui16 ch);
  320. ignore(read_ui16 ch);
  321. | 19 | 20 ->
  322. ignore(read_ui16 ch);
  323. | i ->
  324. failwith (Printf.sprintf "Invalid constant pool byte: %i" i);
  325. end;
  326. incr i;
  327. done;
  328. let as_path s = match List.rev (String.nsplit s "/") with
  329. | [x] -> [],x
  330. | x :: l -> List.rev l,x
  331. | [] -> assert false
  332. in
  333. let paths = Array.map (fun index ->
  334. if index > 0 then as_path (strings.(index))
  335. else ([],"")
  336. ) paths in
  337. let name_and_types = Array.map (fun (name,t) ->
  338. let name = if name > 0 then strings.(name) else "" in
  339. let t = if t > 0 then strings.(t) else "" in
  340. (name,t)
  341. ) name_and_types in
  342. {strings;paths;name_and_types}
  343. let rec parse_element_value consts ch =
  344. let tag = IO.read_byte ch in
  345. match Char.chr tag with
  346. | 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' ->
  347. let jsig = match (Char.chr tag) with
  348. | 's' ->
  349. TObject( (["java";"lang"],"String"), [] )
  350. | tag ->
  351. fst (parse_signature_part (Char.escaped tag))
  352. in
  353. ValConst(jsig,(read_ui16 ch))
  354. | 'e' ->
  355. let path = parse_signature (consts.strings.(read_ui16 ch)) in
  356. let name = consts.strings.(read_ui16 ch) in
  357. ValEnum (path, name)
  358. | 'c' ->
  359. let name = consts.strings.(read_ui16 ch) in
  360. let jsig = if name = "V" then
  361. TObject(([], "Void"), [])
  362. else
  363. parse_signature name
  364. in
  365. ValClass jsig
  366. | '@' ->
  367. ValAnnotation (parse_annotation consts ch)
  368. | '[' ->
  369. let num_vals = read_ui16 ch in
  370. ValArray (ExtList.List.init (num_vals) (fun _ -> parse_element_value consts ch))
  371. | tag ->
  372. failwith ("Invalid element value: '" ^ Char.escaped tag ^ "'")
  373. and parse_ann_element consts ch =
  374. let name = consts.strings.(read_ui16 ch) in
  375. let element_value = parse_element_value consts ch in
  376. name, element_value
  377. and parse_annotation consts ch =
  378. let anntype = parse_signature (consts.strings.(read_ui16 ch)) in
  379. let count = read_ui16 ch in
  380. {
  381. ann_type = anntype;
  382. ann_elements = ExtList.List.init count (fun _ -> parse_ann_element consts ch)
  383. }
  384. let rec parse_attribute consts ch =
  385. let name = consts.strings.(read_ui16 ch) in
  386. let length = read_i32 ch in
  387. match name with
  388. | "Code" ->
  389. ignore(read_ui16 ch); (* max stack *)
  390. ignore(read_ui16 ch); (* max locals *)
  391. let len = read_i32 ch in
  392. ignore(IO.nread_string ch len); (* code *)
  393. let len = read_ui16 ch in
  394. for _ = 0 to len - 1 do
  395. ignore(IO.nread_string ch 8);
  396. done; (* exceptions *)
  397. let attribs = parse_attributes consts ch in
  398. AttrCode attribs
  399. | "Deprecated" ->
  400. AttrDeprecated
  401. | "LocalVariableTable" ->
  402. let len = read_ui16 ch in
  403. let locals = ExtList.List.init len (fun _ ->
  404. let start_pc = read_ui16 ch in
  405. let length = read_ui16 ch in
  406. let name = consts.strings.(read_ui16 ch) in
  407. let descriptor = consts.strings.(read_ui16 ch) in
  408. let index = read_ui16 ch in
  409. {
  410. ld_start_pc = start_pc;
  411. ld_length = length;
  412. ld_name = name;
  413. ld_descriptor = descriptor;
  414. ld_index = index
  415. }
  416. ) in
  417. AttrLocalVariableTable locals
  418. | "MethodParameters" ->
  419. let len = IO.read_byte ch in
  420. let parameters = ExtList.List.init len (fun _ ->
  421. let name = consts.strings.(read_ui16 ch) in
  422. let flags = read_ui16 ch in
  423. (name,flags)
  424. ) in
  425. AttrMethodParameters parameters
  426. | "RuntimeVisibleAnnotations" ->
  427. let count = read_ui16 ch in
  428. AttrVisibleAnnotations (ExtList.List.init count (fun _ -> parse_annotation consts ch))
  429. | "Signature" ->
  430. let s = consts.strings.(read_ui16 ch) in
  431. AttrSignature s
  432. | _ ->
  433. ignore(nread ch length);
  434. AttrOther
  435. and parse_attributes consts ch =
  436. Array.to_list (Array.init (read_ui16 ch) (fun _ ->
  437. parse_attribute consts ch
  438. ))
  439. let parse_field consts is_method ch =
  440. let flags = read_ui16 ch in
  441. let name = consts.strings.(read_ui16 ch) in
  442. let descriptor = consts.strings.(read_ui16 ch) in
  443. let attributes = parse_attributes consts ch in
  444. let types = ref [] in
  445. let jsig = ref None in
  446. let code = ref None in
  447. List.iter (function
  448. | AttrCode code' ->
  449. code := Some code'
  450. | AttrSignature s ->
  451. if is_method then begin
  452. let tp, sgn, thr = parse_complete_method_signature s in
  453. types := tp;
  454. jsig := Some (TMethod(sgn));
  455. end else
  456. jsig := Some (parse_signature s)
  457. | _ ->
  458. ()
  459. ) attributes;
  460. {
  461. jf_name = name;
  462. jf_flags = flags;
  463. jf_types = !types;
  464. jf_descriptor = (match !jsig with
  465. | None -> parse_signature descriptor;
  466. | Some jsig -> jsig);
  467. jf_attributes = attributes;
  468. jf_code = !code;
  469. }
  470. let parse_class ch =
  471. if read_real_i32 ch <> 0xCAFEBABEl then failwith "Invalid header";
  472. let _ = read_ui16 ch in
  473. let _ = read_ui16 ch in
  474. let consts = read_constant_pool ch in
  475. let flags = read_ui16 ch in
  476. let this = consts.paths.(read_ui16 ch) in
  477. let super = TObject(consts.paths.(read_ui16 ch),[]) in
  478. let interfaces = ExtList.List.init (read_ui16 ch) (fun _ ->
  479. TObject(consts.paths.(read_ui16 ch),[])
  480. ) in
  481. let fields = ExtList.List.init (read_ui16 ch) (fun _ -> parse_field consts false ch) in
  482. let methods = ExtList.List.init (read_ui16 ch) (fun _ -> parse_field consts true ch) in
  483. let attributes = parse_attributes consts ch in
  484. let types = ref [] in
  485. let interfaces = ref interfaces in
  486. let super = ref super in
  487. List.iter (function
  488. | AttrSignature s ->
  489. let formal, idx = parse_formal_type_params s in
  490. types := formal;
  491. let s = String.sub s idx (String.length s - idx) in
  492. let len = String.length s in
  493. let sup, idx = parse_signature_part s in
  494. let rec loop idx acc =
  495. if idx = len then
  496. acc
  497. else begin
  498. let s = String.sub s idx (len - idx) in
  499. let iface, i2 = parse_signature_part s in
  500. loop (idx + i2) (iface :: acc)
  501. end
  502. in
  503. interfaces := loop idx [];
  504. super := sup;
  505. | _ ->
  506. ()
  507. ) attributes;
  508. {
  509. jc_path = this;
  510. jc_flags = flags;
  511. jc_super = !super;
  512. jc_interfaces = !interfaces;
  513. jc_types = !types;
  514. jc_fields = fields;
  515. jc_methods = methods;
  516. jc_attributes = attributes;
  517. }
  518. end
  519. module PathConverter = struct
  520. let jname_to_hx name =
  521. let name =
  522. if name <> "" && (String.get name 0 < 'A' || String.get name 0 > 'Z') then
  523. Char.escaped (Char.uppercase_ascii (String.get name 0)) ^ String.sub name 1 (String.length name - 1)
  524. else
  525. name
  526. in
  527. let name = String.concat "__" (String.nsplit name "_") in
  528. match String.nsplit name "$" with
  529. | [] ->
  530. die "" __LOC__
  531. | [_] ->
  532. None,name
  533. | [x;""] ->
  534. None,x ^ "_" (* trailing $ *)
  535. | x :: l ->
  536. let name = String.concat "_" (x :: l) in
  537. if x = "" then None,name (* leading $ *)
  538. else Some x,name
  539. let normalize_pack pack =
  540. List.map (function
  541. | "" -> ""
  542. | str when String.get str 0 >= 'A' && String.get str 0 <= 'Z' ->
  543. String.lowercase str
  544. | str -> str
  545. ) pack
  546. let jpath_to_hx (pack,name) =
  547. let pack,name = match pack,name with
  548. | ["haxe";"root"],name ->
  549. [],name
  550. | "com" :: ("oracle" | "sun") :: _, _
  551. | "javax" :: _, _
  552. | "org" :: ("ietf" | "jcp" | "omg" | "w3c" | "xml") :: _, _
  553. | "sun" :: _, _
  554. | "sunw" :: _, _ ->
  555. "java" :: pack,name
  556. | _ ->
  557. pack,name
  558. in
  559. let pack = normalize_pack pack in
  560. pack,jname_to_hx name
  561. let jpath_to_path (pack,(mname,name)) =
  562. let pack,name = match mname with
  563. | None -> pack,name
  564. | Some mname -> pack @ [mname],name
  565. in
  566. pack,name
  567. let is_haxe_keyword = function
  568. | "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true
  569. | _ -> false
  570. end
  571. type java_lib_ctx = {
  572. type_params : (string,complex_type) PMap.t;
  573. }
  574. module SignatureConverter = struct
  575. open PathConverter
  576. let mk_type_path path params p =
  577. let pack,(mname,name) = jpath_to_hx path in
  578. let path = match mname with
  579. | None ->
  580. {
  581. tpackage = pack;
  582. tname = name;
  583. tparams = params;
  584. tsub = None;
  585. }
  586. | Some mname ->
  587. {
  588. tpackage = pack;
  589. tname = mname;
  590. tparams = params;
  591. tsub = Some name;
  592. }
  593. in
  594. make_ptp_ct path p
  595. let ct_type_param name = make_ptp_ct_null {
  596. tpackage = [];
  597. tname = name;
  598. tparams = [];
  599. tsub = None
  600. }
  601. let ct_void = make_ptp_ct_null {
  602. tpackage = [];
  603. tname = "Void";
  604. tparams = [];
  605. tsub = None;
  606. }
  607. let ct_dynamic = make_ptp_ct_null {
  608. tpackage = [];
  609. tname = "Dynamic";
  610. tparams = [];
  611. tsub = None;
  612. }
  613. let ct_string = make_ptp_ct_null {
  614. tpackage = [];
  615. tname = "String";
  616. tparams = [];
  617. tsub = None;
  618. }
  619. let rec convert_arg ctx p arg =
  620. match arg with
  621. | TAny | TType (WSuper, _) -> TPType (mk_type_path ([], "Dynamic") [] p,p)
  622. | TType (_, jsig) -> TPType (convert_signature ctx p jsig,p)
  623. and convert_signature ctx p jsig =
  624. match jsig with
  625. | TByte -> mk_type_path (["java"; "types"], "Int8") [] p
  626. | TChar -> mk_type_path (["java"; "types"], "Char16") [] p
  627. | TDouble -> mk_type_path ([], "Float") [] p
  628. | TFloat -> mk_type_path ([], "Single") [] p
  629. | TInt -> mk_type_path ([], "Int") [] p
  630. | TLong -> mk_type_path (["haxe"], "Int64") [] p
  631. | TShort -> mk_type_path (["java"; "types"], "Int16") [] p
  632. | TBool -> mk_type_path ([], "Bool") [] p
  633. | TObject ( (["haxe";"root"], name), args ) -> mk_type_path ([], name) (List.map (convert_arg ctx p) args) p
  634. | TObject ( (["java";"lang"], "Object"), [] ) -> mk_type_path ([], "Dynamic") [] p
  635. | TObject ( (["java";"lang"], "String"), [] ) -> mk_type_path ([], "String") [] p
  636. | TObject ( (["java";"lang"], "Enum"), [_] ) -> mk_type_path ([], "EnumValue") [] p
  637. | TObject ( path, [] ) ->
  638. mk_type_path path [] p
  639. | TObject ( path, args ) -> mk_type_path path (List.map (convert_arg ctx p) args) p
  640. | TObjectInner (pack, (name, params) :: inners) ->
  641. let actual_param = match List.rev inners with
  642. | (_, p) :: _ -> p
  643. | _ -> die "" __LOC__ in
  644. mk_type_path (pack, name ^ "$" ^ String.concat "$" (List.map fst inners)) (List.map (fun param -> convert_arg ctx p param) actual_param) p
  645. | TObjectInner (pack, inners) -> die "" __LOC__
  646. | TArray (jsig, _) -> mk_type_path (["java"], "NativeArray") [ TPType (convert_signature ctx p jsig,p) ] p
  647. | TMethod _ -> failwith "TMethod cannot be converted directly into Complex Type"
  648. | TTypeParameter s ->
  649. try
  650. PMap.find s ctx.type_params
  651. with Not_found ->
  652. ct_dynamic
  653. end
  654. let get_type_path ct = match ct with | CTPath ptp -> ptp | _ -> die "" __LOC__
  655. module Converter = struct
  656. open JReaderModern
  657. open PathConverter
  658. open SignatureConverter
  659. let extract_retention_policy l =
  660. let rec loop2 l = match l with
  661. | [] ->
  662. None
  663. | ann :: l ->
  664. match ann.ann_type,ann.ann_elements with
  665. | TObject((["java";"lang";"annotation"],"Retention"),_),[("value",ValEnum(_,name))] ->
  666. Some name
  667. | _ ->
  668. loop2 l
  669. in
  670. let rec loop l = match l with
  671. | [] ->
  672. None
  673. | AttrVisibleAnnotations l :: _ ->
  674. loop2 l
  675. | _ :: l ->
  676. loop l
  677. in
  678. loop l
  679. let convert_type_parameter ctx (name,extends,implements) p =
  680. let jsigs = match extends with
  681. | Some jsig -> jsig :: implements
  682. | None -> implements
  683. in
  684. let constraints = ExtList.List.filter_map (fun jsig -> match jsig with
  685. | TTypeParameter name' when name = name' ->
  686. None
  687. | _ ->
  688. Some (convert_signature ctx p jsig,p)
  689. ) jsigs in
  690. let tp = {
  691. tp_name = (name,p);
  692. tp_params = [];
  693. tp_meta = [];
  694. tp_default = None;
  695. tp_constraints = match constraints with
  696. | [] -> None
  697. | _ -> Some (CTIntersection constraints,p);
  698. } in
  699. tp
  700. let convert_enum (jc : jclass) (file : string) =
  701. let p = {
  702. pfile = file;
  703. pmin = 0;
  704. pmax = 0
  705. } in
  706. let meta = ref [] in
  707. let add_meta m = meta := m :: !meta in
  708. let data = ref [] in
  709. List.iter (fun (jf : jfield) ->
  710. match jf.jf_descriptor with
  711. | TObject( path, [] ) when path = jc.jc_path && AccessFlags.has_flag jf.jf_flags MStatic && AccessFlags.has_flag jf.jf_flags MFinal ->
  712. data := { ec_name = jf.jf_name,p; ec_doc = None; ec_meta = []; ec_args = []; ec_pos = p; ec_params = []; ec_type = None; } :: !data;
  713. | _ -> ()
  714. ) jc.jc_fields;
  715. let _,class_name = jname_to_hx (snd jc.jc_path) in
  716. add_meta (Meta.Native, [EConst (String (s_type_path jc.jc_path,SDoubleQuotes) ),p],p);
  717. let d = {
  718. d_name = (class_name,p);
  719. d_doc = None;
  720. d_params = []; (* enums never have type parameters *)
  721. d_meta = !meta;
  722. d_flags = [EExtern];
  723. d_data = List.rev !data;
  724. } in
  725. (EEnum d,p)
  726. let type_param_lut acc params =
  727. List.fold_left (fun acc (s,_,_) ->
  728. PMap.add s (ct_type_param s) acc
  729. ) acc params
  730. (**
  731. `haxe.Rest<T>` auto-boxes primitive types.
  732. That means we can't use it as varargs for extern methods.
  733. E.g externs with `int` varargs are represented as `int[]` at run time
  734. while `haxe.Rest<Int>` is actually `java.lang.Integer[]`.
  735. *)
  736. let is_eligible_for_haxe_rest_args arg_type =
  737. match arg_type with
  738. | TByte | TChar | TDouble | TFloat | TInt | TLong | TShort | TBool -> false
  739. | _ -> true
  740. let convert_field ctx is_method (jc : jclass) (is_interface : bool) (jf : jfield) p =
  741. let ctx = {
  742. type_params = type_param_lut ctx.type_params jf.jf_types;
  743. } in
  744. let p = {p with pfile = p.pfile ^ "@" ^ jf.jf_name} in
  745. let is_static = AccessFlags.has_flag jf.jf_flags MStatic in
  746. let access = ref [] in
  747. let meta = ref [] in
  748. let add_access a = access := a :: !access in
  749. let add_meta m = meta := m :: !meta in
  750. if is_static then add_access (AStatic,p);
  751. List.iter (function
  752. | AttrDeprecated when jc.jc_path <> (["java";"util"],"Date") ->
  753. add_meta (Meta.Deprecated,[],p);
  754. | AttrVisibleAnnotations ann ->
  755. List.iter (function
  756. | { ann_type = TObject( (["java";"lang"], "Override"), [] ) } ->
  757. add_access (AOverride,null_pos);
  758. | _ -> ()
  759. ) ann
  760. | AttrCode _ when is_interface ->
  761. add_meta (Meta.JavaDefault,[],p)
  762. | _ -> ()
  763. ) jf.jf_attributes;
  764. let add_native_meta () =
  765. add_meta (Meta.Native, [EConst (String (jf.jf_name,SDoubleQuotes) ),p],p)
  766. in
  767. let name = match String.nsplit jf.jf_name "$" with
  768. | ["<init>"] ->
  769. "new"
  770. | [name] ->
  771. if is_haxe_keyword name then begin
  772. add_native_meta();
  773. "_" ^ name
  774. end else
  775. name
  776. | parts ->
  777. add_native_meta();
  778. String.concat "_" parts
  779. in
  780. if is_method then add_access (AOverload,p);
  781. if AccessFlags.has_flag jf.jf_flags MFinal then add_access (AFinal,p);
  782. if not is_interface && AccessFlags.has_flag jf.jf_flags MAbstract then add_access (AAbstract,p);
  783. let extract_local_names () =
  784. let default i =
  785. "param" ^ string_of_int i
  786. in
  787. let rec loop attribs = match attribs with
  788. | AttrLocalVariableTable locals :: _ ->
  789. let shift = if is_static then 0 else -1 in
  790. List.map (fun loc ->
  791. loc.ld_index + shift,loc.ld_name
  792. ) locals
  793. | AttrMethodParameters l :: _ ->
  794. List.mapi (fun i (name,_) ->
  795. (i,name)
  796. ) l
  797. | _ :: attribs ->
  798. loop attribs
  799. | [] ->
  800. raise Not_found
  801. in
  802. let use locals =
  803. let h = Hashtbl.create 0 in
  804. List.iter (fun (index,name) ->
  805. Hashtbl.replace h index name
  806. ) locals;
  807. (fun i ->
  808. try Hashtbl.find h (i - 1) (* they are 1-based *)
  809. with Not_found -> "param" ^ string_of_int i
  810. )
  811. in
  812. try
  813. use (loop jf.jf_attributes)
  814. with Not_found -> try
  815. match jf.jf_code with
  816. | None ->
  817. default
  818. | Some attribs ->
  819. use (loop attribs)
  820. with Not_found ->
  821. default
  822. in
  823. let kind = if not is_method then
  824. FVar(Some (convert_signature ctx p jf.jf_descriptor,p),None)
  825. else
  826. begin match jf.jf_descriptor with
  827. | TMethod(args,ret) ->
  828. let local_names = extract_local_names() in
  829. let args_count = List.length args
  830. and is_varargs = AccessFlags.has_flag jf.jf_flags MVarargs in
  831. let convert_arg i jsig =
  832. let name = local_names (i + 1) in
  833. let hx_sig =
  834. match jsig with
  835. | TArray (jsig1,_) when is_varargs && i + 1 = args_count && is_eligible_for_haxe_rest_args jsig1 ->
  836. mk_type_path (["haxe"], "Rest") [TPType (convert_signature ctx p jsig1,p)] p
  837. | _ ->
  838. convert_signature ctx p jsig
  839. in
  840. ((name,p),false,[],Some (hx_sig,p),None)
  841. in
  842. let f = {
  843. f_params = List.map (fun tp -> convert_type_parameter ctx tp p) jf.jf_types;
  844. f_args = List.mapi convert_arg args;
  845. f_type = Some (Option.map_default (fun jsig -> convert_signature ctx p jsig,p) (ct_void,p) ret);
  846. f_expr = None;
  847. } in
  848. FFun f
  849. | _ ->
  850. assert false
  851. end
  852. in
  853. let cff = {
  854. cff_name = (name,p);
  855. cff_doc = None;
  856. cff_pos = p;
  857. cff_meta = !meta;
  858. cff_access = !access;
  859. cff_kind = kind;
  860. } in
  861. cff
  862. let convert_class ctx (jc : jclass) (file : string) =
  863. let p = {
  864. pfile = file;
  865. pmin = 0;
  866. pmax = 0
  867. } in
  868. let flags = ref [HExtern] in
  869. let meta = ref [] in
  870. let add_flag f = flags := f :: !flags in
  871. let add_meta m = meta := m :: !meta in
  872. add_meta (Meta.LibType,[],p);
  873. let is_interface = AccessFlags.has_flag jc.jc_flags MInterface in
  874. if is_interface then add_flag HInterface
  875. else if AccessFlags.has_flag jc.jc_flags MAbstract then add_flag HAbstract;
  876. let is_annotation = AccessFlags.has_flag jc.jc_flags MAnnotation in
  877. begin match jc.jc_super with
  878. | TObject(([],""),_)
  879. | TObject((["java";"lang"],"Object"),_) ->
  880. if is_annotation then
  881. add_flag (HExtends (make_ptp {tpackage = ["java";"lang";"annotation"]; tname = "Annotation"; tsub = None; tparams = []} p))
  882. | jsig ->
  883. add_flag (HExtends (get_type_path (convert_signature ctx p jsig)))
  884. end;
  885. List.iter (fun jsig ->
  886. let path = get_type_path (convert_signature ctx p jsig) in
  887. if is_interface then
  888. add_flag (HExtends path)
  889. else
  890. add_flag (HImplements path)
  891. ) jc.jc_interfaces;
  892. let fields = DynArray.create () in
  893. let known_names = Hashtbl.create 0 in
  894. let known_sigs = Hashtbl.create 0 in
  895. let should_generate jf =
  896. not (AccessFlags.has_flag jf.jf_flags MPrivate)
  897. (* We might need member synthetics for proper call resolution, but we should never need static ones (issue #10279). *)
  898. && (not (AccessFlags.has_flag jf.jf_flags MSynthetic) || not (AccessFlags.has_flag jf.jf_flags MStatic))
  899. && jf.jf_name <> "<clinit>"
  900. in
  901. if jc.jc_path <> (["java";"lang"], "CharSequence") then begin
  902. List.iter (fun jf ->
  903. if should_generate jf then begin
  904. Hashtbl.replace known_names jf.jf_name jf;
  905. let sig_key = match jf.jf_descriptor with
  906. | TMethod(jsigs,_) -> TMethod(jsigs,None) (* lack of return type variance *)
  907. | jsig -> jsig
  908. in
  909. let key = (jf.jf_name,sig_key) in
  910. if not (Hashtbl.mem known_sigs key) then begin
  911. Hashtbl.add known_sigs key jf;
  912. DynArray.add fields (convert_field ctx true jc is_interface jf p)
  913. end
  914. end
  915. ) jc.jc_methods;
  916. List.iter (fun jf ->
  917. if should_generate jf then begin
  918. if not (Hashtbl.mem known_names jf.jf_name) then begin
  919. Hashtbl.add known_names jf.jf_name jf;
  920. DynArray.add fields (convert_field ctx false jc is_interface jf p)
  921. end
  922. end
  923. ) jc.jc_fields;
  924. end;
  925. let _,class_name = jname_to_hx (snd jc.jc_path) in
  926. add_meta (Meta.Native, [EConst (String (s_type_path jc.jc_path,SDoubleQuotes) ),p],p);
  927. if is_annotation then begin
  928. let args = match extract_retention_policy jc.jc_attributes with
  929. | None ->
  930. []
  931. | Some v ->
  932. [EConst (String(v,SDoubleQuotes)),p]
  933. in
  934. add_meta (Meta.Annotation,args,p)
  935. end;
  936. let d = {
  937. d_name = (class_name,p);
  938. d_doc = None;
  939. d_params = List.map (fun tp -> convert_type_parameter ctx tp p) jc.jc_types;
  940. d_meta = !meta;
  941. d_flags = !flags;
  942. d_data = DynArray.to_list fields;
  943. } in
  944. (EClass d,p)
  945. let convert_type ctx jc file =
  946. if AccessFlags.has_flag jc.jc_flags MEnum then convert_enum jc file else convert_class ctx jc file
  947. let convert_module pack jcs =
  948. let types = List.map (fun (jc,_,file) ->
  949. let ctx = {
  950. type_params = type_param_lut PMap.empty jc.jc_types;
  951. } in
  952. convert_type ctx jc file;
  953. ) jcs in
  954. (pack,types)
  955. end
  956. class java_library_modern com name file_path = object(self)
  957. inherit [java_lib_type,unit] native_library name file_path as super
  958. val zip = lazy (Zip.open_in file_path)
  959. val mutable cached_files = []
  960. val modules = Hashtbl.create 0
  961. val mutable loaded = false
  962. val mutable closed = false
  963. method load =
  964. if not loaded then begin
  965. loaded <- true;
  966. let close = Timer.timer ["jar";"load"] in
  967. List.iter (function
  968. | ({ Zip.is_directory = false; Zip.filename = filename } as entry) when String.ends_with filename ".class" ->
  969. let pack = String.nsplit filename "/" in
  970. begin match List.rev pack with
  971. | [] -> ()
  972. | name :: pack ->
  973. let name = String.sub name 0 (String.length name - 6) in
  974. let pack = List.rev pack in
  975. let pack,(mname,tname) = PathConverter.jpath_to_hx (pack,name) in
  976. let path = PathConverter.jpath_to_path (pack,(mname,tname)) in
  977. let mname = match mname with
  978. | None ->
  979. cached_files <- path :: cached_files;
  980. tname
  981. | Some mname -> mname
  982. in
  983. Hashtbl.add modules (pack,mname) (filename,entry);
  984. end
  985. | _ -> ()
  986. ) (Zip.entries (Lazy.force zip));
  987. close();
  988. end
  989. method private read zip (filename,entry) =
  990. Std.finally (Timer.timer ["jar";"read"]) (fun () ->
  991. let data = Zip.read_entry zip entry in
  992. let jc = JReaderModern.parse_class (IO.input_string data) in
  993. (jc,file_path,file_path ^ "@" ^ filename)
  994. ) ()
  995. method lookup path : java_lib_type =
  996. None
  997. method close =
  998. if not closed then begin
  999. closed <- true;
  1000. Zip.close_in (Lazy.force zip)
  1001. end
  1002. method list_modules : path list =
  1003. cached_files
  1004. method build path (p : pos) : Ast.package option =
  1005. let build path =
  1006. if path = (["java";"lang"],"String") then
  1007. None
  1008. else begin
  1009. try
  1010. let entries = Hashtbl.find_all modules path in
  1011. if entries = [] then raise Not_found;
  1012. let zip = Lazy.force zip in
  1013. let jcs = List.map (self#read zip) entries in
  1014. Std.finally (Timer.timer ["jar";"convert"]) (fun () ->
  1015. Some (Converter.convert_module (fst path) jcs)
  1016. ) ();
  1017. with Not_found ->
  1018. None
  1019. end
  1020. in
  1021. build path
  1022. method get_data = ()
  1023. end