浏览代码

Merge pull request #4419 from andyli/includeFile

Allow to specify includeFile position.
Andy Li 10 年之前
父节点
当前提交
183928ca57
共有 6 个文件被更改,包括 91 次插入13 次删除
  1. 2 0
      common.ml
  2. 19 0
      genjs.ml
  3. 14 0
      interp.ml
  4. 32 13
      std/haxe/macro/Compiler.hx
  5. 23 0
      tests/unit/src/unit/issues/Issue4419.hx
  6. 1 0
      tests/unit/src/unit/issues/misc/Issue4419External.js

+ 2 - 0
common.ml

@@ -144,6 +144,7 @@ type context = {
 	mutable types : Type.module_type list;
 	mutable types : Type.module_type list;
 	mutable resources : (string,string) Hashtbl.t;
 	mutable resources : (string,string) Hashtbl.t;
 	mutable neko_libs : string list;
 	mutable neko_libs : string list;
+	mutable include_files : (string * string) list;
 	mutable php_front : string option;
 	mutable php_front : string option;
 	mutable php_lib : string option;
 	mutable php_lib : string option;
 	mutable php_prefix : string option;
 	mutable php_prefix : string option;
@@ -740,6 +741,7 @@ let create v args =
 		net_path_map = Hashtbl.create 0;
 		net_path_map = Hashtbl.create 0;
 		c_args = [];
 		c_args = [];
 		neko_libs = [];
 		neko_libs = [];
+		include_files = [];
 		php_prefix = None;
 		php_prefix = None;
 		js_gen = None;
 		js_gen = None;
 		load_extern_type = [];
 		load_extern_type = [];

+ 19 - 0
genjs.ml

@@ -1287,6 +1287,16 @@ let generate com =
 		in loop parts "";
 		in loop parts "";
 	)) exposed;
 	)) exposed;
 
 
+	let include_files = List.rev com.include_files in
+
+	List.iter (fun file ->
+		match file with
+		| path, "top" ->
+			let file_content = Std.input_file ~bin:true (fst file) in
+			print ctx "%s\n" file_content;
+			()
+		| _ -> ()
+	) include_files;
 
 
 	let closureArgs = [] in
 	let closureArgs = [] in
 	let closureArgs = if (anyExposed && not (Common.defined com Define.ShallowExpose)) then
 	let closureArgs = if (anyExposed && not (Common.defined com Define.ShallowExpose)) then
@@ -1335,6 +1345,15 @@ let generate com =
 		List.iter (fun f -> print_obj f "$hx_exports") exposedObject.os_fields;
 		List.iter (fun f -> print_obj f "$hx_exports") exposedObject.os_fields;
 	end;
 	end;
 
 
+	List.iter (fun file ->
+		match file with
+		| path, "closure" ->
+			let file_content = Std.input_file ~bin:true (fst file) in
+			print ctx "%s\n" file_content;
+			()
+		| _ -> ()
+	) include_files;
+
 	(* If ctx.js_modern, console is defined in closureArgs. *)
 	(* If ctx.js_modern, console is defined in closureArgs. *)
 	if (not ctx.js_modern) && (not (Common.defined com Define.JsEs5)) then
 	if (not ctx.js_modern) && (not (Common.defined com Define.JsEs5)) then
 		spr ctx "var console = Function(\"return typeof console != 'undefined' ? console : {log:function(){}}\")();\n";
 		spr ctx "var console = Function(\"return typeof console != 'undefined' ? console : {log:function(){}}\")();\n";

+ 14 - 0
interp.ml

@@ -2713,6 +2713,20 @@ let macro_lib =
 			| Some v -> v
 			| Some v -> v
 			| None -> VNull
 			| None -> VNull
 		);
 		);
+		"include_file", Fun2 (fun file position ->
+			match file, position with
+			| VString file, VString position ->
+				let file = if Sys.file_exists file then
+					file
+				else try Common.find_file (ccom()) file with
+					| Not_found ->
+						failwith ("unable to find file for inclusion: " ^ file)
+				in
+				(ccom()).include_files <- (file, position) :: (ccom()).include_files;
+				VNull
+			| _ ->
+				error()
+		);
 	]
 	]
 
 
 (* ---------------------------------------------------------------------- *)
 (* ---------------------------------------------------------------------- *)

+ 32 - 13
std/haxe/macro/Compiler.hx

@@ -331,22 +331,41 @@ class Compiler {
 
 
 	#if (js || macro)
 	#if (js || macro)
 	/**
 	/**
-		Embed an on-disk javascript file (can be called into an __init__ method)
+		Embed a JavaScript file at compile time (can be called by `--macro` or within an `__init__` method).
 	**/
 	**/
-	public static macro function includeFile( fileName : Expr ) {
-		var str = switch( fileName.expr ) {
-		case EConst(c):
-			switch( c ) {
-			case CString(str): str;
-			default: null;
-			}
-		default: null;
+	public static macro function includeFile( file : String, position:IncludePosition = Top ) {
+		return switch ((position:String).toLowerCase()) {
+			case Inline:
+				if (Context.getLocalModule() == "")
+					Context.error("Cannot use inline mode when includeFile is called by `--macro`", Context.currentPos());
+
+				var f = try sys.io.File.getContent(Context.resolvePath(file)) catch( e : Dynamic ) Context.error(Std.string(e), Context.currentPos());
+				var p = Context.currentPos();
+				{ expr : EUntyped( { expr : ECall( { expr : EConst(CIdent("__js__")), pos : p }, [ { expr : EConst(CString(f)), pos : p } ]), pos : p } ), pos : p };
+			case Top | Closure:
+				load("include_file", 2)(untyped file.__s, untyped position.__s);
+				macro {};
+			case _:
+				Context.error("unknown includeFile position: " + position, Context.currentPos());
 		}
 		}
-		if( str == null ) Context.error("Should be a constant string", fileName.pos);
-		var f = try sys.io.File.getContent(Context.resolvePath(str)) catch( e : Dynamic ) Context.error(Std.string(e), fileName.pos);
-		var p = Context.currentPos();
-		return { expr : EUntyped( { expr : ECall( { expr : EConst(CIdent("__js__")), pos : p }, [ { expr : EConst(CString(f)), pos : p } ]), pos : p } ), pos : p };
 	}
 	}
 	#end
 	#end
 
 
 }
 }
+
+@:enum abstract IncludePosition(String) from String to String {
+	/** 
+		Prepend the file content to the output file.
+	*/
+	var Top = "top";
+	/** 
+		Prepend the file content to the body of the top-level closure.
+
+		Since the closure is in strict-mode, there may be run-time error if the input is not strict-mode-compatible.
+	*/
+	var Closure = "closure";
+	/**
+		Directly inject the file content at the call site.
+	*/
+	var Inline = "inline";
+}

+ 23 - 0
tests/unit/src/unit/issues/Issue4419.hx

@@ -0,0 +1,23 @@
+package unit.issues;
+
+#if js
+@:native("Issue4419External")
+private extern class External {
+    static function __init__():Void {
+        haxe.macro.Compiler.includeFile("unit/issues/misc/Issue4419External.js");
+    }
+}
+
+private class SubExt extends External {
+	public function new():Void {}
+	public function hello() return "hello";
+}
+#end
+
+class Issue4419 extends Test {
+	#if js
+	function test() {
+		eq("hello", new SubExt().hello());
+	}
+	#end
+}

+ 1 - 0
tests/unit/src/unit/issues/misc/Issue4419External.js

@@ -0,0 +1 @@
+var Issue4419External = function() { };