소스 검색

allow KwArgs after VarArgs, allow passing null for VarArgs and KwArgs (fixes problem when they are optional arguments and become null implicitly

frabbit 11 년 전
부모
커밋
a5d8dc6699
4개의 변경된 파일70개의 추가작업 그리고 7개의 파일을 삭제
  1. 12 3
      genpy.ml
  2. 1 1
      std/python/KwArgs.hx
  3. 1 3
      std/python/Lib.hx
  4. 56 0
      tests/unit/TestPython.hx

+ 12 - 3
genpy.ml

@@ -1048,17 +1048,21 @@ module Printer = struct
 	let print_args args p =
 		let had_value = ref false in
 		let had_var_args = ref false in
+		let had_kw_args = ref false in
 		let sl = List.map (fun (v,cto) ->
-			if !had_var_args then error "Arguments after KwArgs/VarArgs are not allowed" p;
+			let check_err () = if !had_var_args || !had_kw_args then error "Arguments after KwArgs/VarArgs are not allowed" p in
 			let name = handle_keywords v.v_name in
 			match follow v.v_type with
 				| TAbstract({a_path = ["python"],"KwArgs"},_) ->
-					had_var_args := true;
+					if !had_kw_args then error "Arguments after KwArgs are not allowed" p;
+					had_kw_args := true;
 					"**" ^ name
 				| TAbstract({a_path = ["python"],"VarArgs"},_) ->
+					check_err ();
 					had_var_args := true;
 					"*" ^ name
 				| _ ->
+					check_err ();
 					name ^ match cto with
 						| None when !had_value -> " = None"
 						| None -> ""
@@ -1511,6 +1515,11 @@ module Printer = struct
 
 	and print_call_args pctx e1 el =
 		let print_arg pctx i x =
+			let e = match x.eexpr, follow x.etype with
+				| TConst TNull, TAbstract({a_path = ["python"],"KwArgs"},_) -> "{}"
+				| TConst TNull, TAbstract({a_path = ["python"],"VarArgs"},_) -> "[]"
+				| _ -> (print_expr pctx x)
+			in
 			let prefix = match e1.eexpr, follow x.etype with
 				(* the should not apply for the instance methods of the abstract itself *)
 				| TField(_, FStatic({cl_path = ["python"; "_KwArgs"],"KwArgs_Impl_"},f)), _ when i == 0 && Meta.has Meta.Impl f.cf_meta -> ""
@@ -1519,7 +1528,7 @@ module Printer = struct
 				| _, TAbstract({a_path = ["python"],"VarArgs"},_) -> "*"
 				| _, _ -> ""
 			in
-			prefix ^ (print_expr pctx x)
+			prefix ^ e
 		in
 		String.concat "," (ExtList.List.mapi (print_arg pctx) el)
 

+ 1 - 1
std/python/KwArgs.hx

@@ -7,7 +7,7 @@ abstract KwArgs (Dict<String, Dynamic>)
 {
 	inline function new (d:Dict<String, Dynamic>) this = d;
 
-	@:to inline function toDict ():Dict<String, Dynamic>
+	@:to public inline function toDict ():Dict<String, Dynamic>
 	{
 		return this;
 	}

+ 1 - 3
std/python/Lib.hx

@@ -26,12 +26,10 @@ class Lib {
 	public static function dictToAnon (v:Dict<String, Dynamic>):Dynamic
 	{
 		return new AnonObject(v.copy());
-
-		//return o;
 	}
 
 
-	public static function anonToDict (o:{}):Dynamic
+	public static function anonToDict (o:{}):Dict<String, Dynamic>
 	{
 		return if (HxBuiltin.isinstance(o, AnonObject))
 		{

+ 56 - 0
tests/unit/TestPython.hx

@@ -241,7 +241,61 @@ class TestPython extends Test {
 		eq(3, res);
 	}
 
+	function testKwArgsAfterVarArgs () {
+		function test (va:VarArgs, kw:KwArgs) {
+			var a = va.toArray();
+
+			eq(1,a[0]);
+			eq(2,a[1]);
+			eq(1,kw.get("a", null));
+		}
+		var a = python.Lib.anonToDict({ "a" : 1});
+		var x = [1,2];
+		test(x,a);
+	}
+
+	function testOptionalVarArgs () {
+		function test (?va:VarArgs, ?kw:KwArgs) {
+			var a = va.toArray();
+
+			eq(0,a.length);
+		}
+		test();
+	}
+
+	function testOptionalKwArgs () {
+		function test (?kw:KwArgs) eq(0,kw.toDict().length());
+		test();
+	}
+
+	function testOptionalKwArgsAfterOptionalVarArgs () {
+		function test (?va:VarArgs, ?kw:KwArgs) {
+			var a = va.toArray();
+
+			eq(1,a[0]);
+			eq(2,a[1]);
+
+			eq(0, kw.toDict().length());
+		}
+		var x = [1,2];
+		test(x);
+
+
+
+		function test (?va:VarArgs, ?kw:KwArgs) {
+			var a = va.toArray();
+			eq(0,a.length);
+			eq(1, kw.get("a",null));
+		}
+
+		var a = python.Lib.anonToDict({ "a" : 1});
+
+		test(a);
+	}
+
 	function testKwArgs () {
+
+
 		function x (args:KwArgs) {
 			var a = args.get("a", 0);
 			var b = args.get("b", 0);
@@ -336,6 +390,8 @@ class TestPython extends Test {
 		eq(t.length, 2);
 	}
 
+
+
 	function testExtern()
 	{
 		eq(new ExternClass().f(1), 2);