common.ml 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  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 Ast
  17. open CompilationServer
  18. open Type
  19. open Globals
  20. open Define
  21. open NativeLibraries
  22. type package_rule =
  23. | Forbidden
  24. | Directory of string
  25. | Remap of string
  26. type pos = Globals.pos
  27. let const_type basic const default =
  28. match const with
  29. | TString _ -> basic.tstring
  30. | TInt _ -> basic.tint
  31. | TFloat _ -> basic.tfloat
  32. | TBool _ -> basic.tbool
  33. | _ -> default
  34. type stats = {
  35. s_files_parsed : int ref;
  36. s_classes_built : int ref;
  37. s_methods_typed : int ref;
  38. s_macros_called : int ref;
  39. }
  40. type compiler_message =
  41. | CMInfo of string * pos
  42. | CMWarning of string * pos
  43. | CMError of string * pos
  44. let compiler_message_string msg =
  45. let (str,p) = match msg with
  46. | CMInfo(str,p) | CMError(str,p) -> (str,p)
  47. | CMWarning(str,p) -> ("Warning : " ^ str, p)
  48. in
  49. if p = null_pos then
  50. str
  51. else begin
  52. let error_printer file line = Printf.sprintf "%s:%d:" file line in
  53. let epos = Lexer.get_error_pos error_printer p in
  54. let str = String.concat ("\n" ^ epos ^ " : ") (ExtString.String.nsplit str "\n") in
  55. Printf.sprintf "%s : %s" epos str
  56. end
  57. (**
  58. The capture policy tells which handling we make of captured locals
  59. (the locals which are referenced in local functions)
  60. See details/implementation in Codegen.captured_vars
  61. *)
  62. type capture_policy =
  63. (** do nothing, let the platform handle it *)
  64. | CPNone
  65. (** wrap all captured variables into a single-element array to allow modifications *)
  66. | CPWrapRef
  67. (** similar to wrap ref, but will only apply to the locals that are declared in loops *)
  68. | CPLoopVars
  69. type platform_config = {
  70. (** has a static type system, with not-nullable basic types (Int/Float/Bool) *)
  71. pf_static : bool;
  72. (** has access to the "sys" package *)
  73. pf_sys : bool;
  74. (** captured variables handling (see before) *)
  75. pf_capture_policy : capture_policy;
  76. (** when calling a method with optional args, do we replace the missing args with "null" constants *)
  77. pf_pad_nulls : bool;
  78. (** add a final return to methods not having one already - prevent some compiler warnings *)
  79. pf_add_final_return : bool;
  80. (** does the platform natively support overloaded functions *)
  81. pf_overload : bool;
  82. (** can the platform use default values for non-nullable arguments *)
  83. pf_can_skip_non_nullable_argument : bool;
  84. (** type paths that are reserved on the platform *)
  85. pf_reserved_type_paths : path list;
  86. (** supports function == function **)
  87. pf_supports_function_equality : bool;
  88. (** uses utf16 encoding with ucs2 api **)
  89. pf_uses_utf16 : bool;
  90. (** target supports accessing `this` before calling `super(...)` **)
  91. pf_this_before_super : bool;
  92. (** target supports threads **)
  93. pf_supports_threads : bool;
  94. (** target supports Unicode **)
  95. pf_supports_unicode : bool;
  96. }
  97. class compiler_callbacks = object(self)
  98. val mutable before_typer_create = [];
  99. val mutable after_init_macros = [];
  100. val mutable after_typing = [];
  101. val mutable before_save = [];
  102. val mutable after_save = [];
  103. val mutable after_filters = [];
  104. val mutable after_generation = [];
  105. val mutable null_safety_report = [];
  106. method add_before_typer_create (f : unit -> unit) : unit =
  107. before_typer_create <- f :: before_typer_create
  108. method add_after_init_macros (f : unit -> unit) : unit =
  109. after_init_macros <- f :: after_init_macros
  110. method add_after_typing (f : module_type list -> unit) : unit =
  111. after_typing <- f :: after_typing
  112. method add_before_save (f : unit -> unit) : unit =
  113. before_save <- f :: before_save
  114. method add_after_save (f : unit -> unit) : unit =
  115. after_save <- f :: after_save
  116. method add_after_filters (f : unit -> unit) : unit =
  117. after_filters <- f :: after_filters
  118. method add_after_generation (f : unit -> unit) : unit =
  119. after_generation <- f :: after_generation
  120. method add_null_safety_report (f : (string*pos) list -> unit) : unit =
  121. null_safety_report <- f :: null_safety_report
  122. method get_before_typer_create = before_typer_create
  123. method get_after_init_macros = after_init_macros
  124. method get_after_typing = after_typing
  125. method get_before_save = before_save
  126. method get_after_save = after_save
  127. method get_after_filters = after_filters
  128. method get_after_generation = after_generation
  129. method get_null_safety_report = null_safety_report
  130. end
  131. type shared_display_information = {
  132. mutable diagnostics_messages : (string * pos * DisplayTypes.DiagnosticsKind.t * DisplayTypes.DiagnosticsSeverity.t) list;
  133. mutable dead_blocks : (string,(pos * expr) list) Hashtbl.t;
  134. }
  135. type display_information = {
  136. mutable unresolved_identifiers : (string * pos * (string * CompletionItem.t * int) list) list;
  137. mutable interface_field_implementations : (tclass * tclass_field * tclass * tclass_field option) list;
  138. mutable display_module_has_macro_defines : bool;
  139. }
  140. (* This information is shared between normal and macro context. *)
  141. type shared_context = {
  142. shared_display_information : shared_display_information;
  143. }
  144. type json_api = {
  145. send_result : Json.t -> unit;
  146. send_error : Json.t list -> unit;
  147. jsonrpc : Jsonrpc_handler.jsonrpc_handler;
  148. }
  149. type compiler_stage =
  150. | CCreated (* Context was just created *)
  151. | CInitialized (* Context was initialized (from CLI args and such). *)
  152. | CTyperCreated (* The typer context was just created. *)
  153. | CInitMacrosStart (* Init macros are about to run. *)
  154. | CInitMacrosDone (* Init macros did run - at this point the signature is locked. *)
  155. | CTypingDone (* The typer is done - at this point com.types/modules/main is filled. *)
  156. | CFilteringStart (* Filtering just started (nothing changed yet). *)
  157. | CAnalyzerStart (* Some filters did run, the analyzer is about to run. *)
  158. | CAnalyzerDone (* The analyzer just finished. *)
  159. | CSaveStart (* The type state is about to be saved. *)
  160. | CSaveDone (* The type state has been saved - at this point we can destroy things. *)
  161. | CDceStart (* DCE is about to run - everything is still available. *)
  162. | CDceDone (* DCE just finished. *)
  163. | CFilteringDone (* Filtering just finished. *)
  164. | CGenerationStart (* Generation is about to begin. *)
  165. | CGenerationDone (* Generation just finished. *)
  166. type context = {
  167. mutable stage : compiler_stage;
  168. mutable cache : context_cache option;
  169. (* config *)
  170. version : int;
  171. args : string list;
  172. shared : shared_context;
  173. display_information : display_information;
  174. mutable sys_args : string list;
  175. mutable display : DisplayTypes.DisplayMode.settings;
  176. mutable debug : bool;
  177. mutable verbose : bool;
  178. mutable foptimize : bool;
  179. mutable platform : platform;
  180. mutable config : platform_config;
  181. mutable std_path : string list;
  182. mutable class_path : string list;
  183. mutable main_class : path option;
  184. mutable package_rules : (string,package_rule) PMap.t;
  185. mutable error : string -> pos -> unit;
  186. mutable info : string -> pos -> unit;
  187. mutable warning : string -> pos -> unit;
  188. mutable get_messages : unit -> compiler_message list;
  189. mutable filter_messages : (compiler_message -> bool) -> unit;
  190. mutable load_extern_type : (string * (path -> pos -> Ast.package option)) list; (* allow finding types which are not in sources *)
  191. callbacks : compiler_callbacks;
  192. defines : Define.define;
  193. mutable print : string -> unit;
  194. mutable get_macros : unit -> context option;
  195. mutable run_command : string -> int;
  196. file_lookup_cache : (string,string option) Hashtbl.t;
  197. readdir_cache : (string * string,(string array) option) Hashtbl.t;
  198. parser_cache : (string,(type_def * pos) list) Hashtbl.t;
  199. module_to_file : (path,string) Hashtbl.t;
  200. cached_macros : (path * string,(((string * bool * t) list * t * tclass * Type.tclass_field) * module_def)) Hashtbl.t;
  201. mutable stored_typed_exprs : (int, texpr) PMap.t;
  202. pass_debug_messages : string DynArray.t;
  203. (* output *)
  204. mutable file : string;
  205. mutable flash_version : float;
  206. mutable features : (string,bool) Hashtbl.t;
  207. mutable modules : Type.module_def list;
  208. mutable main : Type.texpr option;
  209. mutable types : Type.module_type list;
  210. mutable resources : (string,string) Hashtbl.t;
  211. mutable neko_libs : string list;
  212. mutable include_files : (string * string) list;
  213. mutable native_libs : native_libraries;
  214. mutable net_std : string list;
  215. net_path_map : (path,string list * string list * string) Hashtbl.t;
  216. mutable c_args : string list;
  217. mutable js_gen : (unit -> unit) option;
  218. mutable json_out : json_api option;
  219. (* typing *)
  220. mutable basic : basic_types;
  221. memory_marker : float array;
  222. }
  223. exception Abort of string * pos
  224. (* Defines *)
  225. module Define = Define
  226. let defined com s =
  227. Define.defined com.defines s
  228. let raw_defined com v =
  229. Define.raw_defined com.defines v
  230. let defined_value com v =
  231. Define.defined_value com.defines v
  232. let defined_value_safe ?default com v =
  233. match default with
  234. | Some s -> Define.defined_value_safe ~default:s com.defines v
  235. | None -> Define.defined_value_safe com.defines v
  236. let define com v =
  237. Define.define com.defines v
  238. let raw_define com v =
  239. Define.raw_define com.defines v
  240. let define_value com k v =
  241. Define.define_value com.defines k v
  242. let raw_defined_value com k =
  243. Define.raw_defined_value com.defines k
  244. let get_es_version com =
  245. try int_of_string (defined_value com Define.JsEs) with _ -> 0
  246. let short_platform_name = function
  247. | Cross -> "x"
  248. | Js -> "js"
  249. | Lua -> "lua"
  250. | Neko -> "n"
  251. | Flash -> "swf"
  252. | Php -> "php"
  253. | Cpp -> "cpp"
  254. | Cs -> "cs"
  255. | Java -> "jav"
  256. | Python -> "py"
  257. | Hl -> "hl"
  258. | Eval -> "evl"
  259. let stats =
  260. {
  261. s_files_parsed = ref 0;
  262. s_classes_built = ref 0;
  263. s_methods_typed = ref 0;
  264. s_macros_called = ref 0;
  265. }
  266. let default_config =
  267. {
  268. pf_static = true;
  269. pf_sys = true;
  270. pf_capture_policy = CPNone;
  271. pf_pad_nulls = false;
  272. pf_add_final_return = false;
  273. pf_overload = false;
  274. pf_can_skip_non_nullable_argument = true;
  275. pf_reserved_type_paths = [];
  276. pf_supports_function_equality = true;
  277. pf_uses_utf16 = true;
  278. pf_this_before_super = true;
  279. pf_supports_threads = false;
  280. pf_supports_unicode = true;
  281. }
  282. let get_config com =
  283. let defined f = PMap.mem (fst (Define.infos f)) com.defines.values in
  284. match com.platform with
  285. | Cross ->
  286. default_config
  287. | Js ->
  288. {
  289. default_config with
  290. pf_static = false;
  291. pf_sys = false;
  292. pf_capture_policy = CPLoopVars;
  293. pf_reserved_type_paths = [([],"Object");([],"Error")];
  294. pf_this_before_super = (get_es_version com) < 6; (* cannot access `this` before `super()` when generating ES6 classes *)
  295. }
  296. | Lua ->
  297. {
  298. default_config with
  299. pf_static = false;
  300. pf_capture_policy = CPLoopVars;
  301. pf_uses_utf16 = false;
  302. }
  303. | Neko ->
  304. {
  305. default_config with
  306. pf_static = false;
  307. pf_pad_nulls = true;
  308. pf_uses_utf16 = false;
  309. pf_supports_threads = true;
  310. pf_supports_unicode = false;
  311. }
  312. | Flash ->
  313. {
  314. default_config with
  315. pf_sys = false;
  316. pf_capture_policy = CPLoopVars;
  317. pf_can_skip_non_nullable_argument = false;
  318. pf_reserved_type_paths = [([],"Object");([],"Error")];
  319. }
  320. | Php ->
  321. {
  322. default_config with
  323. pf_static = false;
  324. pf_uses_utf16 = false;
  325. }
  326. | Cpp ->
  327. {
  328. default_config with
  329. pf_capture_policy = CPWrapRef;
  330. pf_pad_nulls = true;
  331. pf_add_final_return = true;
  332. pf_supports_threads = true;
  333. pf_supports_unicode = (defined Define.Cppia) || not (defined Define.DisableUnicodeStrings);
  334. }
  335. | Cs ->
  336. {
  337. default_config with
  338. pf_capture_policy = CPWrapRef;
  339. pf_pad_nulls = true;
  340. pf_overload = true;
  341. pf_supports_threads = true;
  342. }
  343. | Java ->
  344. {
  345. default_config with
  346. pf_capture_policy = CPWrapRef;
  347. pf_pad_nulls = true;
  348. pf_overload = true;
  349. pf_supports_threads = true;
  350. pf_this_before_super = false;
  351. }
  352. | Python ->
  353. {
  354. default_config with
  355. pf_static = false;
  356. pf_capture_policy = CPLoopVars;
  357. pf_uses_utf16 = false;
  358. }
  359. | Hl ->
  360. {
  361. default_config with
  362. pf_capture_policy = CPWrapRef;
  363. pf_pad_nulls = true;
  364. pf_supports_threads = true;
  365. }
  366. | Eval ->
  367. {
  368. default_config with
  369. pf_static = false;
  370. pf_pad_nulls = true;
  371. pf_uses_utf16 = false;
  372. pf_supports_threads = true;
  373. pf_capture_policy = CPWrapRef;
  374. }
  375. let memory_marker = [|Unix.time()|]
  376. let create version s_version args =
  377. let m = Type.mk_mono() in
  378. let defines =
  379. PMap.add "true" "1" (
  380. PMap.add "source-header" ("Generated by Haxe " ^ s_version) PMap.empty
  381. )
  382. in
  383. {
  384. cache = None;
  385. stage = CCreated;
  386. version = version;
  387. args = args;
  388. shared = {
  389. shared_display_information = {
  390. diagnostics_messages = [];
  391. dead_blocks = Hashtbl.create 0;
  392. }
  393. };
  394. display_information = {
  395. unresolved_identifiers = [];
  396. interface_field_implementations = [];
  397. display_module_has_macro_defines = false;
  398. };
  399. sys_args = args;
  400. debug = false;
  401. display = DisplayTypes.DisplayMode.create !Parser.display_mode;
  402. verbose = false;
  403. foptimize = true;
  404. features = Hashtbl.create 0;
  405. platform = Cross;
  406. config = default_config;
  407. print = (fun s -> print_string s; flush stdout);
  408. run_command = Sys.command;
  409. std_path = [];
  410. class_path = [];
  411. main_class = None;
  412. package_rules = PMap.empty;
  413. file = "";
  414. types = [];
  415. callbacks = new compiler_callbacks;
  416. modules = [];
  417. main = None;
  418. flash_version = 10.;
  419. resources = Hashtbl.create 0;
  420. net_std = [];
  421. native_libs = create_native_libs();
  422. net_path_map = Hashtbl.create 0;
  423. c_args = [];
  424. neko_libs = [];
  425. include_files = [];
  426. js_gen = None;
  427. load_extern_type = [];
  428. defines = {
  429. defines_signature = None;
  430. values = defines;
  431. };
  432. get_macros = (fun() -> None);
  433. info = (fun _ _ -> assert false);
  434. warning = (fun _ _ -> assert false);
  435. error = (fun _ _ -> assert false);
  436. get_messages = (fun() -> []);
  437. filter_messages = (fun _ -> ());
  438. pass_debug_messages = DynArray.create();
  439. basic = {
  440. tvoid = m;
  441. tint = m;
  442. tfloat = m;
  443. tbool = m;
  444. tnull = (fun _ -> assert false);
  445. tstring = m;
  446. tarray = (fun _ -> assert false);
  447. };
  448. file_lookup_cache = Hashtbl.create 0;
  449. readdir_cache = Hashtbl.create 0;
  450. module_to_file = Hashtbl.create 0;
  451. stored_typed_exprs = PMap.empty;
  452. cached_macros = Hashtbl.create 0;
  453. memory_marker = memory_marker;
  454. parser_cache = Hashtbl.create 0;
  455. json_out = None;
  456. }
  457. let log com str =
  458. if com.verbose then com.print (str ^ "\n")
  459. let clone com =
  460. let t = com.basic in
  461. { com with
  462. cache = None;
  463. basic = { t with tvoid = t.tvoid };
  464. main_class = None;
  465. features = Hashtbl.create 0;
  466. file_lookup_cache = Hashtbl.create 0;
  467. readdir_cache = Hashtbl.create 0;
  468. parser_cache = Hashtbl.create 0;
  469. module_to_file = Hashtbl.create 0;
  470. callbacks = new compiler_callbacks;
  471. display_information = {
  472. unresolved_identifiers = [];
  473. interface_field_implementations = [];
  474. display_module_has_macro_defines = false;
  475. };
  476. defines = {
  477. values = com.defines.values;
  478. defines_signature = com.defines.defines_signature;
  479. };
  480. native_libs = create_native_libs();
  481. }
  482. let file_time file = Extc.filetime file
  483. let file_extension file =
  484. match List.rev (ExtString.String.nsplit file ".") with
  485. | e :: _ -> String.lowercase e
  486. | [] -> ""
  487. let flash_versions = List.map (fun v ->
  488. let maj = int_of_float v in
  489. let min = int_of_float (mod_float (v *. 10.) 10.) in
  490. v, string_of_int maj ^ (if min = 0 then "" else "_" ^ string_of_int min)
  491. ) [9.;10.;10.1;10.2;10.3;11.;11.1;11.2;11.3;11.4;11.5;11.6;11.7;11.8;11.9;12.0;13.0;14.0;15.0;16.0;17.0;18.0;19.0;20.0;21.0;22.0;23.0;24.0;25.0;26.0;27.0;28.0;29.0;31.0;32.0]
  492. let flash_version_tag = function
  493. | 6. -> 6
  494. | 7. -> 7
  495. | 8. -> 8
  496. | 9. -> 9
  497. | 10. | 10.1 -> 10
  498. | 10.2 -> 11
  499. | 10.3 -> 12
  500. | 11. -> 13
  501. | 11.1 -> 14
  502. | 11.2 -> 15
  503. | 11.3 -> 16
  504. | 11.4 -> 17
  505. | 11.5 -> 18
  506. | 11.6 -> 19
  507. | 11.7 -> 20
  508. | 11.8 -> 21
  509. | 11.9 -> 22
  510. | v when v >= 12.0 && float_of_int (int_of_float v) = v -> int_of_float v + 11
  511. | v -> failwith ("Invalid SWF version " ^ string_of_float v)
  512. let init_platform com pf =
  513. com.platform <- pf;
  514. let name = platform_name pf in
  515. let forbid acc p = if p = name || PMap.mem p acc then acc else PMap.add p Forbidden acc in
  516. com.package_rules <- List.fold_left forbid com.package_rules ("jvm" :: (List.map platform_name platforms));
  517. com.config <- get_config com;
  518. if com.config.pf_static then begin
  519. raw_define_value com.defines "target.static" "true";
  520. define com Define.Static;
  521. end;
  522. if com.config.pf_sys then begin
  523. raw_define_value com.defines "target.sys" "true";
  524. define com Define.Sys
  525. end else
  526. com.package_rules <- PMap.add "sys" Forbidden com.package_rules;
  527. if com.config.pf_uses_utf16 then begin
  528. raw_define_value com.defines "target.utf16" "true";
  529. define com Define.Utf16;
  530. end;
  531. if com.config.pf_supports_threads then begin
  532. raw_define_value com.defines "target.threaded" "true";
  533. end;
  534. if com.config.pf_supports_unicode then begin
  535. raw_define_value com.defines "target.unicode" "true";
  536. end;
  537. raw_define_value com.defines "target.name" name;
  538. raw_define com name
  539. let add_feature com f =
  540. Hashtbl.replace com.features f true
  541. let has_dce com =
  542. (try defined_value com Define.Dce <> "no" with Not_found -> false)
  543. (*
  544. TODO: The has_dce check is there because we mark types with @:directlyUsed in the DCE filter,
  545. which is not run in dce=no and thus we can't know if a type is used directly or not,
  546. so we just assume that they are.
  547. If we had dce filter always running (even with dce=no), we would have types marked with @:directlyUsed
  548. and we wouldn't need to generate unnecessary imports in dce=no, but that's good enough for now.
  549. *)
  550. let is_directly_used com meta =
  551. not (has_dce com) || Meta.has Meta.DirectlyUsed meta
  552. let rec has_feature com f =
  553. try
  554. Hashtbl.find com.features f
  555. with Not_found ->
  556. if com.types = [] then not (has_dce com) else
  557. match List.rev (ExtString.String.nsplit f ".") with
  558. | [] -> assert false
  559. | [cl] -> has_feature com (cl ^ ".*")
  560. | field :: cl :: pack ->
  561. let r = (try
  562. let path = List.rev pack, cl in
  563. (match List.find (fun t -> t_path t = path && not (Meta.has Meta.RealPath (t_infos t).mt_meta)) com.types with
  564. | t when field = "*" ->
  565. not (has_dce com) ||
  566. (match t with TAbstractDecl a -> Meta.has Meta.ValueUsed a.a_meta | _ -> Meta.has Meta.Used (t_infos t).mt_meta)
  567. | TClassDecl ({cl_extern = true} as c) when com.platform <> Js || cl <> "Array" && cl <> "Math" ->
  568. not (has_dce com) || Meta.has Meta.Used (try PMap.find field c.cl_statics with Not_found -> PMap.find field c.cl_fields).cf_meta
  569. | TClassDecl c ->
  570. PMap.exists field c.cl_statics || PMap.exists field c.cl_fields
  571. | _ ->
  572. false)
  573. with Not_found ->
  574. false
  575. ) in
  576. Hashtbl.add com.features f r;
  577. r
  578. let allow_package ctx s =
  579. try
  580. if (PMap.find s ctx.package_rules) = Forbidden then ctx.package_rules <- PMap.remove s ctx.package_rules
  581. with Not_found ->
  582. ()
  583. let abort msg p = raise (Abort (msg,p))
  584. let platform ctx p = ctx.platform = p
  585. let platform_name_macro com =
  586. if defined com Define.Macro then "macro" else platform_name com.platform
  587. let normalize_dir_separator path =
  588. if is_windows then String.map (fun c -> if c = '/' then '\\' else c) path
  589. else path
  590. let find_file ctx f =
  591. try
  592. match Hashtbl.find ctx.file_lookup_cache f with
  593. | None -> raise Exit
  594. | Some f -> f
  595. with Exit ->
  596. raise Not_found
  597. | Not_found ->
  598. let remove_extension file =
  599. try String.sub file 0 (String.rindex file '.')
  600. with Not_found -> file
  601. in
  602. let extension file =
  603. try
  604. let dot_pos = String.rindex file '.' in
  605. String.sub file dot_pos (String.length file - dot_pos)
  606. with Not_found -> file
  607. in
  608. let f_dir = Filename.dirname f
  609. and platform_ext = "." ^ (platform_name_macro ctx)
  610. and is_core_api = defined ctx Define.CoreApi in
  611. let rec loop had_empty = function
  612. | [] when had_empty -> raise Not_found
  613. | [] -> loop true [""]
  614. | p :: l ->
  615. let file = p ^ f in
  616. let dir = Filename.dirname file in
  617. if Hashtbl.mem ctx.readdir_cache (p,dir) then
  618. loop (had_empty || p = "") l
  619. else begin
  620. let found = ref "" in
  621. let dir_listing =
  622. try Some (Sys.readdir dir);
  623. with Sys_error _ -> None
  624. in
  625. Hashtbl.add ctx.readdir_cache (p,dir) dir_listing;
  626. let normalized_f = normalize_dir_separator f in
  627. Option.may
  628. (Array.iter (fun file_name ->
  629. let current_f = if f_dir = "." then file_name else f_dir ^ "/" ^ file_name in
  630. let pf,current_f =
  631. if is_core_api then false,current_f
  632. else begin
  633. let ext = extension current_f in
  634. let pf_ext = extension (remove_extension current_f) in
  635. if platform_ext = pf_ext then
  636. true,(remove_extension (remove_extension current_f)) ^ ext
  637. else
  638. false,current_f
  639. end
  640. in
  641. let is_cached = Hashtbl.mem ctx.file_lookup_cache current_f in
  642. if is_core_api || pf || not is_cached then begin
  643. let full_path = if dir = "." then file_name else dir ^ "/" ^ file_name in
  644. if is_cached then
  645. Hashtbl.remove ctx.file_lookup_cache current_f;
  646. Hashtbl.add ctx.file_lookup_cache current_f (Some full_path);
  647. if normalize_dir_separator current_f = normalized_f then
  648. found := full_path;
  649. end
  650. ))
  651. dir_listing;
  652. if !found <> "" then !found
  653. else loop (had_empty || p = "") l
  654. end
  655. in
  656. let r = (try Some (loop false ctx.class_path) with Not_found -> None) in
  657. Hashtbl.add ctx.file_lookup_cache f r;
  658. match r with
  659. | None -> raise Not_found
  660. | Some f -> f
  661. (* let find_file ctx f =
  662. let timer = Timer.timer ["find_file"] in
  663. Std.finally timer (find_file ctx) f *)
  664. let mem_size v =
  665. Objsize.size_with_headers (Objsize.objsize v [] [])
  666. let hash f =
  667. let h = ref 0 in
  668. for i = 0 to String.length f - 1 do
  669. h := !h * 223 + int_of_char (String.unsafe_get f i);
  670. done;
  671. if Sys.word_size = 64 then Int32.to_int (Int32.shift_right (Int32.shift_left (Int32.of_int !h) 1) 1) else !h
  672. let url_encode s add_char =
  673. let hex = "0123456789ABCDEF" in
  674. for i = 0 to String.length s - 1 do
  675. let c = String.unsafe_get s i in
  676. match c with
  677. | 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' | '-' | '.' ->
  678. add_char c
  679. | _ ->
  680. add_char '%';
  681. add_char (String.unsafe_get hex (int_of_char c lsr 4));
  682. add_char (String.unsafe_get hex (int_of_char c land 0xF));
  683. done
  684. let url_encode_s s =
  685. let b = Buffer.create 0 in
  686. url_encode s (Buffer.add_char b);
  687. Buffer.contents b
  688. (* UTF8 *)
  689. let to_utf8 str p =
  690. let u8 = try
  691. UTF8.validate str;
  692. str;
  693. with
  694. UTF8.Malformed_code ->
  695. (* ISO to utf8 *)
  696. let b = UTF8.Buf.create 0 in
  697. String.iter (fun c -> UTF8.Buf.add_char b (UCharExt.of_char c)) str;
  698. UTF8.Buf.contents b
  699. in
  700. let ccount = ref 0 in
  701. UTF8.iter (fun c ->
  702. let c = UCharExt.code c in
  703. if (c >= 0xD800 && c <= 0xDFFF) || c >= 0x110000 then abort "Invalid unicode char" p;
  704. incr ccount;
  705. if c > 0x10000 then incr ccount;
  706. ) u8;
  707. u8, !ccount
  708. let utf16_add buf c =
  709. let add c =
  710. Buffer.add_char buf (char_of_int (c land 0xFF));
  711. Buffer.add_char buf (char_of_int (c lsr 8));
  712. in
  713. if c >= 0 && c < 0x10000 then begin
  714. if c >= 0xD800 && c <= 0xDFFF then failwith ("Invalid unicode char " ^ string_of_int c);
  715. add c;
  716. end else if c < 0x110000 then begin
  717. let c = c - 0x10000 in
  718. add ((c asr 10) + 0xD800);
  719. add ((c land 1023) + 0xDC00);
  720. end else
  721. failwith ("Invalid unicode char " ^ string_of_int c)
  722. let utf8_to_utf16 str zt =
  723. let b = Buffer.create (String.length str * 2) in
  724. (try UTF8.iter (fun c -> utf16_add b (UCharExt.code c)) str with Invalid_argument _ | UCharExt.Out_of_range -> ()); (* if malformed *)
  725. if zt then utf16_add b 0;
  726. Buffer.contents b
  727. let utf16_to_utf8 str =
  728. let b = Buffer.create 0 in
  729. let add c = Buffer.add_char b (char_of_int (c land 0xFF)) in
  730. let get i = int_of_char (String.unsafe_get str i) in
  731. let rec loop i =
  732. if i >= String.length str then ()
  733. else begin
  734. let c = get i in
  735. if c < 0x80 then begin
  736. add c;
  737. loop (i + 2);
  738. end else if c < 0x800 then begin
  739. let c = c lor ((get (i + 1)) lsl 8) in
  740. add c;
  741. add (c lsr 8);
  742. loop (i + 2);
  743. end else
  744. assert false;
  745. end
  746. in
  747. loop 0;
  748. Buffer.contents b
  749. let add_diagnostics_message com s p kind sev =
  750. let di = com.shared.shared_display_information in
  751. di.diagnostics_messages <- (s,p,kind,sev) :: di.diagnostics_messages
  752. open Printer
  753. let dump_context com = s_record_fields "" [
  754. "version",string_of_int com.version;
  755. "args",s_list ", " (fun s -> s) com.args;
  756. "debug",string_of_bool com.debug;
  757. "platform",platform_name com.platform;
  758. "std_path",s_list ", " (fun s -> s) com.std_path;
  759. "class_path",s_list ", " (fun s -> s) com.class_path;
  760. "defines",s_pmap (fun s -> s) (fun s -> s) com.defines.values;
  761. "defines_signature",s_opt (fun s -> Digest.to_hex s) com.defines.defines_signature;
  762. ]
  763. let dump_path com =
  764. Define.defined_value_safe ~default:"dump" com.defines Define.DumpPath
  765. let adapt_defines_to_macro_context defines =
  766. let values = ref defines.values in
  767. List.iter (fun p -> values := PMap.remove (Globals.platform_name p) !values) Globals.platforms;
  768. let to_remove = List.map (fun d -> fst (Define.infos d)) [Define.NoTraces] in
  769. let to_remove = to_remove @ List.map (fun (_,d) -> "flash" ^ d) flash_versions in
  770. values := PMap.foldi (fun k v acc -> if List.mem k to_remove then acc else PMap.add k v acc) !values PMap.empty;
  771. values := PMap.add "macro" "1" !values;
  772. values := PMap.add (platform_name !Globals.macro_platform) "1" !values;
  773. {values = !values; defines_signature = None }
  774. let is_legacy_completion com = match com.json_out with
  775. | None -> true
  776. | Some api -> !ServerConfig.legacy_completion