Forráskód Böngészése

Add "Custom" target (#11128)

* Added `--custom-target` arg & `.custom.hx` support

* add Compiler.setPlatformConfiguration

see #11128

* Allow multiple `--custom-target`

* Disallow multiple `--custom-target`

* Get github to detect changes?

* Revert "Get github to detect changes?"

This reverts commit beb72ce8bbebf2d53793275bfa724074e3edd35e.

* Add `Platform` enum to Compiler.hx

* Revert --custom-target argument description

* Update custom target check for Init.init() call

* Do not overwrite config on custom targets

* Add tests

* Test custom target "platform" detection

* remove com.custom_target, use com.platform directly

see #11128

* avoid some code duplication for light macros

also fix rudy tests

* after_arg_parsing -> after_target_init

* Catch and ignore <target>.Init not found

* Add tests for absent or error <target>.Init

* Rework Cross/Custom cases in generate

* Add "custom_target" define

* Test reserved target names

* Remove `PlatformConfig.canSkipNonNullableArgument`

---------

Co-authored-by: Simon Krajewski <[email protected]>
RoBBoR 2 éve
szülő
commit
4d9bd89703
37 módosított fájl, 395 hozzáadás és 64 törlés
  1. 4 0
      src/compiler/args.ml
  2. 1 1
      src/compiler/compilationContext.ml
  3. 27 7
      src/compiler/compiler.ml
  4. 10 8
      src/compiler/generate.ml
  5. 2 2
      src/compiler/server.ml
  6. 34 12
      src/context/common.ml
  7. 5 1
      src/core/globals.ml
  8. 1 1
      src/filters/exceptions.ml
  9. 1 0
      src/macro/eval/evalEncode.ml
  10. 1 0
      src/macro/eval/evalHash.ml
  11. 83 3
      src/macro/macroApi.ml
  12. 39 14
      src/typing/macroContext.ml
  13. 2 1
      src/typing/typer.ml
  14. 1 1
      std/Std.hx
  15. 28 1
      std/haxe/macro/Compiler.hx
  16. 0 5
      std/haxe/macro/PlatformConfig.hx
  17. 1 1
      tests/misc/projects/Issue10844/user-defined-define-json-fail.hxml.stderr
  18. 1 1
      tests/misc/projects/Issue10844/user-defined-meta-json-fail.hxml.stderr
  19. 1 1
      tests/misc/projects/Issue10844/user-defined-meta-json-indent-fail.hxml.stderr
  20. 2 2
      tests/misc/projects/Issue10844/user-defined-meta-json-pretty-fail.hxml.stderr
  21. 10 1
      tests/misc/projects/Issue10871/Compiler/Main.hx
  22. 41 0
      tests/misc/projects/Issue11128/Main.hx
  23. 2 0
      tests/misc/projects/Issue11128/compile1-fail.hxml
  24. 1 0
      tests/misc/projects/Issue11128/compile1-fail.hxml.stderr
  25. 3 0
      tests/misc/projects/Issue11128/compile1.hxml
  26. 6 0
      tests/misc/projects/Issue11128/compile1.hxml.stdout
  27. 4 0
      tests/misc/projects/Issue11128/compile2-fail.hxml
  28. 1 0
      tests/misc/projects/Issue11128/compile2-fail.hxml.stderr
  29. 3 0
      tests/misc/projects/Issue11128/compile2.hxml
  30. 6 0
      tests/misc/projects/Issue11128/compile2.hxml.stdout
  31. 2 0
      tests/misc/projects/Issue11128/compile3.hxml
  32. 4 0
      tests/misc/projects/Issue11128/compile3.hxml.stdout
  33. 4 0
      tests/misc/projects/Issue11128/compile4.hxml
  34. 0 0
      tests/misc/projects/Issue11128/compile4.hxml.stderr
  35. 12 0
      tests/misc/projects/Issue11128/fail_target/Init.hx
  36. 51 0
      tests/misc/projects/Issue11128/hxtest/Init.hx
  37. 1 1
      tests/sourcemaps/src/Validator.hx

+ 4 - 0
src/compiler/args.ml

@@ -98,6 +98,10 @@ let parse_args com =
 		("Target",["--hl"],["-hl"],Arg.String (fun file ->
 			set_platform com Hl file;
 		),"<file>","generate HashLink .hl bytecode or .c code into target file");
+		("Target",["--custom-target"],["-custom"],Arg.String (fun target ->
+			let name, path = try let split = ExtString.String.split target "=" in split with _ -> target, "" in
+			set_custom_target com name path;
+		),"<name[=path]>","generate code for a custom target");
 		("Target",[],["-x"], Arg.String (fun cl ->
 			let cpath = Path.parse_type_path cl in
 			(match com.main_class with

+ 1 - 1
src/compiler/compilationContext.ml

@@ -44,7 +44,7 @@ and compilation_context = {
 
 type compilation_callbacks = {
 	before_anything : compilation_context -> unit;
-	after_arg_parsing : compilation_context -> unit;
+	after_target_init : compilation_context -> unit;
 	after_compilation : compilation_context -> unit;
 }
 

+ 27 - 7
src/compiler/compiler.ml

@@ -71,14 +71,15 @@ let run_command ctx cmd =
 
 module Setup = struct
 	let initialize_target ctx com actx =
+		init_platform com;
 		let add_std dir =
 			com.class_path <- List.filter (fun s -> not (List.mem s com.std_path)) com.class_path @ List.map (fun p -> p ^ dir ^ "/_std/") com.std_path @ com.std_path
 		in
 		match com.platform with
 			| Cross ->
-				(* no platform selected *)
-				set_platform com Cross "";
 				"?"
+			| CustomTarget name ->
+				name
 			| Flash ->
 				let rec loop = function
 					| [] -> ()
@@ -159,7 +160,6 @@ module Setup = struct
 		) com.defines.values;
 		Buffer.truncate buffer (Buffer.length buffer - 1);
 		Common.log com (Buffer.contents buffer);
-		Typecore.type_expr_ref := (fun ?(mode=MGet) ctx e with_type -> Typer.type_expr ~mode ctx e with_type);
 		com.callbacks#run com.callbacks#get_before_typer_create;
 		(* Native lib pass 1: Register *)
 		let fl = List.map (fun (file,extern) -> NativeLibraryHandler.add_native_lib com file extern) (List.rev native_libs) in
@@ -304,14 +304,34 @@ let filter ctx tctx =
 	Filters.run ctx.com tctx ctx.com.main;
 	t()
 
-let compile ctx actx =
+let call_light_init_macro com path =
+	let open MacroContext in
+	let mctx = create_macro_context com in
+	let api = make_macro_com_api com null_pos in
+	let init = create_macro_interp api mctx in
+	MacroContext.MacroLight.call_init_macro com mctx api path;
+	(init,mctx)
+
+let compile ctx actx callbacks =
 	let com = ctx.com in
 	(* Set up display configuration *)
 	DisplayProcessing.process_display_configuration ctx;
 	let display_file_dot_path = DisplayProcessing.process_display_file com actx in
+	let mctx = match com.platform with
+		| CustomTarget name ->
+			begin try
+				Some (call_light_init_macro com (Printf.sprintf "%s.Init.init()" name))
+			with (Error.Error { err_message = Module_not_found ([pack],"Init") }) when pack = name ->
+				(* ignore if <target_name>.Init doesn't exist *)
+				None
+			end
+		| _ ->
+			None
+		in
 	(* Initialize target: This allows access to the appropriate std packages and sets the -D defines. *)
 	let ext = Setup.initialize_target ctx com actx in
-	com.config <- get_config com; (* make sure to adapt all flags changes defined after platform *)
+	update_platform_config com; (* make sure to adapt all flags changes defined after platform *)
+	callbacks.after_target_init ctx;
 	let t = Timer.timer ["init"] in
 	List.iter (fun f -> f()) (List.rev (actx.pre_compilation));
 	t();
@@ -321,6 +341,7 @@ let compile ctx actx =
 	end else begin
 		(* Actual compilation starts here *)
 		let tctx = Setup.create_typer_context ctx actx.native_libs in
+		tctx.g.macros <- mctx;
 		com.stage <- CTyperCreated;
 		let display_file_dot_path = DisplayProcessing.maybe_load_display_file_before_typing tctx display_file_dot_path in
 		begin try
@@ -434,8 +455,7 @@ let compile_ctx callbacks ctx =
 		compile_safe ctx (fun () ->
 			let actx = Args.parse_args ctx.com in
 			process_actx ctx actx;
-			callbacks.after_arg_parsing ctx;
-			compile ctx actx;
+			compile ctx actx callbacks;
 		);
 		finalize ctx;
 		callbacks.after_compilation ctx;

+ 10 - 8
src/compiler/generate.ml

@@ -57,8 +57,6 @@ let generate ctx tctx ext actx =
 	end;
 	if actx.interp then
 		Std.finally (Timer.timer ["interp"]) MacroContext.interpret tctx
-	else if com.platform = Cross then
-		()
 	else begin
 		let generate,name = match com.platform with
 		| Flash ->
@@ -91,11 +89,15 @@ let generate ctx tctx ext actx =
 			Genhl.generate,"hl"
 		| Eval ->
 			(fun _ -> MacroContext.interpret tctx),"eval"
-		| Cross ->
-			die "" __LOC__
+		| Cross
+		| CustomTarget _ ->
+			(fun _ -> ()),""
 		in
-		Common.log com ("Generating " ^ name ^ ": " ^ com.file);
-		let t = Timer.timer ["generate";name] in
-		generate com;
-		t()
+		if name = "" then ()
+		else begin
+			Common.log com ("Generating " ^ name ^ ": " ^ com.file);
+			let t = Timer.timer ["generate";name] in
+			generate com;
+			t()
+		end
 	end

+ 2 - 2
src/compiler/server.ml

@@ -445,7 +445,7 @@ let type_module sctx (ctx:Typecore.typer) mpath p =
 let before_anything sctx ctx =
 	ensure_macro_setup sctx
 
-let after_arg_parsing sctx ctx =
+let after_target_init sctx ctx =
 	let com = ctx.com in
 	let cs = sctx.cs in
 	let sign = Define.get_signature com.defines in
@@ -608,7 +608,7 @@ let rec process sctx comm args =
 		cache = sctx.cs;
 		callbacks = {
 			before_anything = before_anything sctx;
-			after_arg_parsing = after_arg_parsing sctx;
+			after_target_init = after_target_init sctx;
 			after_compilation = after_compilation sctx;
 		};
 		init_wait_socket = init_wait_socket;

+ 34 - 12
src/context/common.ml

@@ -511,6 +511,7 @@ let short_platform_name = function
 	| Python -> "py"
 	| Hl -> "hl"
 	| Eval -> "evl"
+	| CustomTarget n -> "c_" ^ n
 
 let stats =
 	{
@@ -556,6 +557,9 @@ let get_config com =
 	match com.platform with
 	| Cross ->
 		default_config
+	| CustomTarget _ ->
+		(* impossible to reach. see update_platform_config *)
+		raise Exit
 	| Js ->
 		let es6 = get_es_version com >= 6 in
 		{
@@ -928,12 +932,22 @@ let flash_version_tag = function
 	| v when v >= 12.0 && float_of_int (int_of_float v) = v -> int_of_float v + 11
 	| v -> failwith ("Invalid SWF version " ^ string_of_float v)
 
-let init_platform com pf =
-	com.platform <- pf;
-	let name = platform_name pf in
+let update_platform_config com =
+	match com.platform with
+	| CustomTarget _ ->
+		() (* do nothing, configured with macro api *)
+	| _ ->
+		com.config <- get_config com
+
+let init_platform com =
+	let name = platform_name com.platform in
+	if (com.platform = Flash) && Path.file_extension com.file = "swc" then define com Define.Swc;
+	(* Set the source header, unless the user has set one already or the platform sets a custom one *)
+	if not (defined com Define.SourceHeader) && (com.platform <> Hl) then
+		define_value com Define.SourceHeader ("Generated by Haxe " ^ s_version_full);
 	let forbid acc p = if p = name || PMap.mem p acc then acc else PMap.add p Forbidden acc in
 	com.package_rules <- List.fold_left forbid com.package_rules ("jvm" :: (List.map platform_name platforms));
-	com.config <- get_config com;
+	update_platform_config com;
 	if com.config.pf_static then begin
 		raw_define com "target.static";
 		define com Define.Static;
@@ -954,19 +968,26 @@ let init_platform com pf =
 		raw_define com "target.unicode";
 	end;
 	raw_define_value com.defines "target.name" name;
-	raw_define com name;
+	raw_define com (match com.platform with | CustomTarget _ -> "custom_target" | _ -> name);
 	if com.config.pf_supports_atomics then begin
 		raw_define com "target.atomics"
 	end
 
 let set_platform com pf file =
 	if com.platform <> Cross then failwith "Multiple targets";
-	init_platform com pf;
-	com.file <- file;
-	if (pf = Flash) && Path.file_extension file = "swc" then define com Define.Swc;
-	(* Set the source header, unless the user has set one already or the platform sets a custom one *)
-	if not (defined com Define.SourceHeader) && (pf <> Hl) then
-		define_value com Define.SourceHeader ("Generated by Haxe " ^ s_version_full)
+	com.platform <- pf;
+	com.file <- file
+
+let set_custom_target com name path =
+	if List.find_opt (fun pf -> (platform_name pf) = name) platforms <> None then
+		raise (Arg.Bad (Printf.sprintf "--custom-target cannot use reserved name %s" name));
+	if String.length name > max_custom_target_len then
+		raise (Arg.Bad (Printf.sprintf "--custom-target name %s exceeds the maximum of %d characters" name max_custom_target_len));
+	let name_regexp = Str.regexp "^[a-zA-Z0-9\\_]+$" in
+	if Str.string_match name_regexp name 0 then
+		set_platform com (CustomTarget name) path
+	else
+		raise (Arg.Bad (Printf.sprintf "--custom-target name %s may only contain alphanumeric or underscore characters" name))
 
 let add_feature com f =
 	Hashtbl.replace com.features f true
@@ -1023,7 +1044,8 @@ let abort ?(depth = 0) msg p = raise (Abort (Error.make_error ~depth (Custom msg
 let platform ctx p = ctx.platform = p
 
 let platform_name_macro com =
-	if defined com Define.Macro then "macro" else platform_name com.platform
+	if defined com Define.Macro then "macro"
+	else platform_name com.platform
 
 let remove_extension file =
 	try String.sub file 0 (String.rindex file '.')

+ 5 - 1
src/core/globals.ml

@@ -23,6 +23,7 @@ type platform =
 	| Python
 	| Hl
 	| Eval
+	| CustomTarget of string
 
 let version = 5000
 let version_major = version / 1000
@@ -38,6 +39,8 @@ let return_partial_type = ref false
 
 let is_windows = Sys.os_type = "Win32" || Sys.os_type = "Cygwin"
 
+let max_custom_target_len = 16
+
 let platforms = [
 	Js;
 	Lua;
@@ -66,6 +69,7 @@ let platform_name = function
 	| Python -> "python"
 	| Hl -> "hl"
 	| Eval -> "eval"
+	| CustomTarget c -> c
 
 let parse_platform = function
 	| "cross" -> Cross
@@ -80,7 +84,7 @@ let parse_platform = function
 	| "python" -> Python
 	| "hl" -> Hl
 	| "eval" -> Eval
-	| p -> raise (failwith ("invalid platform " ^ p))
+	| p -> CustomTarget p
 
 let platform_list_help = function
 	| [] -> ""

+ 1 - 1
src/filters/exceptions.ml

@@ -587,7 +587,7 @@ let filter tctx =
 			if contains_throw_or_try e then run e
 			else stub e
 		)
-	| Cross -> stub
+	| Cross | CustomTarget _ -> stub
 
 (**
 	Inserts `haxe.NativeStackTrace.saveStack(e)` in non-haxe.Exception catches.

+ 1 - 0
src/macro/eval/evalEncode.ml

@@ -186,6 +186,7 @@ let encode_enum i pos index pl =
 		| ICapturePolicy -> key_haxe_macro_CapturePolicy
 		| IVarScope -> key_haxe_macro_VarScope
 		| IVarScopingFlags -> key_haxe_macro_VarScopingFlags
+		| IPlatform -> key_haxe_macro_Platform
 		| IPackageRule -> key_haxe_macro_PackageRule
 		| IMessage -> key_haxe_macro_Message
 		| IFunctionKind -> key_haxe_macro_FunctionKind

+ 1 - 0
src/macro/eval/evalHash.ml

@@ -119,6 +119,7 @@ let key_haxe_macro_DisplayMode = hash "haxe.macro.DisplayMode"
 let key_haxe_macro_CapturePolicy = hash "haxe.macro.CapturePolicy"
 let key_haxe_macro_VarScope = hash "haxe.macro.VarScope"
 let key_haxe_macro_VarScopingFlags = hash "haxe.macro.VarScopingFlags"
+let key_haxe_macro_Platform = hash "haxe.macro.Platform"
 let key_haxe_macro_PackageRule = hash "haxe.macro.PackageRule"
 let key_haxe_macro_Message = hash "haxe.macro.Message"
 let key_haxe_macro_FunctionKind = hash "haxe.macro.FunctionKind"

+ 83 - 3
src/macro/macroApi.ml

@@ -98,6 +98,7 @@ type enum_type =
 	| ICapturePolicy
 	| IVarScope
 	| IVarScopingFlags
+	| IPlatform
 	| IPackageRule
 	| IMessage
 	| IFunctionKind
@@ -421,9 +422,23 @@ and encode_display_mode dm =
 	in
 	encode_enum ~pos:None IDisplayMode tag pl
 
-(** encoded to haxe.display.Display.Platform, an enum abstract of String *)
 and encode_platform p =
-	encode_string (platform_name p)
+	let tag, pl = match p with
+		| Cross -> 0, []
+		| Js -> 1, []
+		| Lua -> 2, []
+		| Neko -> 3, []
+		| Flash -> 4, []
+		| Php -> 5, []
+		| Cpp -> 6, []
+		| Cs -> 7, []
+		| Java -> 8, []
+		| Python -> 9, []
+		| Hl -> 10, []
+		| Eval -> 11, []
+		| CustomTarget s -> 12, [(encode_string s)]
+	in
+	encode_enum ~pos:None IPlatform tag pl
 
 and encode_platform_config pc =
 	encode_obj [
@@ -433,7 +448,6 @@ and encode_platform_config pc =
 		"padNulls", vbool pc.pf_pad_nulls;
 		"addFinalReturn", vbool pc.pf_add_final_return;
 		"overloadFunctions", vbool pc.pf_overload;
-		"canSkipNonNullableArgument", vbool pc.pf_can_skip_non_nullable_argument;
 		"reservedTypePaths", encode_array (List.map encode_path pc.pf_reserved_type_paths);
 		"supportsFunctionEquality", vbool pc.pf_supports_function_equality;
 		"usesUtf16", vbool pc.pf_uses_utf16;
@@ -1667,6 +1681,68 @@ let decode_type_def v =
 	) in
 	(pack, name), tdef, pos
 
+let decode_path v =
+	let pack = List.map decode_string (decode_array (field v "pack"))
+	and name = decode_string (field v "name") in
+	(pack,name)
+
+let decode_platform_config v =
+	let open Common in
+	let capture_policy = match decode_enum (field v "capturePolicy") with
+		| 0, [] -> CPNone
+		| 1, [] -> CPWrapRef
+		| 2, [] -> CPLoopVars
+		| _ -> raise Invalid_expr
+	in
+	let v_exc = field v "exceptions" in
+	let exception_config = {
+		ec_native_throws = List.map decode_path (decode_array (field v_exc "nativeThrows"));
+		ec_native_catches = List.map decode_path (decode_array (field v_exc "nativeCatches"));
+		ec_avoid_wrapping = decode_bool (field v_exc "avoidWrapping");
+		ec_wildcard_catch = decode_path (field v_exc "wildcardCatch");
+		ec_base_throw = decode_path (field v_exc "baseThrow");
+		ec_special_throw = (fun _ -> (* wtf is this? *) false);
+	} in
+	let v_scoping = field v "scoping" in
+	let decode_scope_flag v = match decode_enum v with
+		| 0, [] -> VarHoisting
+		| 1, [] -> NoShadowing
+		| 2, [] -> NoCatchVarShadowing
+		| 3, [] -> ReserveCurrentTopLevelSymbol
+		| 4, [] -> ReserveAllTopLevelSymbols
+		| 5, [] -> ReserveAllTypesFlat
+		| 6, [sl] -> ReserveNames (List.map decode_string (decode_array sl))
+		| 7, [] -> SwitchCasesNoBlocks
+		| _ -> raise Invalid_expr
+	in
+	let var_scoping_config = {
+		vs_scope = (match decode_enum (field v_scoping "scope") with
+			| 0,[] -> FunctionScope
+			| 1,[] -> BlockScope
+			| _ -> raise Invalid_expr
+		);
+		vs_flags = List.map decode_scope_flag (decode_array (field v_scoping "flags"));
+	} in
+	{
+		pf_static = decode_bool (field v "staticTypeSystem");
+		pf_sys = decode_bool (field v "sys");
+		pf_capture_policy = capture_policy;
+		pf_pad_nulls = decode_bool (field v "padNulls");
+		pf_add_final_return = decode_bool (field v "addFinalReturn");
+		pf_overload = decode_bool (field v "overloadFunctions");
+		pf_can_skip_non_nullable_argument = false;
+		pf_reserved_type_paths = List.map decode_path (decode_array (field v "reservedTypePaths"));
+		pf_supports_function_equality = decode_bool (field v "supportsFunctionEquality");
+		pf_uses_utf16 = decode_bool (field v "usesUtf16");
+		pf_this_before_super = decode_bool (field v "thisBeforeSuper");
+		pf_supports_threads = decode_bool (field v "supportsThreads");
+		pf_supports_unicode = decode_bool (field v "supportsUnicode");
+		pf_supports_rest_args = decode_bool (field v "supportsRestArgs");
+		pf_exceptions = exception_config;
+		pf_scoping = var_scoping_config;
+		pf_supports_atomics = decode_bool (field v "supportsAtomics");
+	}
+
 (* ---------------------------------------------------------------------- *)
 (* VALUE-TO-CONSTANT *)
 
@@ -2170,6 +2246,10 @@ let macro_api ccom get_api =
 				"packageRules", encode_string_map encode_package_rule com.package_rules;
 			]
 		);
+		"set_platform_configuration", vfun1 (fun v ->
+			(ccom()).config <- decode_platform_config v;
+			vnull
+		);
 		"get_main_expr", vfun0 (fun() ->
 			match (ccom()).main with None -> vnull | Some e -> encode_texpr e
 		);

+ 39 - 14
src/typing/macroContext.ml

@@ -647,7 +647,8 @@ let create_macro_context com =
 	let defines = adapt_defines_to_macro_context com2.defines; in
 	com2.defines.values <- defines.values;
 	com2.defines.defines_signature <- None;
-	Common.init_platform com2 !Globals.macro_platform;
+	com2.platform <- !Globals.macro_platform;
+	Common.init_platform com2;
 	let mctx = !create_context_ref com2 in
 	mctx.is_display_file <- false;
 	CommonCache.lock_signature com2 "get_macro_context";
@@ -730,6 +731,15 @@ let load_macro' ctx display cpath f p =
 	   voodoo stuff in displayToplevel.ml *)
 	fst (load_macro'' ctx.com (get_macro_context ctx) display cpath f p)
 
+let do_call_macro com api cpath f args p =
+	if com.verbose then Common.log com ("Calling macro " ^ s_type_path cpath ^ "." ^ f ^ " (" ^ p.pfile ^ ":" ^ string_of_int (Lexer.get_error_line p) ^ ")");
+	let t = macro_timer com ["execution";s_type_path cpath ^ "." ^ f] in
+	incr stats.s_macros_called;
+	let r = Interp.call_path (Interp.get_ctx()) ((fst cpath) @ [snd cpath]) f args api in
+	t();
+	if com.verbose then Common.log com ("Exiting macro " ^ s_type_path cpath ^ "." ^ f);
+	r
+
 let load_macro ctx display cpath f p =
 	let api = make_macro_api ctx p in
 	let mctx = get_macro_context ctx in
@@ -737,13 +747,7 @@ let load_macro ctx display cpath f p =
 	let _,_,{cl_path = cpath},_ = meth in
 	let call args =
 		add_dependency ctx.m.curmod mloaded;
-		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) ^ ")");
-		let t = macro_timer ctx.com ["execution";s_type_path cpath ^ "." ^ f] in
-		incr stats.s_macros_called;
-		let r = Interp.call_path (Interp.get_ctx()) ((fst cpath) @ [snd cpath]) f args api in
-		t();
-		if ctx.com.verbose then Common.log ctx.com ("Exiting macro " ^ s_type_path cpath ^ "." ^ f);
-		r
+		do_call_macro ctx.com api cpath f args p
 	in
 	mctx, meth, call
 
@@ -930,22 +934,21 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p =
 	in
 	e
 
-let call_macro ctx path meth args p =
-	let mctx, (margs,_,mclass,mfield), call = load_macro ctx false path meth p in
+let call_macro mctx args margs call p =
 	mctx.curclass <- null_class;
 	let el, _ = CallUnification.unify_call_args mctx args margs t_dynamic p false false false in
 	call (List.map (fun e -> try Interp.make_const e with Exit -> raise_typing_error "Argument should be a constant" e.epos) el)
 
-let call_init_macro ctx e =
+let resolve_init_macro com e =
 	let p = { pfile = "--macro " ^ e; pmin = -1; pmax = -1 } in
 	let e = try
 		if String.get e (String.length e - 1) = ';' then raise_typing_error "Unexpected ;" p;
-		begin match ParserEntry.parse_expr_string ctx.com.defines e p raise_typing_error false with
+		begin match ParserEntry.parse_expr_string com.defines e p raise_typing_error false with
 		| ParseSuccess(data,_,_) -> data
 		| ParseError(_,(msg,p),_) -> (Parser.error msg p)
 		end
 	with err ->
-		display_error ctx.com ("Could not parse `" ^ e ^ "`") p;
+		display_error com ("Could not parse `" ^ e ^ "`") p;
 		raise err
 	in
 	match fst e with
@@ -961,10 +964,32 @@ let call_init_macro ctx e =
 		| [meth;"server"] -> (["haxe";"macro"],"CompilationServer"), meth
 		| meth :: cl :: path -> (List.rev path,cl), meth
 		| _ -> raise_typing_error "Invalid macro call" p) in
-		ignore(call_macro ctx path meth args p);
+		(path,meth,args,p)
 	| _ ->
 		raise_typing_error "Invalid macro call" p
 
+let call_init_macro ctx e =
+	let (path,meth,args,p) = resolve_init_macro ctx.com e in
+	let mctx, (margs,_,mclass,mfield), call = load_macro ctx false path meth p in
+	ignore(call_macro mctx args margs call p);
+
+module MacroLight = struct
+	let load_macro_light com mctx api display cpath f p =
+		let api = {api with MacroApi.pos = p} in
+		let meth,mloaded = load_macro'' com mctx display cpath f p in
+		let _,_,{cl_path = cpath},_ = meth in
+		let call args =
+			do_call_macro com api cpath f args p
+		in
+		mctx, meth, call
+
+	let call_init_macro com mctx api e =
+		let (path,meth,args,p) = resolve_init_macro com e in
+		let mctx, (margs,_,mclass,mfield), call = load_macro_light com mctx api false path meth p in
+		ignore(call_macro mctx args margs call p);
+
+end
+
 let interpret ctx =
 	let mctx = Interp.create ctx.com (make_macro_api ctx null_pos) false in
 	Interp.add_types mctx ctx.com.types (fun t -> ());

+ 2 - 1
src/typing/typer.ml

@@ -2219,4 +2219,5 @@ make_call_ref := make_call;
 type_call_target_ref := type_call_target;
 type_access_ref := type_access;
 type_block_ref := type_block;
-create_context_ref := create
+create_context_ref := create;
+type_expr_ref := (fun ?(mode=MGet) ctx e with_type -> type_expr ~mode ctx e with_type);

+ 1 - 1
std/Std.hx

@@ -19,7 +19,7 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-#if !(core_api || cross || eval)
+#if !(core_api || cross || custom_target || eval)
 #error "Please don't add haxe/std to your classpath, instead set HAXE_STD_PATH env var"
 #end
 

+ 28 - 1
std/haxe/macro/Compiler.hx

@@ -181,6 +181,17 @@ class Compiler {
 		#end
 	}
 
+	/**
+		Sets the target configuration.
+
+		Usage of this function outside a macro context does nothing.
+	**/
+	public static function setPlatformConfiguration(config:PlatformConfig):Void {
+		#if (neko || eval)
+		load("set_platform_configuration", 1)(config);
+		#end
+	}
+
 	/**
 		Adds a native library depending on the platform (e.g. `-swf-lib` for Flash).
 
@@ -720,7 +731,7 @@ typedef CompilerConfiguration = {
 	/**
 		The target platform.
 	**/
-	final platform:haxe.display.Display.Platform;
+	final platform:Platform;
 
 	/**
 		The compilation configuration for the target platform.
@@ -745,6 +756,22 @@ typedef CompilerConfiguration = {
 	final packageRules:Map<String, PackageRule>;
 }
 
+enum Platform {
+	Cross;
+	Js;
+	Lua;
+	Neko;
+	Flash;
+	Php;
+	Cpp;
+	Cs;
+	Java;
+	Python;
+	Hl;
+	Eval;
+	CustomTarget(name:String);
+}
+
 enum PackageRule {
 	Forbidden;
 	Directory(path:String);

+ 0 - 5
std/haxe/macro/PlatformConfig.hx

@@ -41,11 +41,6 @@ typedef PlatformConfig = {
 	**/
 	final overloadFunctions:Bool;
 
-	/**
-		Can the platform use default values for non-nullable arguments
-	**/
-	final canSkipNonNullableArgument:Bool;
-
 	/**
 		Type paths that are reserved on the platform
 	**/

+ 1 - 1
tests/misc/projects/Issue10844/user-defined-define-json-fail.hxml.stderr

@@ -1,3 +1,3 @@
 (unknown) : Uncaught exception Could not read file define.jsno
-$$normPath(::std::)/haxe/macro/Compiler.hx:498: characters 11-39 : Called from here
+$$normPath(::std::)/haxe/macro/Compiler.hx:509: characters 11-39 : Called from here
 (unknown) : Called from here

+ 1 - 1
tests/misc/projects/Issue10844/user-defined-meta-json-fail.hxml.stderr

@@ -1,3 +1,3 @@
 (unknown) : Uncaught exception Could not read file meta.jsno
-$$normPath(::std::)/haxe/macro/Compiler.hx:487: characters 11-39 : Called from here
+$$normPath(::std::)/haxe/macro/Compiler.hx:498: characters 11-39 : Called from here
 (unknown) : Called from here

+ 1 - 1
tests/misc/projects/Issue10844/user-defined-meta-json-indent-fail.hxml.stderr

@@ -1,3 +1,3 @@
 (unknown) : Uncaught exception Could not read file meta.jsno
-  $$normPath(::std::)/haxe/macro/Compiler.hx:487: characters 11-39 : Called from here
+  $$normPath(::std::)/haxe/macro/Compiler.hx:498: characters 11-39 : Called from here
   (unknown) : Called from here

+ 2 - 2
tests/misc/projects/Issue10844/user-defined-meta-json-pretty-fail.hxml.stderr

@@ -2,9 +2,9 @@
 
    | Uncaught exception Could not read file meta.jsno
 
-    ->  $$normPath(::std::)/haxe/macro/Compiler.hx:487: characters 11-39
+    ->  $$normPath(::std::)/haxe/macro/Compiler.hx:498: characters 11-39
 
-    487 |   var f = sys.io.File.getContent(path);
+    498 |   var f = sys.io.File.getContent(path);
         |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         | Called from here
 

+ 10 - 1
tests/misc/projects/Issue10871/Compiler/Main.hx

@@ -17,7 +17,7 @@ class MacroClass {
 		trace(config.debug);
 		trace(config.verbose);
 		trace(config.foptimize);
-		trace(config.platform);
+		trace(platformToString(config.platform));
 		trace(config.mainClass.pack);
 		trace(config.mainClass.name);
 
@@ -28,5 +28,14 @@ class MacroClass {
 			}
 		}
 	}
+
+	static function platformToString(p: Platform) {
+		return switch(p) {
+			case Eval: "eval";
+			case Js: "js";
+			case Cpp: "cpp";
+			case _: "unused platform";
+		}
+	}
 }
 #end

+ 41 - 0
tests/misc/projects/Issue11128/Main.hx

@@ -0,0 +1,41 @@
+#if macro
+import haxe.macro.Compiler;
+import haxe.macro.Context;
+#end
+
+function main() {
+	trace("Hello world!");
+}
+
+#if macro
+function setupHxTestTarget() {
+	printTargetName("--macro");
+
+	// Check that output is available by --macro phase.
+	// Good place for "custom target" to ensure output path is valid early on (file vs folder).
+	switch(Compiler.getOutput()) {
+		case "": Sys.println("no output");
+		case o: Sys.println("output: " + o);
+	}
+
+	Context.onGenerate(onGenerate);
+}
+
+// Ensure custom target can be detected.
+function printTargetName(phase) {
+	Sys.println('[$phase] Target name: ' + (switch(Compiler.getConfiguration().platform) {
+		case CustomTarget(name): name;
+		case _: "Not custom target";
+	}));
+}
+
+// Where "custom target" files would be generated.
+function onGenerate(types: Array<haxe.macro.Type>) {
+	printTargetName("Generate");
+
+	// Make sure the config has not been overwritten since Init.init().
+	final intended = Std.string(hxtest.Init.intendedConfig);
+	final currentConfig = Std.string(Compiler.getConfiguration().platformConfig);
+	Sys.println("[Generate] Config correct: " + (intended == currentConfig));
+}
+#end

+ 2 - 0
tests/misc/projects/Issue11128/compile1-fail.hxml

@@ -0,0 +1,2 @@
+--main Main
+--custom-target fail_target

+ 1 - 0
tests/misc/projects/Issue11128/compile1-fail.hxml.stderr

@@ -0,0 +1 @@
+fail_target/Init.hx:10: characters 3-23 : Int should be String

+ 3 - 0
tests/misc/projects/Issue11128/compile1.hxml

@@ -0,0 +1,3 @@
+--main Main
+--macro Main.setupHxTestTarget()
+--custom-target hxtest=out

+ 6 - 0
tests/misc/projects/Issue11128/compile1.hxml.stdout

@@ -0,0 +1,6 @@
+hxtest.Init.init()
+[Init] Config correct: true
+[--macro] Target name: hxtest
+output: out
+[Generate] Target name: hxtest
+[Generate] Config correct: true

+ 4 - 0
tests/misc/projects/Issue11128/compile2-fail.hxml

@@ -0,0 +1,4 @@
+--main Main
+
+# Error cause of reserved name
+--custom-target js

+ 1 - 0
tests/misc/projects/Issue11128/compile2-fail.hxml.stderr

@@ -0,0 +1 @@
+Error: : --custom-target cannot use reserved name js.

+ 3 - 0
tests/misc/projects/Issue11128/compile2.hxml

@@ -0,0 +1,3 @@
+--main Main
+--macro Main.setupHxTestTarget()
+--custom-target hxtest

+ 6 - 0
tests/misc/projects/Issue11128/compile2.hxml.stdout

@@ -0,0 +1,6 @@
+hxtest.Init.init()
+[Init] Config correct: true
+[--macro] Target name: hxtest
+no output
+[Generate] Target name: hxtest
+[Generate] Config correct: true

+ 2 - 0
tests/misc/projects/Issue11128/compile3.hxml

@@ -0,0 +1,2 @@
+--main Main
+--macro Main.setupHxTestTarget()

+ 4 - 0
tests/misc/projects/Issue11128/compile3.hxml.stdout

@@ -0,0 +1,4 @@
+[--macro] Target name: Not custom target
+no output
+[Generate] Target name: Not custom target
+[Generate] Config correct: false

+ 4 - 0
tests/misc/projects/Issue11128/compile4.hxml

@@ -0,0 +1,4 @@
+--main Main
+
+# Ensure no error is thrown if no_init_target.Init doesn't exist.
+--custom-target no_init_target

+ 0 - 0
tests/misc/projects/Issue11128/compile4.hxml.stderr


+ 12 - 0
tests/misc/projects/Issue11128/fail_target/Init.hx

@@ -0,0 +1,12 @@
+package fail_target;
+
+import haxe.macro.Compiler;
+import haxe.macro.PlatformConfig;
+
+class Init {
+	public static function init() {
+		// Do something to fail to check that errors work here.
+		final a = 123;
+		final b: String = a;
+	}
+}

+ 51 - 0
tests/misc/projects/Issue11128/hxtest/Init.hx

@@ -0,0 +1,51 @@
+package hxtest;
+
+import haxe.macro.Compiler;
+import haxe.macro.PlatformConfig;
+
+class Init {
+	// Default, except everything has been set to `true`.
+	public static var intendedConfig: PlatformConfig = {
+		supportsAtomics: true,
+		thisBeforeSuper: true,
+		scoping: {
+			scope: BlockScope,
+			flags: []
+		},
+		exceptions: {
+			nativeThrows: [],
+			avoidWrapping: true,
+			baseThrow: {
+				name: "Dynamic",
+				pack: ["StdTypes"]
+			},
+			nativeCatches: [],
+			wildcardCatch: {
+				name: "Dynamic",
+				pack: ["StdTypes"]
+			}
+		},
+		supportsRestArgs: true,
+		overloadFunctions: true,
+		capturePolicy: None,
+		staticTypeSystem: true,
+		supportsUnicode: true,
+		supportsFunctionEquality: true,
+		reservedTypePaths: [],
+		addFinalReturn: true,
+		supportsThreads: true,
+		sys: true,
+		usesUtf16: true,
+		padNulls: true
+	}
+
+	public static function init() {
+		Sys.println("hxtest.Init.init()");
+		haxe.macro.Compiler.setPlatformConfiguration(intendedConfig);
+
+		// Check the config that was just set.
+		final intended = Std.string(intendedConfig);
+		final currentConfig = Std.string(Compiler.getConfiguration().platformConfig);
+		Sys.println("[Init] Config correct: " + (intended == currentConfig));
+	}
+}

+ 1 - 1
tests/sourcemaps/src/Validator.hx

@@ -1,5 +1,4 @@
 #if macro
-import validation.Target;
 import validation.Lines;
 import validation.ValidationReport;
 import validation.ValidationError;
@@ -8,6 +7,7 @@ import haxe.display.Position.Location;
 import haxe.macro.Context;
 import haxe.macro.Expr;
 import haxe.macro.Compiler;
+import validation.Target;
 import haxe.io.Path;
 
 using sys.io.File;