Skip to content

Commit

Permalink
[macro] add @:buildOrder(Early|Late) for build macros
Browse files Browse the repository at this point in the history
  • Loading branch information
kLabz committed Apr 10, 2024
1 parent 7217530 commit 60180e6
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 27 deletions.
7 changes: 7 additions & 0 deletions src-json/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@
"targets": ["TClass", "TEnum", "TAbstract"],
"links": ["https://haxe.org/manual/macro-type-building.html"]
},
{
"name": "BuildOrder",
"metadata": ":buildOrder",
"doc": "Specify that a build macro should run Early or Late (in relation to other build macros for current type)",
"params": ["Build order"],
"targets": ["TClassField"]
},
{
"name": "BuildXml",
"metadata": ":buildXml",
Expand Down
71 changes: 44 additions & 27 deletions src/typing/typeloadFields.ml
Original file line number Diff line number Diff line change
Expand Up @@ -382,34 +382,51 @@ let build_module_def ctx mt meta fvars fbuild =
| TTypeDecl _ -> true, t_infos mt
| _ -> false, t_infos mt
in
let loop f_build = function
| Meta.Build,args,p when not is_typedef -> (fun () ->
let epath, el = (match args with
| [ECall (epath,el),p] -> epath, el
| _ -> raise_typing_error "Invalid build parameters" p
) in
let cpath, meth =
let sl = try string_list_of_expr_path_raise ~root_cb:(resolve_type_import ctx p) epath with Exit -> raise_typing_error "Build call parameter must be a class path" p in
match sl with
| meth :: name :: pack ->
(List.rev pack,name), meth
| _ ->
raise_typing_error "Invalid macro path" p
in
if ctx.com.is_macro_context then raise_typing_error "You cannot use @:build inside a macro : make sure that your type is not used in macro" p;
let old = ctx.c.get_build_infos in
ctx.c.get_build_infos <- (fun() -> Some (mt, extract_param_types ti.mt_params, fvars()));
let r = try ctx.g.do_macro ctx MBuild cpath meth el p with e -> ctx.c.get_build_infos <- old; raise e in
ctx.c.get_build_infos <- old;
(match r with
| MError | MMacroInMacro -> raise_typing_error "Build failure" p
| MSuccess e -> fbuild e)
) :: f_build
| _ ->
f_build
let get_build_priority meta =
let rec loop meta = match meta with
| [] -> 0
| (Meta.BuildOrder,params,p) :: _ ->
(match params with
| [EConst (Ident "Early"),p] -> 1
| [EConst (Ident "Late"),p] -> -1
| [] -> raise_typing_error "Missing value for @:buildOrder" p
| _ -> raise_typing_error "Invalid @:buildOrder value. Expected `Early` or `Late`" p
)
| _ :: meta -> loop meta
in
loop meta
in
let build_macros = ExtLib.List.filter_map (fun m -> match m with
| Meta.Build,args,p when not is_typedef ->
let epath, el = (match args with
| [ECall (epath,el),p] -> epath, el
| _ -> raise_typing_error "Invalid build parameters" p
) in
let cpath, meth =
let sl = try string_list_of_expr_path_raise ~root_cb:(resolve_type_import ctx p) epath with Exit -> raise_typing_error "Build call parameter must be a class path" p in
match sl with
| meth :: name :: pack -> (List.rev pack,name), meth
| _ -> raise_typing_error "Invalid macro path" p
in
let (_,_,_,cf) = ctx.g.do_load_macro ctx false cpath meth p in
let priority = get_build_priority cf.cf_meta in
Some (cpath, meth, el, priority, p)
| _ ->
None
) meta in
let build_macros = List.sort (fun (_,_,_,p1,_) (_,_,_,p2,_) -> p2 - p1) build_macros in
let loop (cpath,meth,el,_,p) = (fun () ->
if ctx.com.is_macro_context then raise_typing_error "You cannot use @:build inside a macro : make sure that your type is not used in macro" p;
let old = ctx.c.get_build_infos in
ctx.c.get_build_infos <- (fun() -> Some (mt, extract_param_types ti.mt_params, fvars()));
let r = try ctx.g.do_macro ctx MBuild cpath meth el p with e -> ctx.c.get_build_infos <- old; raise e in
ctx.c.get_build_infos <- old;
(match r with
| MError | MMacroInMacro -> raise_typing_error "Build failure" p
| MSuccess e -> fbuild e)
) in
(* let errors go through to prevent resume if build fails *)
let f_build = List.fold_left loop [] meta in
let f_build = List.map loop build_macros in
let f_enum = match mt with
| TClassDecl ({cl_kind = KAbstractImpl a} as c) when a.a_enum ->
Some (fun () ->
Expand All @@ -429,7 +446,7 @@ let build_module_def ctx mt meta fvars fbuild =
| _ ->
None
in
List.iter (fun f -> f()) (List.rev f_build);
List.iter (fun f -> f()) f_build;
let apply_using = function
| Meta.Using,el,p ->
List.iter (fun e ->
Expand Down

0 comments on commit 60180e6

Please sign in to comment.