evalMain.ml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  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 Globals
  17. open Ast
  18. open Type
  19. open Common
  20. open EvalValue
  21. open EvalContext
  22. open EvalPrototype
  23. open EvalExceptions
  24. open EvalJit
  25. open EvalJitContext
  26. open EvalPrinting
  27. open EvalMisc
  28. open EvalHash
  29. open EvalEncode
  30. open EvalField
  31. open MacroApi
  32. (* Create *)
  33. let sid = ref (-1)
  34. let stdlib = ref None
  35. let debug = ref None
  36. let create com api is_macro =
  37. let t = Timer.timer [(if is_macro then "macro" else "interp");"create"] in
  38. incr sid;
  39. let builtins = match !stdlib with
  40. | None ->
  41. let builtins = {
  42. static_builtins = IntMap.empty;
  43. instance_builtins = IntMap.empty;
  44. constructor_builtins = Hashtbl.create 0;
  45. empty_constructor_builtins = Hashtbl.create 0;
  46. } in
  47. EvalStdLib.init_standard_library builtins;
  48. stdlib := Some builtins;
  49. builtins
  50. | Some (builtins) ->
  51. builtins
  52. in
  53. let debug = match !debug with
  54. | None ->
  55. let support_debugger = Common.defined com Define.EvalDebugger in
  56. let socket =
  57. try
  58. if not support_debugger then raise Exit;
  59. let fail msg =
  60. print_endline msg;
  61. raise Exit
  62. in
  63. let s = Common.defined_value com Define.EvalDebugger in
  64. let host,port = try ExtString.String.split s ":" with _ -> fail "Invalid host format, expected host:port" in
  65. let port = try int_of_string port with _ -> fail "Invalid port, expected int" in
  66. Some (try
  67. let socket = Socket.create host port in
  68. {
  69. socket = socket;
  70. connection = EvalDebugSocket.make_connection socket;
  71. };
  72. with exc ->
  73. fail (Printexc.to_string exc)
  74. )
  75. with _ ->
  76. None
  77. in
  78. let debug' = {
  79. breakpoints = Hashtbl.create 0;
  80. function_breakpoints = Hashtbl.create 0;
  81. support_debugger = support_debugger;
  82. debug_state = DbgStart;
  83. breakpoint = EvalDebugMisc.make_breakpoint 0 0 BPDisabled BPAny None;
  84. caught_types = Hashtbl.create 0;
  85. environment_offset_delta = 0;
  86. debug_socket = socket;
  87. exception_mode = CatchUncaught;
  88. caught_exception = vnull;
  89. } in
  90. debug := Some debug';
  91. debug'
  92. | Some debug ->
  93. debug
  94. in
  95. let detail_times = Common.defined com Define.EvalTimes in
  96. let evals = DynArray.create () in
  97. let eval = {
  98. environments = DynArray.make 32;
  99. environment_offset = 0;
  100. } in
  101. DynArray.add evals eval;
  102. let rec ctx = {
  103. ctx_id = !sid;
  104. is_macro = is_macro;
  105. debug = debug;
  106. detail_times = detail_times;
  107. curapi = api;
  108. builtins = builtins;
  109. type_cache = IntMap.empty;
  110. overrides = Hashtbl.create 0;
  111. had_error = false;
  112. (* prototypes *)
  113. string_prototype = fake_proto key_String;
  114. array_prototype = fake_proto key_Array;
  115. vector_prototype = fake_proto key_eval_Vector;
  116. static_prototypes = IntMap.empty;
  117. instance_prototypes = IntMap.empty;
  118. constructors = IntMap.empty;
  119. get_object_prototype = get_object_prototype;
  120. static_inits = IntMap.empty;
  121. (* eval *)
  122. toplevel = vobject {
  123. ofields = [||];
  124. oproto = fake_proto key_eval_toplevel;
  125. };
  126. eval = eval;
  127. evals = evals;
  128. exception_stack = [];
  129. } in
  130. t();
  131. ctx
  132. (* API for macroContext.ml *)
  133. let call_path ctx path f vl api =
  134. if ctx.had_error then
  135. None
  136. else begin
  137. let old = ctx.curapi in
  138. ctx.curapi <- api;
  139. let path = match List.rev path with
  140. | [] -> assert false
  141. | name :: path -> List.rev path,name
  142. in
  143. catch_exceptions ctx ~final:(fun () -> ctx.curapi <- old) (fun () ->
  144. let vtype = get_static_prototype_as_value ctx (path_hash path) api.pos in
  145. let vfield = field vtype (hash f) in
  146. call_value_on vtype vfield vl
  147. ) api.pos
  148. end
  149. let value_signature v =
  150. let buf = Buffer.create 0 in
  151. let add s = Buffer.add_string buf s in
  152. let addc c = Buffer.add_char buf c in
  153. let scache = Hashtbl.create 0 in
  154. let adds s =
  155. try
  156. let i = Hashtbl.find scache s in
  157. addc 'R';
  158. add (string_of_int i)
  159. with Not_found ->
  160. Hashtbl.add scache s (Hashtbl.length scache);
  161. addc 'y';
  162. let s = EvalStdLib.StdStringTools.url_encode s in
  163. add (string_of_int (String.length s));
  164. addc ':';
  165. add s
  166. in
  167. let cache = ValueHashtbl.create 0 in
  168. let cache_length = ref 0 in
  169. let cache v f =
  170. try
  171. let i = ValueHashtbl.find cache v in
  172. addc 'r';
  173. add (string_of_int i)
  174. with Not_found ->
  175. let i = !cache_length in
  176. ValueHashtbl.add cache v i;
  177. incr cache_length;
  178. f()
  179. in
  180. let function_count = ref 0 in
  181. let rec loop v = match v with
  182. | VNull -> addc 'n'
  183. | VTrue -> addc 't'
  184. | VFalse -> addc 'f'
  185. | VInt32 i when i = Int32.zero -> addc 'z'
  186. | VInt32 i ->
  187. addc 'i';
  188. add (Int32.to_string i)
  189. | VFloat f ->
  190. if f = neg_infinity then addc 'm'
  191. else if f = infinity then addc 'p'
  192. else if f <> f then addc 'k'
  193. else begin
  194. addc 'd';
  195. add (string_of_float f)
  196. end
  197. | VEnumValue ve ->
  198. cache v (fun () ->
  199. addc 'j';
  200. adds (rev_hash ve.epath);
  201. addc ':';
  202. add (string_of_int ve.eindex);
  203. addc ':';
  204. add (string_of_int (Array.length ve.eargs));
  205. Array.iter loop ve.eargs;
  206. )
  207. | VObject o ->
  208. cache v (fun () ->
  209. addc 'o';
  210. let fields = object_fields o in
  211. loop_fields fields;
  212. addc 'g'
  213. )
  214. | VInstance {ikind = IDate f} ->
  215. cache v (fun () ->
  216. addc 'v';
  217. add ((s_date f).sstring)
  218. )
  219. | VInstance {ikind = IStringMap map} ->
  220. cache v (fun() ->
  221. addc 'b';
  222. StringHashtbl.iter (fun s (_,value) ->
  223. adds s;
  224. loop value
  225. ) map;
  226. addc 'h'
  227. )
  228. | VInstance {ikind = IIntMap map} ->
  229. cache v (fun () ->
  230. addc 'q';
  231. IntHashtbl.iter (fun i value ->
  232. addc ':';
  233. add (string_of_int i);
  234. loop value
  235. ) map;
  236. addc 'h'
  237. )
  238. | VInstance {ikind = IObjectMap map} ->
  239. cache v (fun() ->
  240. addc 'M';
  241. ValueHashtbl.iter (fun key value ->
  242. loop key;
  243. loop value
  244. ) (Obj.magic map);
  245. addc 'h'
  246. )
  247. | VInstance {ikind = IBytes b} ->
  248. cache v (fun () ->
  249. addc 's';
  250. let base64_chars = [|
  251. 'A';'B';'C';'D';'E';'F';'G';'H';'I';'J';'K';'L';'M';'N';'O';'P';
  252. 'Q';'R';'S';'T';'U';'V';'W';'X';'Y';'Z';'a';'b';'c';'d';'e';'f';
  253. 'g';'h';'i';'j';'k';'l';'m';'n';'o';'p';'q';'r';'s';'t';'u';'v';
  254. 'w';'x';'y';'z';'0';'1';'2';'3';'4';'5';'6';'7';'8';'9';'%';':'
  255. |] in
  256. let s = Bytes.unsafe_to_string (Base64.str_encode ~tbl:(base64_chars) (Bytes.unsafe_to_string b)) in
  257. add (string_of_int (String.length s));
  258. addc ':';
  259. add s
  260. )
  261. | VInstance i ->
  262. cache v (fun () ->
  263. addc 'c';
  264. adds (rev_hash i.iproto.ppath);
  265. let fields = instance_fields i in
  266. loop_fields fields;
  267. addc 'g';
  268. )
  269. | VString s ->
  270. adds s.sstring
  271. | VArray {avalues = a} | VVector a ->
  272. cache v (fun () ->
  273. addc 'a';
  274. let nulls null_count =
  275. if null_count > 0 then begin
  276. addc 'u';
  277. add (string_of_int null_count);
  278. end
  279. in
  280. let rec loop2 null_count vl = match vl with
  281. | VNull :: vl -> loop2 (null_count + 1) vl
  282. | v :: vl ->
  283. nulls null_count;
  284. loop v;
  285. loop2 0 vl
  286. | [] ->
  287. nulls null_count
  288. in
  289. loop2 0 (Array.to_list a);
  290. addc 'h'
  291. )
  292. | VPrototype {pkind = PClass _; ppath = path} ->
  293. addc 'A';
  294. adds (rev_hash path)
  295. | VPrototype {pkind = PEnum _; ppath = path} ->
  296. addc 'B';
  297. adds (rev_hash path)
  298. | VPrototype _ ->
  299. assert false
  300. | VFunction _ | VFieldClosure _ ->
  301. (* Custom format: enumerate functions as F0, F1 etc. *)
  302. cache v (fun () ->
  303. addc 'F';
  304. add (string_of_int !function_count);
  305. incr function_count
  306. )
  307. | VLazy f ->
  308. loop (!f())
  309. and loop_fields fields =
  310. List.iter (fun (name,v) ->
  311. adds (rev_hash name);
  312. loop v;
  313. ) fields
  314. in
  315. loop v;
  316. Digest.string (Buffer.contents buf)
  317. let prepare_callback v n =
  318. match v with
  319. | VFunction _ | VFieldClosure _ ->
  320. let ctx = get_ctx() in
  321. (fun args -> match catch_exceptions ctx (fun() -> call_value v args) null_pos with
  322. | Some v -> v
  323. | None -> vnull)
  324. | _ ->
  325. raise Invalid_expr
  326. let init ctx = ()
  327. let setup get_api =
  328. let api = get_api (fun() -> (get_ctx()).curapi.get_com()) (fun() -> (get_ctx()).curapi) in
  329. List.iter (fun (n,v) -> match v with
  330. | VFunction(f,b) ->
  331. let f vl = try
  332. f vl
  333. with
  334. | Sys_error msg | Failure msg ->
  335. exc_string msg
  336. | MacroApi.Invalid_expr ->
  337. exc_string "Invalid expression"
  338. in
  339. let v = VFunction (f,b) in
  340. Hashtbl.replace EvalStdLib.macro_lib n v
  341. | _ -> assert false
  342. ) api;
  343. Globals.macro_platform := Globals.Eval
  344. let do_reuse ctx api =
  345. ctx.curapi <- api;
  346. IntMap.iter (fun _ (proto,delays) -> List.iter (fun f -> f proto) delays) ctx.static_inits
  347. let set_error ctx b =
  348. (* TODO: Have to reset this somewhere if running compilation server. But where... *)
  349. ctx.had_error <- b
  350. let add_types ctx types ready =
  351. ignore(catch_exceptions ctx (fun () -> ignore(add_types ctx types ready)) null_pos)
  352. let compiler_error msg pos =
  353. let vi = encode_instance key_haxe_macro_Error in
  354. match vi with
  355. | VInstance i ->
  356. set_instance_field i key_message (EvalString.create_unknown msg);
  357. set_instance_field i key_pos (encode_pos pos);
  358. exc vi
  359. | _ ->
  360. assert false
  361. let rec value_to_expr v p =
  362. let path i =
  363. let mt = IntMap.find i (get_ctx()).type_cache in
  364. let make_path t =
  365. let rec loop = function
  366. | [] -> assert false
  367. | [name] -> (EConst (Ident name),p)
  368. | name :: l -> (EField (loop l,name),p)
  369. in
  370. let t = t_infos t in
  371. loop (List.rev (if t.mt_module.m_path = t.mt_path then fst t.mt_path @ [snd t.mt_path] else fst t.mt_module.m_path @ [snd t.mt_module.m_path;snd t.mt_path]))
  372. in
  373. make_path mt
  374. in
  375. match vresolve v with
  376. | VNull -> (EConst (Ident "null"),p)
  377. | VTrue -> (EConst (Ident "true"),p)
  378. | VFalse -> (EConst (Ident "false"),p)
  379. | VInt32 i -> (EConst (Int (Int32.to_string i)),p)
  380. | VFloat f -> haxe_float f p
  381. | VString s -> (EConst (String s.sstring),p)
  382. | VArray va -> (EArrayDecl (List.map (fun v -> value_to_expr v p) (EvalArray.to_list va)),p)
  383. | VObject o -> (EObjectDecl (List.map (fun (k,v) ->
  384. let n = rev_hash k in
  385. ((n,p,(if Lexer.is_valid_identifier n then NoQuotes else DoubleQuotes)),(value_to_expr v p))
  386. ) (object_fields o)),p)
  387. | VEnumValue e ->
  388. let epath =
  389. let proto = get_static_prototype_raise (get_ctx()) e.epath in
  390. let expr = path e.epath in
  391. let name = match proto.pkind with
  392. | PEnum names -> fst (List.nth names e.eindex)
  393. | _ -> assert false
  394. in
  395. (EField (expr, name), p)
  396. in
  397. begin
  398. match e.eargs with
  399. | [||] -> epath
  400. | _ ->
  401. let args = List.map (fun v -> value_to_expr v p) (Array.to_list e.eargs) in
  402. (ECall (epath, args), p)
  403. end
  404. | _ -> exc_string ("Cannot convert " ^ (value_string v) ^ " to expr")
  405. let encode_obj = encode_obj_s
  406. let field v f = field v (EvalHash.hash f)
  407. let value_string = value_string
  408. let exc_string = exc_string
  409. let eval_expr ctx e = eval_expr ctx key_questionmark key_questionmark e
  410. let handle_decoding_error f v t =
  411. let line = ref 1 in
  412. let errors = ref [] in
  413. let error msg v =
  414. errors := (msg,!line) :: !errors;
  415. f (Printf.sprintf "%s <- %s" (value_string v) msg)
  416. in
  417. let rec loop tabs t v =
  418. match t with
  419. | TAnon an ->
  420. f "{";
  421. PMap.iter (fun _ cf ->
  422. incr line;
  423. f (Printf.sprintf "\n%s%s: " (tabs ^ "\t") cf.cf_name);
  424. try
  425. let vf = field_raise v (EvalHash.hash cf.cf_name) in
  426. begin match vf with
  427. | VNull when not (is_explicit_null cf.cf_type) -> error "expected value" vf
  428. | _ -> loop (tabs ^ "\t") cf.cf_type vf
  429. end
  430. with Not_found ->
  431. if not (is_explicit_null cf.cf_type) then error "expected value" VNull
  432. else f "null"
  433. ) an.a_fields;
  434. incr line;
  435. f (Printf.sprintf "\n%s}" tabs)
  436. | TInst({cl_path=[],"Array"},[t1]) ->
  437. begin match v with
  438. | VArray va ->
  439. f "[";
  440. let _ = List.fold_left (fun first v ->
  441. if not first then f ", ";
  442. loop tabs t1 v;
  443. false
  444. ) true (EvalArray.to_list va) in
  445. f "]"
  446. | _ -> error "expected Array" v
  447. end
  448. | TInst({cl_path=[],"String"},_) ->
  449. begin match v with
  450. | VString _ -> f (value_string v)
  451. | _ -> error "expected String" v
  452. end
  453. | TAbstract({a_path=[],"Null"},[t1]) ->
  454. if v = VNull then f "null" else loop tabs t1 v
  455. | TAbstract({a_path=[],"Bool"},_) ->
  456. begin match v with
  457. | VTrue -> f "true"
  458. | VFalse -> f "false"
  459. | _ -> error "expected Bool" v
  460. end
  461. | TAbstract({a_path=[],("Int" | "Float")},_) ->
  462. begin match v with
  463. | VInt32 _ | VFloat _ -> f (value_string v)
  464. | _ -> error "expected Bool" v
  465. end
  466. | TType(t,tl) ->
  467. loop tabs (apply_params t.t_params tl t.t_type) v
  468. | TAbstract({a_path=["haxe";"macro"],"Position"},_) ->
  469. begin match v with
  470. | VInstance {ikind=IPos _} -> f "#pos"
  471. | _ -> error "expected Position" v
  472. end
  473. | TEnum(en,_) ->
  474. begin match v with
  475. | VEnumValue ev ->
  476. let ef = PMap.find (List.nth en.e_names ev.eindex) en.e_constrs in
  477. f ef.ef_name;
  478. let rec loop2 first tl vl = match tl,vl with
  479. | _,[] -> ()
  480. | [],_ -> ()
  481. | (_,_,t) :: tl,v :: vl ->
  482. if not first then f ", ";
  483. loop tabs t v;
  484. loop2 false tl vl
  485. in
  486. begin match follow ef.ef_type,Array.to_list ev.eargs with
  487. | _,[] ->
  488. ()
  489. | TFun(tl,_),vl ->
  490. f "(";
  491. loop2 true tl vl;
  492. f ")"
  493. | _ -> ()
  494. end
  495. | _ -> error "expected enum value" v
  496. end
  497. | TInst _ | TAbstract _ | TFun _ ->
  498. (* TODO: might need some more of these, not sure *)
  499. assert false
  500. | TMono r ->
  501. begin match !r with
  502. | None -> ()
  503. | Some t -> loop tabs t v
  504. end
  505. | TLazy r ->
  506. loop tabs (lazy_type r) v
  507. | TDynamic _ ->
  508. ()
  509. in
  510. loop "" t v;
  511. !errors