Browse Source

[cs] unit tests fixes

Caue Waneck 12 years ago
parent
commit
eec3cf846a
8 changed files with 118 additions and 46 deletions
  1. 18 9
      gencommon.ml
  2. 7 2
      gencs.ml
  3. 5 2
      std/StringTools.hx
  4. 3 3
      std/cs/_std/Math.hx
  5. 7 4
      std/cs/_std/String.hx
  6. 5 3
      std/cs/_std/Type.hx
  7. 57 7
      std/cs/internal/Runtime.hx
  8. 16 16
      tests/unit/TestType.hx

+ 18 - 9
gencommon.ml

@@ -4886,7 +4886,7 @@ struct
           { e with eexpr = TCall(ef, [ run maybe_empty ]); }
         | TCall( { eexpr = TConst TSuper } as ef, eparams ) ->
           (* handle special distinction between EmptyConstructor vs one argument contructor *)
-          let handle = if gen.gcon.platform = Java && List.length eparams = 1 then
+          let handle = if (List.length eparams = 1) then
             (fun e t1 t2 -> mk_cast (gen.greal_type t1) e)
           else
             handle
@@ -4918,7 +4918,7 @@ struct
           { e with eexpr = TNew(cl, tparams, [ maybe_empty ]); etype = TInst(cl, tparams) }
         | TNew (cl, tparams, eparams) ->
           (* handle special distinction between EmptyConstructor vs one argument contructor *)
-          let handle = if gen.gcon.platform = Java && List.length eparams = 1 then
+          let handle = if (List.length eparams = 1) then
             (fun e t1 t2 -> mk_cast (gen.greal_type t1) e)
           else
             handle
@@ -5007,13 +5007,22 @@ struct
         | TCast (expr, md) when is_void (follow e.etype) ->
           run expr
         | TCast (expr, md) ->
-          let last_unsafe = gen.gon_unsafe_cast in
-          gen.gon_unsafe_cast <- (fun t t2 pos -> ());
-          let ret = handle (run expr) e.etype expr.etype in
-          gen.gon_unsafe_cast <- last_unsafe;
-          (match ret.eexpr with
-            | TCast _ -> ret
-            | _ -> { e with eexpr = TCast(ret,md); etype = gen.greal_type e.etype }
+          let rec get_null e =
+            match e.eexpr with
+            | TConst TNull -> Some e
+            | TParenthesis e -> get_null e
+            | _ -> None
+          in
+          (match get_null expr with
+          | Some enull -> { enull with etype = e.etype }
+          | _ ->
+            let last_unsafe = gen.gon_unsafe_cast in
+            gen.gon_unsafe_cast <- (fun t t2 pos -> ());
+            let ret = handle (run expr) e.etype expr.etype in
+            gen.gon_unsafe_cast <- last_unsafe;
+            match ret.eexpr with
+              | TCast _ -> ret
+              | _ -> { e with eexpr = TCast(ret,md); etype = gen.greal_type e.etype }
           )
         (*| TCast _ ->
           (* if there is already a cast, we should skip this cast check *)

+ 7 - 2
gencs.ml

@@ -132,7 +132,7 @@ struct
         (* Std.is() *)
         | TCall(
             { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) },
-            [ obj; { eexpr = TTypeExpr(TClassDecl { cl_path = [], "Dynamic" }) }]
+            [ obj; { eexpr = TTypeExpr(TClassDecl { cl_path = [], "Dynamic" } | TAbstractDecl { a_path = [], "Dynamic" }) }]
           ) ->
             Type.map_expr run e
         | TCall(
@@ -1892,6 +1892,11 @@ let configure gen =
       | _ -> false
   in
 
+  let string_cl = match gen.gcon.basic.tstring with
+    | TInst(c,[]) -> c
+    | _ -> assert false
+  in
+
   DynamicOperators.configure gen
     (DynamicOperators.abstract_implementation gen (fun e -> match e.eexpr with
       | TBinop (Ast.OpEq, e1, e2)
@@ -1952,7 +1957,7 @@ let configure gen =
           mk_cast e.etype { eexpr = TCall(static, [e1; e2]); etype = t_dynamic; epos=e1.epos })
     (fun e1 e2 ->
       if is_string e1.etype then begin
-        { e1 with eexpr = TCall(mk_field_access gen e1 "compareTo" e1.epos, [ e2 ]); etype = gen.gcon.basic.tint }
+        { e1 with eexpr = TCall(mk_static_field_access_infer string_cl "Compare" e1.epos [], [ e1; e2 ]); etype = gen.gcon.basic.tint }
       end else begin
         let static = mk_static_field_access_infer (runtime_cl) "compare" e1.epos [] in
         { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos }

+ 5 - 2
std/StringTools.hx

@@ -285,14 +285,17 @@ class StringTools {
 
 		If [sub] or [by] are null, the result is unspecified.
 	**/
-	public #if cs inline #end static function replace( s : String, sub : String, by : String ) : String {
+	public static function replace( s : String, sub : String, by : String ) : String {
 		#if java
 		if (sub.length == 0)
 			return s.split(sub).join(by);
 		else
 			return untyped s.replace(sub, by);
 		#elseif cs
-		return untyped s.Replace(sub, by);
+		if (sub.length == 0)
+			return s.split(sub).join(by);
+		else
+			return untyped s.Replace(sub, by);
 		#else
 		return s.split(sub).join(by);
 		#end

+ 3 - 3
std/cs/_std/Math.hx

@@ -47,12 +47,12 @@ import cs.system.Random;
 
 	public static inline function min(a:Float, b:Float):Float
 	{
-		return (a < b) ? a : b;
+		return cs.system.Math.Min(a,b);
 	}
 
 	public static inline function max(a:Float, b:Float):Float
 	{
-		return (a > b) ? a : b;
+		return cs.system.Math.Max(a,b);
 	}
 
 	public static inline function sin(v:Float):Float
@@ -155,7 +155,7 @@ import cs.system.Random;
 
 	public static function isFinite( f : Float ) : Bool
 	{
-		return untyped __cs__("!double.IsInfinity(f)");
+		return untyped __cs__("!double.IsInfinity(f) && !double.IsNaN(f)");
 	}
 
 	public static function isNaN( f : Float ) : Bool

+ 7 - 4
std/cs/_std/String.hx

@@ -24,7 +24,9 @@ import cs.StdTypes;
 /**
 	The basic String class.
 **/
-extern class String implements ArrayAccess<Char16> {
+@:coreType extern class String implements ArrayAccess<Char16> {
+
+	private static function Compare(s1:String, s2:String):Int;
 
 	/**
 		The number of characters in the String.
@@ -81,7 +83,7 @@ extern class String implements ArrayAccess<Char16> {
 		If [len] is not specified, it takes all the remaining characters.
 	**/
 	function substr( pos : Int, ?len : Int ) : String;
-	
+
 	/**
 		Returns a part of the String, taking from [startIndex] to [endIndex] - 1.
 		If [endIndex] is not specified, length is used.
@@ -96,14 +98,15 @@ extern class String implements ArrayAccess<Char16> {
 	function toString() : String;
 
 	static function fromCharCode( code : Int ) : String;
-	
+
 	private function Replace(oldValue:String, newValue:String):String;
 	private function StartsWith(value:String):Bool;
 	private function EndsWith(value:String):Bool;
 	private function TrimStart():String;
 	private function TrimEnd():String;
+	private function Trim():String;
 	private function CompareTo(obj:Dynamic):Int;
 	@:overload(function(startIndex:Int):String {})
 	private function Substring(startIndex:Int, length:Int):String;
 
-}
+}

+ 5 - 3
std/cs/_std/Type.hx

@@ -62,7 +62,7 @@ import cs.internal.Runtime;
 @:keep @:coreApi class Type {
 
 	@:functionCode('
-		if (o is haxe.lang.DynamicObject || o is System.Type)
+		if (o == null || o is haxe.lang.DynamicObject || o is System.Type)
 			return null;
 
 		return o.GetType();
@@ -174,6 +174,8 @@ import cs.internal.Runtime;
 
 	public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T
 	{
+		if (untyped cl == String)
+			return args[0];
 		var t:cs.system.Type = Lib.toNativeType(cl);
 		var ctors = t.GetConstructors();
 		return Runtime.callMethod(null, cast ctors, ctors.Length, args);
@@ -215,13 +217,13 @@ import cs.internal.Runtime;
 
 		Array<object> ret = new Array<object>();
 
-        System.Reflection.MemberInfo[] mis = c.GetMembers(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.Instance);
+        System.Reflection.MemberInfo[] mis = c.GetMembers(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy);
         for (int i = 0; i < mis.Length; i++)
         {
 			if (mis[i] is System.Reflection.PropertyInfo)
                 continue;
 			string n = mis[i].Name;
-			if (!n.StartsWith("__hx_") && n[0] != \'.\')
+			if (!n.StartsWith("__hx_") && n[0] != \'.\' && !n.Equals("Equals") && !n.Equals("ToString") && !n.Equals("GetHashCode") && !n.Equals("GetType"))
 				ret.push(mis[i].Name);
         }
 

+ 57 - 7
std/cs/internal/Runtime.hx

@@ -197,10 +197,40 @@ import cs.system.Type;
 					case System.TypeCode.String:
 						if (cv2.GetTypeCode() != System.TypeCode.String)
 							throw new System.ArgumentException("Cannot compare " + v1.GetType().ToString() + " and " + v2.GetType().ToString());
-						return v1.ToString().CompareTo(v2);
-					/*case System.TypeCode.Int64:
-					case System.TypeCode.UInt64:
-						return ((int) (cv1.ToUInt64() - cv2.ToUInt64())) no Int64 operator support */
+						string s1 = v1 as string;
+						string s2 = v2 as string;
+						int i =0;
+						int l1 = s1.Length;
+						int l2 = s2.Length;
+						bool active = true;
+						while(active)
+						{
+							char h1; char h2;
+							if (i >= l1)
+							{
+								h1 = (char) 0;
+								active = false;
+							} else {
+								h1 = s1[i];
+							}
+
+							if (i >= l2)
+							{
+								h2 = (char) 0;
+								active = false;
+							} else {
+								h2 = s2[i];
+							}
+
+							int v = h1 - h2;
+							if (v > 0)
+								return 1;
+							else if (v < 0)
+								return -1;
+
+							i++;
+						}
+						return 0;
 					case System.TypeCode.Double:
 					double d1 = (double) v1;
 					double d2 = cv2.ToDouble(null);
@@ -389,6 +419,7 @@ import cs.system.Type;
 		var length = args.length;
 		var oargs:NativeArray<Dynamic> = new NativeArray(length);
 		var ts:NativeArray<cs.system.Type> = new NativeArray(length);
+		var rates:NativeArray<Int> = new NativeArray(methods.Length);
 
 		for (i in 0...length)
 		{
@@ -408,15 +439,21 @@ import cs.system.Type;
 				if (params.Length != length) {
 					continue;
 				} else {
-					var fits = true;
+					var fits = true, crate = 0;
 					for (i in 0...params.Length)
 					{
 						var param = params[i].ParameterType;
 						var strParam = param + "";
-						if (untyped strParam.StartsWith("haxe.lang.Null") || ( (oargs[i] == null || Std.is(oargs[i], IConvertible) ) && cast(untyped __typeof__(IConvertible), Type).IsAssignableFrom(param) ))
+						if (param.IsAssignableFrom(ts[i]))
+						{
+							//if it is directly assignable, we'll give it top rate
+							continue;
+						} else if (untyped strParam.StartsWith("haxe.lang.Null") || ( (oargs[i] == null || Std.is(oargs[i], IConvertible) ) && cast(untyped __typeof__(IConvertible), Type).IsAssignableFrom(param) ))
 						{
+							//if it needs conversion, give a penalty. TODO rate penalty
+							crate++;
 							continue;
-						} else if (!param.ContainsGenericParameters && !param.IsAssignableFrom(ts[i])) {
+						} else if (!param.ContainsGenericParameters) { //generics don't appear as assignable, but may be in the end. no rate there.
 							fits = false;
 							break;
 						}
@@ -424,6 +461,7 @@ import cs.system.Type;
 
 					if (fits)
 					{
+						rates[last] = crate;
 						methods[last++] = methods[i];
 					}
 				}
@@ -442,6 +480,18 @@ import cs.system.Type;
 		if (methodLength == 0)
 			throw "Invalid calling parameters for method " + methods[0].Name;
 
+		var best = Math.POSITIVE_INFINITY;
+		var bestMethod = 0;
+		for(i in 0...methodLength)
+		{
+			if (rates[i] < best)
+			{
+				bestMethod = i;
+				best = rates[i];
+			}
+		}
+
+		methods[0] = methods[bestMethod];
 		var params = methods[0].GetParameters();
 		for (i in 0...params.Length)
 		{

+ 16 - 16
tests/unit/TestType.hx

@@ -687,7 +687,7 @@ class TestType extends Test {
 			var s:String = z;
 		}));
 	}
-	
+
 	function testOpArrow() {
 		var m = new Map<Int,Int>();
 		var map = [1 => 2, 3 => 4];
@@ -695,14 +695,14 @@ class TestType extends Test {
 		t(Std.is(map, haxe.ds.IntMap));
 		eq(map.get(1), 2);
 		eq(map.get(3), 4);
-		
+
 		var m = new Map<String,Int>();
 		var map = ["1" => 2, "3" => 4];
 		typedAs(map, m);
 		t(Std.is(map, haxe.ds.StringMap));
 		eq(map.get("1"), 2);
 		eq(map.get("3"), 4);
-		
+
 		var a = new unit.MyAbstract.ClassWithHashCode(1);
 		var b = new unit.MyAbstract.ClassWithHashCode(2);
 		var m = new Map<unit.MyAbstract.ClassWithHashCode,Int>();
@@ -711,7 +711,7 @@ class TestType extends Test {
 		//t(Std.is(map, haxe.ds.IntMap));
 		eq(map.get(a), 2);
 		eq(map.get(b), 4);
-		
+
 		// duplicate key
 		t(typeError([1 => 2, 1 => 3]));
 		// key unification
@@ -747,7 +747,7 @@ class TestType extends Test {
 		eq(map.get(b), "bar");
 		// this may be specialized
 		//t(Std.is(map, haxe.ds.ObjectMap));
-		
+
 		//var map = new unit.MyAbstract.MyMap();
 		//map.set(new haxe.Template("foo"), 99);
 		//t(Std.is(map, unit.MyAbstract.PseudoObjectHash));
@@ -764,7 +764,7 @@ class TestType extends Test {
 	}
 
 	static function _mapMe(map:Map < Int, String > ) { }
-	
+
 	function testAbstractOverload() {
 		var ms1:unit.MyAbstract.MyString = "foo";
 		var ms2:unit.MyAbstract.MyString = "bar";
@@ -772,25 +772,25 @@ class TestType extends Test {
 		eq(msum, "foobar");
 		typedAs(msum, ms1);
 		t(Std.is(msum, String));
-		
+
 		var msum2 = ms1 + 1;
 		eq(msum2, "foo1");
 		typedAs(msum2, ms1);
 		t(Std.is(msum2, String));
-		
+
 		// operation is defined, but return type is not compatible
 		t(typeError(ms1 + true));
 		// operation is not defined
 		t(typeError(ms1 - ms2));
 	}
-	
+
 	function testAbstractUnop() {
 		var vec:unit.MyAbstract.MyVector = new unit.MyAbstract.MyPoint3(1, 2, 3);
 		var vec2 = -vec;
 		t(vec2 != vec);
 		eq(vec.toString(), "(1,2,3)");
 		eq(vec2.toString(), "(-1,-2,-3)");
-		
+
 		var my = new unit.MyAbstract.MyInt2(12);
 		eq( (-my).get(), -12);
 		typedAs( -my, my);
@@ -801,7 +801,7 @@ class TestType extends Test {
 		// wrong flag
 		t(typeError(my++));
 	}
-	
+
 	function testMapComprehension() {
 		var map = [for (x in ["a", "b"]) x => x.toUpperCase()];
 		t(map.exists("a"));
@@ -809,7 +809,7 @@ class TestType extends Test {
 		eq(map.get("a"), "A");
 		eq(map.get("b"), "B");
 	}
-	
+
 	function testCustomArrayAccess() {
 		var obj = {
 			foo: 12,
@@ -825,24 +825,24 @@ class TestType extends Test {
 		mr["baz"] = mr["bar"] += mr["foo"];
 		eq(mr["baz"], "test110");
 		eq(mr["bar"], "test110");
-		
+
 		var v = "hh";
 		mr[v] = 1;
 		mr[v += "h"] = 2;
 		eq(mr["hhh"], 2);
 		eq(v, "hhh");
-		
+
 		mr["hhhh"] = 0;
 		mr[v += "h"] += 4;
 		eq(mr["hhhh"], 4);
 		eq(mr["hhh"], 2);
 		eq(v, "hhhh");
-		
+
 		// note for later: As3 compilation fails if the function name is removed
 		mr["101"] = function n(x) return 9 + x;
 		eq(mr["101"](1), 10);
 	}
-	
+
 	function testAbstractClosure() {
 		var s = new unit.MyAbstract.MyAbstractClosure("foo");
 		var func1 = s.test();