瀏覽代碼

rewrote macro rest handling by checking for @:rest

Simon Krajewski 13 年之前
父節點
當前提交
07a97f3836
共有 3 個文件被更改,包括 78 次插入15 次删除
  1. 19 0
      tests/unit/MyMacro.hx
  2. 38 0
      tests/unit/TestType.hx
  3. 21 15
      typer.ml

+ 19 - 0
tests/unit/MyMacro.hx

@@ -0,0 +1,19 @@
+package unit;
+
+import haxe.macro.Expr;
+
+class MyRestMacro {
+	@:rest @:macro static public function testRest1(e:Expr, r:Array<Expr>) {
+		var ret = [e];
+		for (e in r)
+			ret.push(e);
+		return macro $[ret];
+	}
+	
+	@:rest @:macro static public function testRest2(e1:Expr, e2:Expr, r:Array<Expr>) {
+		var ret = [e1,e2];
+		for (e in r)
+			ret.push(e);
+		return macro $[ret];		
+	}
+}

+ 38 - 0
tests/unit/TestType.hx

@@ -500,4 +500,42 @@ class TestType extends Test {
 	inline function inlineTest2(map:Array<Dynamic>) {
 		map[0];
 	}
+	
+	public function testMacroRest() {
+		#if !macro
+		var r = MyMacro.MyRestMacro.testRest1(1, 2, 3);
+		eq(r.length, 3);
+		eq(r[0], 1);
+		eq(r[1], 2);
+		eq(r[2], 3);
+		
+		var r = MyMacro.MyRestMacro.testRest1(1, [2, 3]);
+		eq(r.length, 2);
+		eq(r[0], 1);
+		eq(r[1][0], 2);
+		eq(r[1][1], 3);
+		
+		var r = MyMacro.MyRestMacro.testRest1(1);
+		eq(r.length, 1);
+		eq(r[0], 1);
+		
+		var r = MyMacro.MyRestMacro.testRest2(1, 2, 3, 4);
+		eq(r.length, 4);
+		eq(r[0], 1);
+		eq(r[1], 2);
+		eq(r[2], 3);
+		eq(r[3], 4);
+		
+		var r = MyMacro.MyRestMacro.testRest2(1, 2);
+		eq(r.length, 2);
+		eq(r[0], 1);
+		eq(r[1], 2);
+		
+		var r = MyMacro.MyRestMacro.testRest2(1, 2, [3]);
+		eq(r.length, 3);
+		eq(r[0], 1);
+		eq(r[1], 2);	
+		eq(r[2][0], 3);
+		#end
+	}	
 }

+ 21 - 15
typer.ml

@@ -2838,22 +2838,28 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p =
 	(*
 		if the function's last argument is of Array<Expr>, split the argument list and use [] for unify_call_params
 	*)
-	let el,el2 = match List.rev margs with
+	let el,el2 = if has_meta ":rest" mfield.cf_meta then match List.rev margs with
 		| (_,_,TInst({cl_path=([], "Array")},[e])) :: rest when (try Type.type_eq EqStrict e expr; true with Unify_error _ -> false) ->
-			let rec loop el1 el2 margs el = match margs,el with
-				| _,[] ->
-					el1,el2
-				| _ :: [], (EArrayDecl e,_) :: [] ->
-					(el1 @ [EArrayDecl [],p]),e
-				| [], e :: el ->
-					loop el1 (el2 @ [e]) [] el
-				| _ :: [], e :: el ->
-					loop (el1 @ [EArrayDecl [],p]) el2 [] (e :: el)
-				| _ :: margs, e :: el ->
-					loop (el1 @ [e]) el2 margs el
+			let rec loop (acc1,acc2) el1 el2 = match el1,el2 with
+				| [],[] ->
+					List.rev acc1, List.rev acc2
+				| [], e2 :: [] ->
+					(List.rev ((EArrayDecl [],p) :: acc1), [])
+				| [], _ ->
+					(* not enough arguments, will be handled by unify_call_params *)
+					List.rev acc1, List.rev acc2
+				| e1 :: l1, e2 :: [] ->
+					loop (((EArrayDecl [],p) :: acc1), [e1]) l1 []
+				| e1 :: l1, [] ->
+					loop (acc1, e1 :: acc2) l1 []
+				| e1 :: l1, e2 :: l2 ->
+					loop (e1 :: acc1, acc2) l1 l2
 			in
-			loop [] [] margs el
-		| _ -> el,[]
+			loop ([],[]) el margs
+		| _ ->
+			error "Last argument of a @:rest macro must be of Array<Expr>" p
+	else
+		el,[]
 	in
 	let args =
 		(*
@@ -2899,7 +2905,7 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p =
 	in
 	let args = match el2 with
 		| [] -> args
-		| _ -> (match List.rev args with _::args -> args | [] -> []) @ [Interp.enc_array (List.map Interp.encode_expr el2)]
+		| _ -> (match List.rev args with _::args -> List.rev args | [] -> []) @ [Interp.enc_array (List.map Interp.encode_expr el2)]
 	in
 	let call() =
 		match call_macro args with