macroContext.ml 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. (*
  2. The Haxe Compiler
  3. Copyright (C) 2005-2017 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 Common.DisplayMode
  18. open Common
  19. open Type
  20. open Typecore
  21. open Error
  22. open Globals
  23. module InterpImpl = Interp (* Hlmacro *)
  24. module Interp = struct
  25. module BuiltApi = MacroApi.MacroApiImpl(InterpImpl)
  26. include InterpImpl
  27. include BuiltApi
  28. end
  29. let macro_enable_cache = ref false
  30. let macro_interp_cache = ref None
  31. let macro_interp_on_reuse = ref []
  32. let macro_interp_reused = ref false
  33. let delayed_macro_result = ref ((fun() -> assert false) : unit -> unit -> Interp.value)
  34. let unify_call_args_ref = ref (fun _ _ _ _ _ _ _-> assert false)
  35. let unify_call_args a b c d e f g : (texpr list * t) = !unify_call_args_ref a b c d e f g
  36. let get_next_stored_typed_expr_id =
  37. let uid = ref 0 in
  38. (fun() -> incr uid; !uid)
  39. let get_stored_typed_expr com id =
  40. let e = PMap.find id com.stored_typed_exprs in
  41. Texpr.duplicate_tvars e
  42. let get_type_patch ctx t sub =
  43. let new_patch() =
  44. { tp_type = None; tp_remove = false; tp_meta = [] }
  45. in
  46. let path = Ast.parse_path t in
  47. let h, tp = (try
  48. Hashtbl.find ctx.g.type_patches path
  49. with Not_found ->
  50. let h = Hashtbl.create 0 in
  51. let tp = new_patch() in
  52. Hashtbl.add ctx.g.type_patches path (h,tp);
  53. h, tp
  54. ) in
  55. match sub with
  56. | None -> tp
  57. | Some k ->
  58. try
  59. Hashtbl.find h k
  60. with Not_found ->
  61. let tp = new_patch() in
  62. Hashtbl.add h k tp;
  63. tp
  64. let macro_timer ctx l =
  65. Common.timer (if Common.defined ctx.com Define.MacroTimes then ("macro" :: l) else ["macro"])
  66. let typing_timer ctx need_type f =
  67. let t = Common.timer ["typing"] in
  68. let old = ctx.com.error and oldp = ctx.pass in
  69. (*
  70. disable resumable errors... unless we are in display mode (we want to reach point of completion)
  71. *)
  72. (*if ctx.com.display = DMNone then ctx.com.error <- (fun e p -> raise (Error(Custom e,p)));*) (* TODO: review this... *)
  73. ctx.com.error <- (fun e p -> raise (Error(Custom e,p)));
  74. if need_type && ctx.pass < PTypeField then ctx.pass <- PTypeField;
  75. let exit() =
  76. t();
  77. ctx.com.error <- old;
  78. ctx.pass <- oldp;
  79. in
  80. try
  81. let r = f() in
  82. exit();
  83. r
  84. with Error (ekind,p) ->
  85. exit();
  86. Interp.compiler_error (error_msg ekind) p
  87. | WithTypeError (l,p) ->
  88. exit();
  89. Interp.compiler_error (error_msg l) p
  90. | e ->
  91. exit();
  92. raise e
  93. let load_macro_ref : (typer -> bool -> path -> string -> pos -> (typer * ((string * bool * t) list * t * tclass * Type.tclass_field) * (Interp.value list -> Interp.value option))) ref = ref (fun _ _ _ _ -> assert false)
  94. let make_macro_api ctx p =
  95. let parse_expr_string s p inl =
  96. typing_timer ctx false (fun() -> try Parser.parse_expr_string ctx.com s p error inl with Exit -> raise MacroApi.Invalid_expr)
  97. in
  98. {
  99. MacroApi.pos = p;
  100. MacroApi.get_com = (fun() -> ctx.com);
  101. MacroApi.get_type = (fun s ->
  102. typing_timer ctx false (fun() ->
  103. let path = parse_path s in
  104. let tp = match List.rev (fst path) with
  105. | s :: sl when String.length s > 0 && (match s.[0] with 'A'..'Z' -> true | _ -> false) ->
  106. { tpackage = List.rev sl; tname = s; tparams = []; tsub = Some (snd path) }
  107. | _ ->
  108. { tpackage = fst path; tname = snd path; tparams = []; tsub = None }
  109. in
  110. try
  111. let m = Some (Typeload.load_instance ctx (tp,null_pos) true p) in
  112. m
  113. with Error (Module_not_found _,p2) when p == p2 ->
  114. None
  115. )
  116. );
  117. MacroApi.resolve_type = (fun t p ->
  118. typing_timer ctx false (fun() -> Typeload.load_complex_type ctx false p (t,null_pos))
  119. );
  120. MacroApi.get_module = (fun s ->
  121. typing_timer ctx false (fun() ->
  122. let path = parse_path s in
  123. let m = List.map type_of_module_type (Typeload.load_module ctx path p).m_types in
  124. m
  125. )
  126. );
  127. MacroApi.after_typing = (fun f ->
  128. Common.add_typing_filter ctx.com (fun tl ->
  129. let t = macro_timer ctx ["afterTyping"] in
  130. f tl;
  131. t()
  132. )
  133. );
  134. MacroApi.on_generate = (fun f ->
  135. Common.add_filter ctx.com (fun() ->
  136. let t = macro_timer ctx ["onGenerate"] in
  137. f (List.map type_of_module_type ctx.com.types);
  138. t()
  139. )
  140. );
  141. MacroApi.after_generate = (fun f ->
  142. Common.add_final_filter ctx.com (fun() ->
  143. let t = macro_timer ctx ["afterGenerate"] in
  144. f();
  145. t()
  146. )
  147. );
  148. MacroApi.on_type_not_found = (fun f ->
  149. ctx.com.load_extern_type <- ctx.com.load_extern_type @ [fun path p ->
  150. let td = f (s_type_path path) in
  151. if td = Interp.vnull then
  152. None
  153. else
  154. let (pack,name),tdef,p = Interp.decode_type_def td in
  155. Some (name,(pack,[tdef,p]))
  156. ];
  157. );
  158. MacroApi.parse_string = parse_expr_string;
  159. MacroApi.type_expr = (fun e ->
  160. typing_timer ctx true (fun() -> type_expr ctx e Value)
  161. );
  162. MacroApi.type_macro_expr = (fun e ->
  163. let e = typing_timer ctx true (fun() -> type_expr ctx e Value) in
  164. let rec loop e = match e.eexpr with
  165. | TField(_,FStatic(c,({cf_kind = Method _} as cf))) -> ignore(!load_macro_ref ctx false c.cl_path cf.cf_name e.epos)
  166. | _ -> Type.iter loop e
  167. in
  168. loop e;
  169. e
  170. );
  171. MacroApi.store_typed_expr = (fun te ->
  172. let p = te.epos in
  173. let id = get_next_stored_typed_expr_id() in
  174. ctx.com.stored_typed_exprs <- PMap.add id te ctx.com.stored_typed_exprs;
  175. let eid = (EConst (Int (string_of_int id))), p in
  176. (EMeta ((Meta.StoredTypedExpr,[],p), eid)), p
  177. );
  178. MacroApi.allow_package = (fun v -> Common.allow_package ctx.com v);
  179. MacroApi.type_patch = (fun t f s v ->
  180. typing_timer ctx false (fun() ->
  181. let v = (match v with None -> None | Some s ->
  182. match Parser.parse_string ctx.com ("typedef T = " ^ s) null_pos error false with
  183. | _,[ETypedef { d_data = ct },_] -> Some ct
  184. | _ -> assert false
  185. ) in
  186. let tp = get_type_patch ctx t (Some (f,s)) in
  187. match v with
  188. | None -> tp.tp_remove <- true
  189. | Some _ -> tp.tp_type <- Option.map fst v
  190. );
  191. );
  192. MacroApi.meta_patch = (fun m t f s ->
  193. let m = (match Parser.parse_string ctx.com (m ^ " typedef T = T") null_pos error false with
  194. | _,[ETypedef t,_] -> t.d_meta
  195. | _ -> assert false
  196. ) in
  197. let tp = get_type_patch ctx t (match f with None -> None | Some f -> Some (f,s)) in
  198. tp.tp_meta <- tp.tp_meta @ m;
  199. );
  200. MacroApi.set_js_generator = (fun gen ->
  201. let js_ctx = Genjs.alloc_ctx ctx.com in
  202. ctx.com.js_gen <- Some (fun() ->
  203. let t = macro_timer ctx ["jsGenerator"] in
  204. gen js_ctx;
  205. t()
  206. );
  207. );
  208. MacroApi.get_local_type = (fun() ->
  209. match ctx.g.get_build_infos() with
  210. | Some (mt,tl,_) ->
  211. Some (match mt with
  212. | TClassDecl c -> TInst (c,tl)
  213. | TEnumDecl e -> TEnum (e,tl)
  214. | TTypeDecl t -> TType (t,tl)
  215. | TAbstractDecl a -> TAbstract(a,tl))
  216. | None ->
  217. if ctx.curclass == null_class then
  218. None
  219. else
  220. Some (TInst (ctx.curclass,[]))
  221. );
  222. MacroApi.get_expected_type = (fun() ->
  223. match ctx.with_type_stack with
  224. | (WithType t) :: _ -> Some t
  225. | _ -> None
  226. );
  227. MacroApi.get_call_arguments = (fun() ->
  228. match ctx.call_argument_stack with
  229. | [] -> None
  230. | el :: _ -> Some el
  231. );
  232. MacroApi.get_local_method = (fun() ->
  233. ctx.curfield.cf_name;
  234. );
  235. MacroApi.get_local_using = (fun() ->
  236. List.map fst ctx.m.module_using;
  237. );
  238. MacroApi.get_local_imports = (fun() ->
  239. ctx.m.module_imports;
  240. );
  241. MacroApi.get_local_vars = (fun () ->
  242. ctx.locals;
  243. );
  244. MacroApi.get_build_fields = (fun() ->
  245. match ctx.g.get_build_infos() with
  246. | None -> Interp.vnull
  247. | Some (_,_,fields) -> Interp.encode_array (List.map Interp.encode_field fields)
  248. );
  249. MacroApi.get_pattern_locals = (fun e t ->
  250. !get_pattern_locals_ref ctx e t
  251. );
  252. MacroApi.define_type = (fun v mdep ->
  253. let m, tdef, pos = (try Interp.decode_type_def v with MacroApi.Invalid_expr -> Interp.exc_string "Invalid type definition") in
  254. let add is_macro ctx =
  255. let mdep = Option.map_default (fun s -> Typeload.load_module ctx (parse_path s) pos) ctx.m.curmod mdep in
  256. let mnew = Typeload.type_module ctx m mdep.m_extra.m_file [tdef,pos] pos in
  257. mnew.m_extra.m_kind <- if is_macro then MMacro else MFake;
  258. add_dependency mnew mdep;
  259. in
  260. add false ctx;
  261. (* if we are adding a class which has a macro field, we also have to add it to the macro context (issue #1497) *)
  262. if not ctx.in_macro then match tdef,ctx.g.macros with
  263. | EClass c,Some (_,mctx) when List.exists (fun cff -> (Meta.has Meta.Macro cff.cff_meta || List.mem AMacro cff.cff_access)) c.d_data ->
  264. add true mctx
  265. | _ ->
  266. ()
  267. );
  268. MacroApi.define_module = (fun m types imports usings ->
  269. let types = List.map (fun v ->
  270. let _, tdef, pos = (try Interp.decode_type_def v with MacroApi.Invalid_expr -> Interp.exc_string "Invalid type definition") in
  271. tdef, pos
  272. ) types in
  273. let pos = (match types with [] -> null_pos | (_,p) :: _ -> p) in
  274. let imports = List.map (fun (il,ik) -> EImport(il,ik),pos) imports in
  275. let usings = List.map (fun tp ->
  276. let sl = tp.tpackage @ [tp.tname] @ (match tp.tsub with None -> [] | Some s -> [s]) in
  277. EUsing (List.map (fun s -> s,null_pos) sl),pos
  278. ) usings in
  279. let types = imports @ usings @ types in
  280. let mpath = Ast.parse_path m in
  281. begin try
  282. let m = Hashtbl.find ctx.g.modules mpath in
  283. ignore(Typeload.type_types_into_module ctx m types pos)
  284. with Not_found ->
  285. let mnew = Typeload.type_module ctx mpath ctx.m.curmod.m_extra.m_file types pos in
  286. mnew.m_extra.m_kind <- MFake;
  287. add_dependency mnew ctx.m.curmod;
  288. end
  289. );
  290. MacroApi.module_dependency = (fun mpath file ismacro ->
  291. let m = typing_timer ctx false (fun() -> Typeload.load_module ctx (parse_path mpath) p) in
  292. if ismacro then
  293. m.m_extra.m_macro_calls <- file :: List.filter ((<>) file) m.m_extra.m_macro_calls
  294. else
  295. add_dependency m (create_fake_module ctx file);
  296. );
  297. MacroApi.current_module = (fun() ->
  298. ctx.m.curmod
  299. );
  300. MacroApi.current_macro_module = (fun () -> assert false);
  301. MacroApi.delayed_macro = (fun i ->
  302. let mctx = (match ctx.g.macros with None -> assert false | Some (_,mctx) -> mctx) in
  303. let f = (try DynArray.get mctx.g.delayed_macros i with _ -> failwith "Delayed macro retrieve failure") in
  304. f();
  305. let ret = !delayed_macro_result in
  306. delayed_macro_result := (fun() -> assert false);
  307. ret
  308. );
  309. MacroApi.use_cache = (fun() ->
  310. !macro_enable_cache
  311. );
  312. MacroApi.format_string = (fun s p ->
  313. ctx.g.do_format_string ctx s p
  314. );
  315. MacroApi.cast_or_unify = (fun t e p ->
  316. AbstractCast.cast_or_unify_raise ctx t e p
  317. );
  318. MacroApi.add_global_metadata = (fun s1 s2 config ->
  319. let meta = (match Parser.parse_string ctx.com (s2 ^ " typedef T = T") null_pos error false with
  320. | _,[ETypedef t,_] -> t.d_meta
  321. | _ -> assert false
  322. ) in
  323. List.iter (fun m ->
  324. ctx.g.global_metadata <- (ExtString.String.nsplit s1 ".",m,config) :: ctx.g.global_metadata;
  325. ) meta;
  326. );
  327. MacroApi.add_module_check_policy = (fun sl il b i ->
  328. let add ctx =
  329. ctx.g.module_check_policies <- (List.fold_left (fun acc s -> (ExtString.String.nsplit s ".",List.map Obj.magic il,b) :: acc) ctx.g.module_check_policies sl);
  330. Hashtbl.iter (fun _ m -> m.m_extra.m_check_policy <- Typeload.get_policy ctx m.m_path) ctx.g.modules;
  331. in
  332. let add_macro ctx = match ctx.g.macros with
  333. | None -> ()
  334. | Some(_,mctx) -> add mctx;
  335. in
  336. match Obj.magic i with
  337. | CompilationServer.NormalContext -> add ctx
  338. | CompilationServer.MacroContext -> add_macro ctx
  339. | CompilationServer.NormalAndMacroContext -> add ctx; add_macro ctx;
  340. );
  341. MacroApi.on_reuse = (fun f ->
  342. macro_interp_on_reuse := f :: !macro_interp_on_reuse
  343. );
  344. }
  345. let rec init_macro_interp ctx mctx mint =
  346. let p = null_pos in
  347. ignore(Typeload.load_module mctx (["haxe";"macro"],"Expr") p);
  348. ignore(Typeload.load_module mctx (["haxe";"macro"],"Type") p);
  349. flush_macro_context mint ctx;
  350. Interp.init mint;
  351. if !macro_enable_cache && not (Common.defined mctx.com Define.NoMacroCache) then begin
  352. macro_interp_cache := Some mint;
  353. macro_interp_on_reuse := [];
  354. macro_interp_reused := true;
  355. end
  356. and flush_macro_context mint ctx =
  357. let t = macro_timer ctx ["flush"] in
  358. let mctx = (match ctx.g.macros with None -> assert false | Some (_,mctx) -> mctx) in
  359. ctx.g.do_finalize mctx;
  360. let _, types, modules = ctx.g.do_generate mctx in
  361. mctx.com.types <- types;
  362. mctx.com.Common.modules <- modules;
  363. let check_reuse() =
  364. if !macro_interp_reused then
  365. true
  366. else if not (List.for_all (fun f -> f()) !macro_interp_on_reuse) then
  367. false
  368. else begin
  369. macro_interp_reused := true;
  370. true;
  371. end
  372. in
  373. (* if one of the type we are using has been modified, we need to create a new macro context from scratch *)
  374. let mint = if not (Interp.can_reuse mint types && check_reuse()) then begin
  375. let com2 = mctx.com in
  376. let mint = Interp.create com2 (make_macro_api ctx Globals.null_pos) true in
  377. let macro = ((fun() -> Interp.select mint), mctx) in
  378. ctx.g.macros <- Some macro;
  379. mctx.g.macros <- Some macro;
  380. init_macro_interp ctx mctx mint;
  381. mint
  382. end else mint in
  383. (* we should maybe ensure that all filters in Main are applied. Not urgent atm *)
  384. let expr_filters = [Filters.VarLazifier.apply mctx.com;AbstractCast.handle_abstract_casts mctx; CapturedVars.captured_vars mctx.com; Filters.rename_local_vars mctx] in
  385. (*
  386. some filters here might cause side effects that would break compilation server.
  387. let's save the minimal amount of information we need
  388. *)
  389. let minimal_restore t =
  390. match t with
  391. | TClassDecl c ->
  392. let meta = c.cl_meta in
  393. let path = c.cl_path in
  394. c.cl_restore <- (fun() -> c.cl_meta <- meta; c.cl_path <- path);
  395. | _ ->
  396. ()
  397. in
  398. let type_filters = [
  399. Filters.add_field_inits mctx;
  400. minimal_restore;
  401. Filters.apply_native_paths mctx
  402. ] in
  403. let ready = fun t ->
  404. Filters.apply_filters_once mctx expr_filters t;
  405. List.iter (fun f -> f t) type_filters
  406. in
  407. (try Interp.add_types mint types ready
  408. with Error (e,p) -> t(); raise (Fatal_error(error_msg e,p)));
  409. t();
  410. Filters.next_compilation()
  411. let create_macro_interp ctx mctx =
  412. let com2 = mctx.com in
  413. let mint, init = (match !macro_interp_cache with
  414. | None ->
  415. let mint = Interp.create com2 (make_macro_api ctx null_pos) true in
  416. Interp.select mint;
  417. mint, (fun() -> init_macro_interp ctx mctx mint)
  418. | Some mint ->
  419. macro_interp_reused := false;
  420. Interp.do_reuse mint (make_macro_api ctx null_pos);
  421. mint, (fun() -> ())
  422. ) in
  423. let on_error = com2.error in
  424. com2.error <- (fun e p ->
  425. Interp.set_error (Interp.get_ctx()) true;
  426. macro_interp_cache := None;
  427. on_error e p
  428. );
  429. let macro = ((fun() -> Interp.select mint), mctx) in
  430. ctx.g.macros <- Some macro;
  431. mctx.g.macros <- Some macro;
  432. (* mctx.g.core_api <- ctx.g.core_api; // causes some issues because of optional args and Null type in Flash9 *)
  433. init()
  434. let get_macro_context ctx p =
  435. let api = make_macro_api ctx p in
  436. match ctx.g.macros with
  437. | Some (select,ctx) ->
  438. select();
  439. api, ctx
  440. | None ->
  441. let com2 = Common.clone ctx.com in
  442. ctx.com.get_macros <- (fun() -> Some com2);
  443. com2.package_rules <- PMap.empty;
  444. com2.main_class <- None;
  445. com2.display <- DisplayMode.create DMNone;
  446. List.iter (fun p -> com2.defines <- PMap.remove (Globals.platform_name p) com2.defines) Globals.platforms;
  447. com2.defines_signature <- None;
  448. com2.class_path <- List.filter (fun s -> not (ExtString.String.exists s "/_std/")) com2.class_path;
  449. let name = platform_name !Globals.macro_platform in
  450. com2.class_path <- List.map (fun p -> p ^ name ^ "/_std/") com2.std_path @ com2.class_path;
  451. let to_remove = List.map (fun d -> fst (Define.infos d)) [Define.NoTraces] in
  452. let to_remove = to_remove @ List.map (fun (_,d) -> "flash" ^ d) Common.flash_versions in
  453. com2.defines <- PMap.foldi (fun k v acc -> if List.mem k to_remove then acc else PMap.add k v acc) com2.defines PMap.empty;
  454. Common.define com2 Define.Macro;
  455. Common.init_platform com2 !Globals.macro_platform;
  456. let mctx = ctx.g.do_create com2 in
  457. mctx.is_display_file <- ctx.is_display_file;
  458. create_macro_interp ctx mctx;
  459. api, mctx
  460. let load_macro ctx display cpath f p =
  461. let api, mctx = get_macro_context ctx p in
  462. let mint = Interp.get_ctx() in
  463. let cpath, sub = (match List.rev (fst cpath) with
  464. | name :: pack when name.[0] >= 'A' && name.[0] <= 'Z' -> (List.rev pack,name), Some (snd cpath)
  465. | _ -> cpath, None
  466. ) in
  467. let meth = try Hashtbl.find mctx.com.cached_macros (cpath,f) with Not_found ->
  468. let t = macro_timer ctx ["typing";s_type_path cpath ^ "." ^ f] in
  469. (* Temporarily enter display mode while typing the macro. *)
  470. if display then mctx.com.display <- ctx.com.display;
  471. let m = (try Hashtbl.find ctx.g.types_module cpath with Not_found -> cpath) in
  472. let mloaded = Typeload.load_module mctx m p in
  473. api.MacroApi.current_macro_module <- (fun() -> mloaded);
  474. mctx.m <- {
  475. curmod = mloaded;
  476. module_types = [];
  477. module_using = [];
  478. module_globals = PMap.empty;
  479. wildcard_packages = [];
  480. module_imports = [];
  481. };
  482. add_dependency ctx.m.curmod mloaded;
  483. let mt = Typeload.load_type_def mctx p { tpackage = fst cpath; tname = snd cpath; tparams = []; tsub = sub } in
  484. let cl, meth = (match mt with
  485. | TClassDecl c ->
  486. mctx.g.do_finalize mctx;
  487. c, (try PMap.find f c.cl_statics with Not_found -> error ("Method " ^ f ^ " not found on class " ^ s_type_path cpath) p)
  488. | _ -> error "Macro should be called on a class" p
  489. ) in
  490. if not (Common.defined ctx.com Define.NoDeprecationWarnings) then
  491. Display.DeprecationCheck.check_cf mctx.com meth p;
  492. let meth = (match follow meth.cf_type with TFun (args,ret) -> args,ret,cl,meth | _ -> error "Macro call should be a method" p) in
  493. mctx.com.display <- DisplayMode.create DMNone;
  494. if not ctx.in_macro then flush_macro_context mint ctx;
  495. Hashtbl.add mctx.com.cached_macros (cpath,f) meth;
  496. mctx.m <- {
  497. curmod = null_module;
  498. module_types = [];
  499. module_using = [];
  500. module_globals = PMap.empty;
  501. wildcard_packages = [];
  502. module_imports = [];
  503. };
  504. t();
  505. meth
  506. in
  507. let call args =
  508. if ctx.com.verbose then Common.log ctx.com ("Calling macro " ^ s_type_path cpath ^ "." ^ f ^ " (" ^ p.pfile ^ ":" ^ string_of_int (Lexer.get_error_line p) ^ ")");
  509. let t = macro_timer ctx ["execution";s_type_path cpath ^ "." ^ f] in
  510. incr stats.s_macros_called;
  511. let r = Interp.call_path (Interp.get_ctx()) ((fst cpath) @ [(match sub with None -> snd cpath | Some s -> s)]) f args api in
  512. t();
  513. if ctx.com.verbose then Common.log ctx.com ("Exiting macro " ^ s_type_path cpath ^ "." ^ f);
  514. r
  515. in
  516. mctx, meth, call
  517. type macro_arg_type =
  518. | MAExpr
  519. | MAFunction
  520. | MAOther
  521. let type_macro ctx mode cpath f (el:Ast.expr list) p =
  522. let mctx, (margs,mret,mclass,mfield), call_macro = load_macro ctx (mode = MDisplay) cpath f p in
  523. let mpos = mfield.cf_pos in
  524. let ctexpr = { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = None } in
  525. let expr = Typeload.load_instance mctx (ctexpr,null_pos) false p in
  526. (match mode with
  527. | MDisplay ->
  528. raise Exit (* We don't have to actually call the macro. *)
  529. | MExpr ->
  530. unify mctx mret expr mpos;
  531. | MBuild ->
  532. let ctfields = { tpackage = []; tname = "Array"; tparams = [TPType (CTPath { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = Some "Field" },null_pos)]; tsub = None } in
  533. let tfields = Typeload.load_instance mctx (ctfields,null_pos) false p in
  534. unify mctx mret tfields mpos
  535. | MMacroType ->
  536. let cttype = { tpackage = ["haxe";"macro"]; tname = "Type"; tparams = []; tsub = None } in
  537. let ttype = Typeload.load_instance mctx (cttype,null_pos) false p in
  538. try
  539. unify_raise mctx mret ttype mpos;
  540. (* TODO: enable this again in the future *)
  541. (* ctx.com.warning "Returning Type from @:genericBuild macros is deprecated, consider returning ComplexType instead" p; *)
  542. with Error (Unify _,_) ->
  543. let cttype = { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = Some ("ComplexType") } in
  544. let ttype = Typeload.load_instance mctx (cttype,null_pos) false p in
  545. unify_raise mctx mret ttype mpos;
  546. );
  547. (*
  548. if the function's last argument is of Array<Expr>, split the argument list and use [] for unify_call_args
  549. *)
  550. let el,el2 = match List.rev margs with
  551. | (_,_,TInst({cl_path=([], "Array")},[e])) :: rest when (try Type.type_eq EqStrict e expr; true with Unify_error _ -> false) ->
  552. let rec loop (acc1,acc2) el1 el2 = match el1,el2 with
  553. | [],[] ->
  554. List.rev acc1, List.rev acc2
  555. | [], e2 :: [] ->
  556. (List.rev ((EArrayDecl [],p) :: acc1), [])
  557. | [], _ ->
  558. (* not enough arguments, will be handled by unify_call_args *)
  559. List.rev acc1, List.rev acc2
  560. | e1 :: l1, e2 :: [] ->
  561. loop (((EArrayDecl [],p) :: acc1), [e1]) l1 []
  562. | e1 :: l1, [] ->
  563. loop (acc1, e1 :: acc2) l1 []
  564. | e1 :: l1, e2 :: l2 ->
  565. loop (e1 :: acc1, acc2) l1 l2
  566. in
  567. loop ([],[]) el margs
  568. | _ ->
  569. el,[]
  570. in
  571. let todo = ref [] in
  572. let args =
  573. (*
  574. force default parameter types to haxe.macro.Expr, and if success allow to pass any value type since it will be encoded
  575. *)
  576. let eargs = List.map (fun (n,o,t) ->
  577. try unify_raise mctx t expr p; (n, o, t_dynamic), MAExpr
  578. with Error (Unify _,_) -> match follow t with
  579. | TFun _ ->
  580. (n,o,t_dynamic), MAFunction
  581. | _ ->
  582. (n,o,t), MAOther
  583. ) margs in
  584. (*
  585. this is quite tricky here : we want to use unify_call_args which will type our AST expr
  586. but we want to be able to get it back after it's been padded with nulls
  587. *)
  588. let index = ref (-1) in
  589. let constants = List.map (fun e ->
  590. let p = snd e in
  591. let e = (try
  592. (match Codegen.type_constant_value ctx.com e with
  593. | { eexpr = TConst (TString _); epos = p } when Lexer.is_fmt_string p ->
  594. Lexer.remove_fmt_string p;
  595. todo := (fun() -> Lexer.add_fmt_string p) :: !todo;
  596. | _ -> ());
  597. e
  598. with Error (Custom _,_) ->
  599. (* if it's not a constant, let's make something that is typed as haxe.macro.Expr - for nice error reporting *)
  600. (EBlock [
  601. (EVars [("__tmp",null_pos),Some (CTPath ctexpr,p),Some (EConst (Ident "null"),p)],p);
  602. (EConst (Ident "__tmp"),p);
  603. ],p)
  604. ) in
  605. (* let's track the index by doing [e][index] (we will keep the expression type this way) *)
  606. incr index;
  607. (EArray ((EArrayDecl [e],p),(EConst (Int (string_of_int (!index))),p)),p)
  608. ) el in
  609. let elt, _ = unify_call_args mctx constants (List.map fst eargs) t_dynamic p false false in
  610. List.iter (fun f -> f()) (!todo);
  611. List.map2 (fun (_,mct) e ->
  612. let e, et = (match e.eexpr with
  613. (* get back our index and real expression *)
  614. | TArray ({ eexpr = TArrayDecl [e] }, { eexpr = TConst (TInt index) }) -> List.nth el (Int32.to_int index), e
  615. (* added by unify_call_args *)
  616. | TConst TNull -> (EConst (Ident "null"),e.epos), e
  617. | _ -> assert false
  618. ) in
  619. let ictx = Interp.get_ctx() in
  620. match mct with
  621. | MAExpr ->
  622. Interp.encode_expr e
  623. | MAFunction ->
  624. let e = ictx.Interp.curapi.MacroApi.type_macro_expr e in
  625. begin match Interp.eval_expr ictx e with
  626. | Some v -> v
  627. | None -> Interp.vnull
  628. end
  629. | MAOther -> match Interp.eval_expr ictx et with
  630. | None -> assert false
  631. | Some v -> v
  632. ) eargs elt
  633. in
  634. let args = match el2 with
  635. | [] -> args
  636. | _ -> (match List.rev args with _::args -> List.rev args | [] -> []) @ [Interp.encode_array (List.map Interp.encode_expr el2)]
  637. in
  638. let call() =
  639. match call_macro args with
  640. | None -> None
  641. | Some v ->
  642. try
  643. Some (match mode with
  644. | MExpr | MDisplay -> Interp.decode_expr v
  645. | MBuild ->
  646. let fields = if v = Interp.vnull then
  647. (match ctx.g.get_build_infos() with
  648. | None -> assert false
  649. | Some (_,_,fields) -> fields)
  650. else
  651. List.map Interp.decode_field (Interp.decode_array v)
  652. in
  653. (EVars [("fields",null_pos),Some (CTAnonymous fields,p),None],p)
  654. | MMacroType ->
  655. let t = if v = Interp.vnull then
  656. mk_mono()
  657. else try
  658. let ct = Interp.decode_ctype v in
  659. Typeload.load_complex_type ctx false p ct;
  660. with MacroApi.Invalid_expr ->
  661. Interp.decode_type v
  662. in
  663. ctx.ret <- t;
  664. (EBlock [],p)
  665. )
  666. with MacroApi.Invalid_expr ->
  667. if v = Interp.vnull then
  668. error "Unexpected null value returned from macro" p
  669. else
  670. error "The macro didn't return a valid result" p
  671. in
  672. let e = (if ctx.in_macro then begin
  673. (*
  674. this is super-tricky : we can't evaluate a macro inside a macro because we might trigger some cycles.
  675. So instead, we generate a haxe.macro.Context.delayedCalled(i) expression that will only evaluate the
  676. macro if/when it is called.
  677. The tricky part is that the whole delayed-evaluation process has to use the same contextual informations
  678. as if it was evaluated now.
  679. *)
  680. let ctx = {
  681. ctx with locals = ctx.locals;
  682. } in
  683. let pos = DynArray.length mctx.g.delayed_macros in
  684. DynArray.add mctx.g.delayed_macros (fun() ->
  685. delayed_macro_result := (fun() ->
  686. let mint = Interp.get_ctx() in
  687. match call() with
  688. | None -> (fun() -> raise MacroApi.Abort)
  689. | Some e -> Interp.eval_delayed mint (type_expr ctx e Value)
  690. );
  691. );
  692. ctx.m.curmod.m_extra.m_time <- -1.; (* disable caching for modules having macro-in-macro *)
  693. if Common.defined ctx.com Define.MacroDebug then
  694. ctx.com.warning "Macro-in-macro call detected" p;
  695. let e = (EConst (Ident "$__delayed_call__"),p) in
  696. Some (EUntyped (ECall (e,[EConst (Int (string_of_int pos)),p]),p),p)
  697. end else
  698. call()
  699. ) in
  700. e
  701. let call_macro ctx path meth args p =
  702. let mctx, (margs,_,mclass,mfield), call = load_macro ctx false path meth p in
  703. let el, _ = unify_call_args mctx args margs t_dynamic p false false in
  704. call (List.map (fun e -> try Interp.make_const e with Exit -> error "Parameter should be a constant" e.epos) el)
  705. let call_init_macro ctx e =
  706. let p = { pfile = "--macro"; pmin = 0; pmax = 0 } in
  707. let e = try
  708. Parser.parse_expr_string ctx.com e p error false
  709. with err ->
  710. display_error ctx ("Could not parse `" ^ e ^ "`") p;
  711. raise err
  712. in
  713. match fst e with
  714. | ECall (e,args) ->
  715. let rec loop e =
  716. match fst e with
  717. | EField (e,f) -> f :: loop e
  718. | EConst (Ident i) -> [i]
  719. | _ -> error "Invalid macro call" p
  720. in
  721. let path, meth = (match loop e with
  722. | [meth] -> (["haxe";"macro"],"Compiler"), meth
  723. | [meth;"server"] -> (["haxe";"macro"],"CompilationServer"), meth
  724. | meth :: cl :: path -> (List.rev path,cl), meth
  725. | _ -> error "Invalid macro call" p) in
  726. ignore(call_macro ctx path meth args p);
  727. | _ ->
  728. error "Invalid macro call" p
  729. let interpret ctx =
  730. let mctx = Interp.create ctx.com (make_macro_api ctx null_pos) false in
  731. Interp.add_types mctx ctx.com.types (fun t -> ());
  732. match ctx.com.main with
  733. | None -> ()
  734. | Some e -> ignore(Interp.eval_expr mctx e)
  735. let setup() =
  736. Interp.setup Interp.macro_api
  737. ;;
  738. load_macro_ref := load_macro;