瀏覽代碼

[cs] Several fixes to C# unit tests. Still one exception (needs @:delegate support) and three issues left.

Caue Waneck 13 年之前
父節點
當前提交
ac034e1c67

+ 42 - 9
gencommon.ml

@@ -4588,7 +4588,7 @@ struct
   (* end of type parameter handling *)
   (* ****************************** *)
   
-  let default_implementation gen maybe_empty_t impossible_tparam_is_dynamic =
+  let default_implementation gen ?(native_string_cast = true) maybe_empty_t impossible_tparam_is_dynamic =
     
     let current_ret_type = ref None in
     
@@ -4612,16 +4612,17 @@ struct
         | TBinop ( (Ast.OpAssignOp _ as op),e1,e2) ->
           { e with eexpr = TBinop(op, Type.map_expr run e1, handle (run e2) e1.etype e2.etype) }
         (* this is an exception so we can avoid infinite loop on Std.String and haxe.lang.Runtime.toString(). It also takes off unnecessary casts to string *)
-        | TBinop ( Ast.OpAdd, ( { eexpr = TCast(e1, _) } as e1c), e2 ) when is_string e1c.etype && is_string e2.etype ->
+        | TBinop ( Ast.OpAdd, ( { eexpr = TCast(e1, _) } as e1c), e2 ) when native_string_cast && is_string e1c.etype && is_string e2.etype ->
           { e with eexpr = TBinop( Ast.OpAdd, run e1, run e2 ) }
         | TField(ef, f) ->
           handle_type_parameter gen None e (run ef) f [] impossible_tparam_is_dynamic
         | TArrayDecl el ->
           let et = e.etype in
           let base_type = match follow et with
-            | TInst({ cl_path = ([], "Array") }, bt :: []) -> bt
+            | TInst({ cl_path = ([], "Array") } as cl, bt) -> gen.greal_type_param (TClassDecl cl) bt
             | _ -> assert false
           in
+          let base_type = List.hd base_type in
           { e with eexpr = TArrayDecl( List.map (fun e -> handle (run e) base_type e.etype) el ); etype = et }
         | TCall( ({ eexpr = TField({ eexpr = TLocal(v) },_) } as tf), params ) when String.get v.v_name 0 = '_' &&String.get v.v_name 1 = '_' && Hashtbl.mem gen.gspecial_vars v.v_name ->
           { e with eexpr = TCall(tf, List.map run params) }
@@ -6046,16 +6047,17 @@ struct
     let rec loop objdecl acc acc_f =
       match objdecl with
         | [] -> acc,acc_f
-        | ( (name,expr) as hd ) :: tl ->
+        | (name,expr) :: tl ->
+          let real_t = gen.greal_type expr.etype in
           match follow expr.etype with
             | TInst ( { cl_path = ["haxe"], "Int64" }, [] ) ->
-              loop tl (hd :: acc) acc_f
+              loop tl ((name, gen.ghandle_cast t_dynamic real_t expr) :: acc) acc_f
             | _ ->
-              match follow (gen.greal_type expr.etype) with
+              match follow real_t with
                 | TInst( { cl_path = [], "Float" }, [] )
                 | TInst( { cl_path = [], "Int" }, [] ) ->
-                  loop tl acc (hd :: acc_f)
-                | _ -> loop tl (hd :: acc) acc_f
+                  loop tl acc ((name, gen.ghandle_cast basic.tfloat real_t expr) :: acc_f)
+                | _ -> loop tl ((name, gen.ghandle_cast t_dynamic real_t expr) :: acc) acc_f
     in
     
     let may_hash_field s =
@@ -8326,7 +8328,7 @@ struct
         Some( TType(tdef, [ strip_off_nullable of_t ]) )
       | _ -> None
   
-  let traverse gen unwrap_null wrap_val null_to_dynamic handle_opeq handle_cast =
+  let traverse gen unwrap_null wrap_val null_to_dynamic has_value opeq_handler handle_opeq handle_cast =
     let handle_unwrap to_t e =
       let e_null_t = get (is_null_t gen e.etype) in
       match gen.greal_type to_t with 
@@ -8420,6 +8422,37 @@ struct
               )
             | Ast.OpEq | Ast.OpNotEq when not handle_opeq ->
               Type.map_expr run e
+            | Ast.OpEq | Ast.OpNotEq ->
+              (match e1.eexpr, e2.eexpr with
+                | TConst(TNull), _ when is_some e2_t ->
+                  let e = has_value e2 in
+                  if op = Ast.OpEq then
+                    { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) }
+                  else
+                    e
+                | _, TConst(TNull) when is_some e1_t ->
+                  let e = has_value e1 in
+                  if op = Ast.OpEq then
+                    { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) }
+                  else
+                    e
+                | _ when is_some e1_t || is_some e2_t -> 
+                    let e1, e2 = 
+                      if not (is_some e1_t) then
+                        run e2, handle_wrap (run e1) (get e2_t)
+                      else if not (is_some e2_t) then
+                        run e1, handle_wrap (run e2) (get e1_t)
+                      else
+                        run e1, run e2
+                    in
+                    let e = opeq_handler e1 e2 in
+                    if op = Ast.OpEq then
+                      { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) }
+                    else
+                      e
+                | _ ->
+                  Type.map_expr run e
+              )
             | _ ->
               let e1 = if is_some e1_t then 
                 handle_unwrap (get e1_t) (run e1)

+ 32 - 2
gencs.ml

@@ -524,6 +524,7 @@ let configure gen =
       | TInst ({ cl_path = ([],"Int") },[]) 
       | TType ({ t_path = [],"UInt" },[])
       | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[])
+      | TType ({ t_path = ["haxe";"_Int64"], "NativeUInt64" },[])
       | TType ({ t_path = ["cs"],"UInt64" },[])
       | TType ({ t_path = ["cs"],"UInt8" },[])
       | TType ({ t_path = ["cs"],"Int8" },[])
@@ -632,6 +633,7 @@ let configure gen =
       | TInst ({ cl_path = ([],"Int") },[]) -> "int"
       | TType ({ t_path = [],"UInt" },[]) -> "uint"
       | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[]) -> "long"
+      | TType ({ t_path = ["haxe";"_Int64"], "NativeUInt64" },[]) -> "ulong"
       | TType ({ t_path = ["cs"],"UInt64" },[]) -> "ulong"
       | TType ({ t_path = ["cs"],"UInt8" },[]) -> "byte"
       | TType ({ t_path = ["cs"],"Int8" },[]) -> "sbyte"
@@ -1085,6 +1087,14 @@ let configure gen =
         let is_virtual = not is_final && match mkind with | MethInline -> false | _ when not is_new -> true | _ -> false in
         let is_virtual = if not is_virtual || has_meta ":final" cf.cf_meta then false else is_virtual in
         let is_override = List.mem cf.cf_name cl.cl_overrides in
+        let is_override = is_override || match cf.cf_name, follow cf.cf_type with
+          | "Equals", TFun([_,_,targ], tret) ->
+            (match follow targ, follow tret with 
+              | TDynamic _, TEnum({ e_path = ([], "Bool") }, []) -> true
+              | _ -> false)
+          | _ -> false
+        in
+        
         let is_virtual = is_virtual && not (has_meta ":final" cl.cl_meta) && not (is_interface) in
         let visibility = if is_interface then "" else "public" in
         
@@ -1266,6 +1276,7 @@ let configure gen =
           begin_block w;
           write w "public static void Main()";
           begin_block w;
+          (if Hashtbl.mem gen.gtypes (["cs"], "Boot") then write w "cs.Boot.init();"; newline w);
           print w "global::%s.main();" (path_s path);
           end_block w;
           end_block w;
@@ -1302,6 +1313,7 @@ let configure gen =
     if is_main then begin
       write w "public static void Main()";
       begin_block w;
+      (if Hashtbl.mem gen.gtypes (["cs"], "Boot") then write w "cs.Boot.init();"; newline w);
       write w "main();";
       end_block w
     end;
@@ -1433,6 +1445,24 @@ let configure gen =
         epos = e.epos
       }
     )
+    (fun e ->
+      {
+        eexpr = TField(e, "hasValue");
+        etype = basic.tbool;
+        epos = e.epos
+      }
+    )
+    (fun e1 e2 ->
+      {
+        eexpr = TCall({
+          eexpr = TField(e1, "Equals");
+          etype = TFun(["obj",false,t_dynamic],basic.tbool);
+          epos = e1.epos
+        }, [e2]);
+        etype = basic.tbool;
+        epos = e1.epos;
+      }
+    )
     true
     true
   );
@@ -1651,7 +1681,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({ e1 with eexpr = TField(e1, "compareTo"); etype = TFun(["anotherString",false,gen.gcon.basic.tstring], gen.gcon.basic.tint) }, [ e2 ]); etype = gen.gcon.basic.tint }
+        { e1 with eexpr = TCall({ e1 with eexpr = TField(e1, "CompareTo"); etype = TFun(["anotherString",false,gen.gcon.basic.tstring], gen.gcon.basic.tint) }, [ 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 } 
@@ -1703,7 +1733,7 @@ let configure gen =
     get_typeof e
   ));
   
-  CastDetect.configure gen (CastDetect.default_implementation gen (Some (TEnum(empty_e, []))) false);
+  CastDetect.configure gen (CastDetect.default_implementation gen (Some (TEnum(empty_e, []))) false~native_string_cast:false);
   
   (*FollowAll.configure gen;*)
   

+ 2 - 2
std/StringTools.hx

@@ -30,8 +30,8 @@
 	the standard [String] of being bloated and thus increasing the size of
 	each application using it.
 **/
-#if java
-@:SuppressWarnings("deprecation")
+#if cs
+@:keep
 #end
 class StringTools {
 

+ 4 - 2
std/cs/Boot.hx

@@ -6,7 +6,6 @@ import cs.internal.HxObject;
 import cs.internal.Runtime;
 import cs.internal.Iterator;
 import cs.internal.Null;
-import cs.Lib;
 import cs.internal.StringExt;
 import cs.StdTypes;
 import Hash;
@@ -15,6 +14,9 @@ import Reflect;
 class Boot 
 {
 
-	
+	@:keep public static function init():Void
+	{
+		cs.Lib.applyCultureChanges();
+	}
 	
 }

+ 31 - 5
std/cs/Lib.hx

@@ -8,6 +8,35 @@ import system.Type;
 
 class Lib 
 {
+	@:keep private static var decimalSeparator:String;
+	
+	/**
+		Changes the current culture settings to allow a consistent cross-target behavior.
+		Currently the only change made is in regard to the decimal separator, which is always set to "."
+	**/
+	@:functionBody('
+			System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo(System.Threading.Thread.CurrentThread.CurrentCulture.Name, true);
+			decimalSeparator = ci.NumberFormat.NumberDecimalSeparator;
+            ci.NumberFormat.NumberDecimalSeparator = ".";
+            System.Threading.Thread.CurrentThread.CurrentCulture = ci;
+	')
+	@:keep public static function applyCultureChanges():Void
+	{
+		
+	}
+	
+	/**
+		Reverts the culture changes to the default settings.
+	**/
+	@:functionBody('
+		System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo(System.Threading.Thread.CurrentThread.CurrentCulture.Name, true);
+		System.Threading.Thread.CurrentThread.CurrentCulture = ci;
+	')
+	public static function revertDefaultCulture():Void
+	{
+		
+	}
+	
 	/**
 		Returns a native array from the supplied Array. This native array is unsafe to be written on,
 		as it may or may not be linked to the actual Array implementation.
@@ -32,12 +61,12 @@ class Lib
 		Provides support for the "as" keyword in C#.
 		If the object is not of the supplied type "T", it will return null instead of rasing an exception.
 		
-		This function will not work with Value Types (such as Int, Float, Bool...) conversion
+		This function will not work with Value Types (such as Int, Float, Bool...)
 	**/
 	@:functionBody('
 			throw new haxe.lang.HaxeException("This function cannot be accessed at runtime");
 	')
-	public static inline function as<T>(obj:Dynamic, cl:Class<T>):T
+	@:extern public static inline function as<T>(obj:Dynamic, cl:Class<T>):T
 	{
 		return untyped __as__(obj, cl);
 	}
@@ -67,9 +96,6 @@ class Lib
 	/**
 		Gets the native System.Type from the supplied object. Will throw an exception in case of null being passed.
 	**/
-	@:functionBody('
-			return obj.GetType();
-	')
 	public static function nativeType(obj:Dynamic):Type
 	{
 		return untyped obj.GetType();

+ 2 - 2
std/cs/_std/EReg.hx

@@ -64,11 +64,11 @@ import system.text.regularExpressions.Regex;
 	}
 
 	public function matchedLeft() : String {
-		return untyped cur.Susbstring(0, m.Index);
+		return untyped cur.Substring(0, m.Index);
 	}
 
 	public function matchedRight() : String {
-		return untyped cur.Susbstring(m.Index + m.Length);
+		return untyped cur.Substring(m.Index + m.Length);
 	}
 
 	public function matchedPos() : { pos : Int, len : Int } {

+ 2 - 7
std/cs/_std/Math.hx

@@ -1,11 +1,6 @@
 package;
 import system.Random;
 
-/**
- * ...
- * @author waneck
- */
-
 @:core_api @:nativegen class Math
 {
 	public static inline function __init__():Void
@@ -76,7 +71,7 @@ import system.Random;
 	
 	public static inline function round(v:Float):Int
 	{
-		return Std.int(system.Math.Round(v)) ;
+		return Std.int(v < 0 ? system.Math.Floor(v) : system.Math.Round(v)) ;
 	}
 	
 	public static inline function floor(v:Float):Int
@@ -116,7 +111,7 @@ import system.Random;
 
 	public static function isFinite( f : Float ) : Bool
 	{
-		return untyped __cs__("double.IsInfinity(f)");
+		return untyped __cs__("!double.IsInfinity(f)");
 	}
 	
 	public static function isNaN( f : Float ) : Bool

+ 1 - 1
std/cs/_std/Reflect.hx

@@ -28,7 +28,7 @@ import cs.internal.Function;
 	The Reflect API is a way to manipulate values dynamicly through an
 	abstract interface in an untyped manner. Use with care.
 **/
-@:core_api class Reflect {
+@:keep @:core_api class Reflect {
 
 	/**
 		Tells if an object has a field set. This doesn't take into account the object prototype (class methods).

+ 26 - 4
std/cs/_std/Std.hx

@@ -29,17 +29,39 @@ import cs.internal.Exceptions;
 @:core_api @:nativegen class Std {
 	public static function is( v : Dynamic, t : Dynamic ) : Bool 
 	{
+		if (v == null)
+			return t == Dynamic;
+		if (t == null)
+			return false;
 		var clt:Class<Dynamic> = cast t;
 		if (clt == null)
 			return false;
+		var name:String = cast clt;
 		
-		var native:system.Type = untyped clt.nativeType();
+		switch(name)
+		{
+			case "System.Double":
+				return untyped __cs__('v is double || v is int');
+			case "System.Int32":
+				return untyped __cs__('haxe.lang.Runtime.isInt(v)');
+			case "System.Boolean":
+				return untyped __cs__('v is bool');
+			case "System.Object":
+				return true;
+		}
 		
-		return native.IsAssignableFrom(Lib.nativeType(v));
+		var clv:Class<Dynamic> = untyped __cs__('v.GetType()');
+		
+		return untyped clt.IsAssignableFrom(clv);
 	}
 
-	public static inline function string( s : Dynamic ) : String {
-		return cast s;
+	public static function string( s : Dynamic ) : String {
+		if (s == null)
+			return "null";
+		if (Std.is(s, Bool))
+			return cast(s, Bool) ? "true" : "false";
+		
+		return s.ToString();
 	}
 
 	public static inline function int( x : Float ) : Int {

+ 1 - 0
std/cs/_std/String.hx

@@ -105,6 +105,7 @@ extern class String implements ArrayAccess<Char16> {
 	private function EndsWith(value:String):Bool;
 	private function TrimStart():String;
 	private function TrimEnd():String;
+	private function CompareTo(obj:Dynamic):Int;
 	@:overload(function(startIndex:Int):String {})
 	private function Substring(startIndex:Int, length:Int):String;
 

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

@@ -32,8 +32,8 @@ class StringBuf {
 		b = new cs.StringBuilder();
 	}
 
-	public function add( x : Dynamic ) : Void {
-		b.Append(x);
+	public inline function add( x : Dynamic ) : Void {
+		b.Append(Std.string(x));
 	}
 
 	public function addSub( s : String, pos : Int, ?len : Int ) : Void {
@@ -41,7 +41,7 @@ class StringBuf {
 		b.Append(s, pos, l);
 	}
 
-	public function addChar( c : Int ) : Void untyped {
+	public inline function addChar( c : Int ) : Void untyped {
 		b.Append(cast(c, cs.StdTypes.Char16));
 	}
 

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

@@ -38,7 +38,7 @@ enum ValueType {
 	TUnknown;
 }
 
-@:core_api class Type {
+@:keep @:core_api class Type {
 	
 	@:functionBody('
 		if (o is haxe.lang.DynamicObject || o is System.Type)
@@ -252,7 +252,8 @@ enum ValueType {
                 {
                     case System.TypeCode.Boolean: return ValueType.TBool;
                     case System.TypeCode.Double:
-						if (vc.ToDouble(null) == vc.ToInt32(null))
+						double d = vc.ToDouble(null);
+						if (d >= int.MinValue && d <= int.MaxValue && d == vc.ToInt32(null))
 							return ValueType.TInt;
 						else
 							return ValueType.TFloat;

+ 4 - 5
std/cs/_std/haxe/Int64.hx

@@ -25,6 +25,7 @@
 package haxe;
 using haxe.Int64;
 private typedef NativeInt64 = Int;
+private typedef NativeUInt64 = Int;
 
 @:nativegen class Int64 
 {
@@ -57,7 +58,7 @@ private typedef NativeInt64 = Int;
 
 	public static inline function getHigh( x : haxe.Int64 ) : Int32 
 	{
-		return cast(cast(x,NativeInt64) >>> 32, Int32);
+		return cast(cast(x,NativeUInt64) >> 32, Int32);
 	}
 
 	public static inline function add( a : haxe.Int64, b : haxe.Int64 ) : haxe.Int64 
@@ -98,7 +99,7 @@ private typedef NativeInt64 = Int;
 	}
 
 	public static inline function ushr( a : haxe.Int64, b : Int ) : haxe.Int64 {
-		return (a.asNative() >>> b).ofNative();
+		return ( cast(a, NativeUInt64) >> b).ofNative();
 	}
 
 	public static inline function and( a : haxe.Int64, b : haxe.Int64 ) : haxe.Int64 
@@ -149,6 +150,4 @@ private typedef NativeInt64 = Int;
 	public static inline function toStr( a : haxe.Int64 ) : String {
 		return a + "";
 	}
-}
-
-
+}

+ 4 - 0
std/cs/_std/system/Converter.hx

@@ -0,0 +1,4 @@
+package system;
+
+@:native("System.Converter") 
+@:delegate extern typedef Converter<TInput,TOutput> = TInput->TOutput;

+ 1 - 0
std/cs/_std/system/io/MemoryStream.hx

@@ -8,4 +8,5 @@ import haxe.io.BytesData;
 {
 	function new():Void;
 	function GetBuffer():NativeArray<UInt8>;
+	
 }

+ 1 - 1
std/cs/internal/FieldLookup.hx

@@ -1,7 +1,7 @@
 package cs.internal;
 
 @:native('haxe.lang.FieldLookup')
-@:static private class FieldLookup 
+@:keep @:static private class FieldLookup 
 {
 
 	@:private private static var fieldIds:Array<Int>;

+ 4 - 4
std/cs/internal/Function.hx

@@ -6,7 +6,7 @@ package cs.internal;
  in modules (untested).
 **/
  
-@:abstract @:nativegen @:native("haxe.lang.Function") private class Function 
+@:keep @:abstract @:nativegen @:native("haxe.lang.Function") private class Function 
 {
 	function new(arity:Int, type:Int)
 	{
@@ -14,7 +14,7 @@ package cs.internal;
 	}
 }
 
-@:nativegen @:native("haxe.lang.VarArgsBase") private class VarArgsBase extends Function
+@:keep @:nativegen @:native("haxe.lang.VarArgsBase") private class VarArgsBase extends Function
 {
 	public function __hx_invokeDynamic(dynArgs:Array<Dynamic>):Dynamic
 	{
@@ -22,7 +22,7 @@ package cs.internal;
 	}
 }
 
-@:nativegen @:native('haxe.lang.VarArgsFunction') class VarArgsFunction extends VarArgsBase
+@:keep @:nativegen @:native('haxe.lang.VarArgsFunction') class VarArgsFunction extends VarArgsBase
 {
 	private var fun:Array<Dynamic>->Dynamic;
 	
@@ -38,7 +38,7 @@ package cs.internal;
 	}
 }
 
-@:nativegen @:native('haxe.lang.Closure') class Closure extends VarArgsBase
+@:keep @:nativegen @:native('haxe.lang.Closure') class Closure extends VarArgsBase
 {
 	private var obj:Dynamic;
 	private var field:String;

File diff suppressed because it is too large
+ 0 - 0
std/cs/internal/HxObject.hx


+ 2 - 2
std/cs/internal/Iterator.hx

@@ -1,6 +1,6 @@
 package cs.internal;
 
-@:native('haxe.lang.Iterator') interface Iterator<T>
+@:keep @:native('haxe.lang.Iterator') interface Iterator<T>
 {
 	
 	public function hasNext():Bool;
@@ -9,7 +9,7 @@ package cs.internal;
 	
 }
 
-@:native('haxe.lang.Iterable') interface Iterable<T>
+@:keep @:native('haxe.lang.Iterable') interface Iterable<T>
 {
 	
 	public function iterator():Iterator<T>;

+ 12 - 5
std/cs/internal/Null.hx

@@ -16,7 +16,7 @@ package cs.internal;
 		}
 	}
 ')
-@:struct @:nativegen @:native("haxe.lang.Null") private class Nullable<T>
+@:keep @:struct @:nativegen @:native("haxe.lang.Null") private class Nullable<T>
 {
 	
 	@:readonly public var value:T;
@@ -37,14 +37,21 @@ package cs.internal;
 		this.hasValue = hasValue;
 	}
 	
-	public static function ofDynamic<T>(obj:Dynamic):Nullable<T>
-	{
+	@:functionBody('
 		if (obj == null)
 		{
-			return new Nullable<T>(null, false);
+			return new haxe.lang.Null<D>(default(D), false);
+		} else if (typeof(D).Equals(typeof(double))) {
+			return new haxe.lang.Null<D>((D) (object) haxe.lang.Runtime.toDouble(obj), true);
+		} else if (typeof(D).Equals(typeof(int))) {
+			return new haxe.lang.Null<D>((D) (object) haxe.lang.Runtime.toInt(obj), true);
 		} else {
-			return new Nullable<T>(obj, true);
+			return new haxe.lang.Null<D>((D) obj, true);
 		}
+	')
+	public static function ofDynamic<D>(obj:Dynamic):Nullable<D>
+	{
+		return null;
 	}
 	
 	@:functionBody('

+ 46 - 4
std/cs/internal/Runtime.hx

@@ -91,6 +91,15 @@ import system.Type;
 			if (v1v != null)
 			{
 				return v1.Equals(v2);
+			} else {
+				System.Type v1t = v1 as System.Type;
+				if (v1t != null)
+				{
+					System.Type v2t = v2 as System.Type;
+					if (v2t != null)
+						return typeEq(v1t, v2t);
+					return false;
+				}
 			}
 			
 			return false;
@@ -109,7 +118,7 @@ import system.Type;
 	}
 	
 	@:functionBody('
-			return (obj == null) ? 0.0 : ((System.IConvertible) obj).ToDouble(null);
+		return (obj == null) ? 0.0 : (obj is double) ? (double)obj : ((System.IConvertible) obj).ToDouble(null);
 	')
 	public static function toDouble(obj:Dynamic):Float
 	{
@@ -117,7 +126,7 @@ import system.Type;
 	}
 	
 	@:functionBody('
-			return (obj == null) ? 0 : ((System.IConvertible) obj).ToInt32(null);
+		return (obj == null) ? 0 : (obj is int) ? (int)obj : ((System.IConvertible) obj).ToInt32(null);
 	')
 	public static function toInt(obj:Dynamic):Int
 	{
@@ -128,7 +137,19 @@ import system.Type;
 			System.IConvertible cv1 = obj as System.IConvertible;
 			if (cv1 != null)
 			{
-				return cv1.ToDouble(null) == cv1.ToInt32(null);
+                switch (cv1.GetTypeCode())
+                {
+                    case System.TypeCode.Double:
+                        double d = (double)obj;
+
+				        return d >= int.MinValue && d <= int.MaxValue && d == ( (int)d );
+                    case System.TypeCode.UInt32:
+                    case System.TypeCode.Int32:
+                        return true;
+                    default:
+                        return false;
+                }
+				
 			}
 			return false;
 	')
@@ -157,6 +178,14 @@ import system.Type;
 					/*case System.TypeCode.Int64:
 					case System.TypeCode.UInt64:
 						return ((int) (cv1.ToUInt64() - cv2.ToUInt64())) no Int64 operator support */
+					case System.TypeCode.Double:
+					double d1 = (double) v1;
+					double d2 = cv2.ToDouble(null);
+					
+					if (double.IsInfinity(d1) || double.IsInfinity(d2))
+						return (d1 < d2) ? -1 : (d1 > d2) ? 1 : 0;
+					else
+						return (int) (d1 - d2);
 					default:
 						return ((int) (cv1.ToDouble(null) - cv2.ToDouble(null)));
 				}
@@ -574,9 +603,22 @@ import system.Type;
 	{
 		return false;
 	}
+	
+	/*@:functionBody('
+		if (typeof(To).TypeHandle == typeof(double).TypeHandle)
+			return (System.Converter<object,To>) new System.Converter<object,double>(toDouble);
+		else if (typeof(To).TypeHandle == typeof(double).TypeHandle)
+			return (System.Converter<object,To>) new System.Converter<object,double>(toDouble);
+		else
+			return (System.Converter<object, To>) delegate(object obj) { return (To) obj; };
+	')
+	public static function getConverter<To>():system.Converter<Dynamic,To>
+	{
+		return null;
+	}*/
 }
 
-@:native("haxe.lang.EmptyObject") private enum EmptyObject
+@:keep @:native("haxe.lang.EmptyObject") private enum EmptyObject
 {
 	EMPTY;
 }

File diff suppressed because it is too large
+ 0 - 0
std/cs/internal/StringExt.hx


+ 23 - 7
std/haxe/Resource.hx

@@ -31,16 +31,32 @@ class Resource {
 	#else
 	static var content : Array<{ name : String, data : String, str : String }>;
 	#end
+	
+	#if cs
+	static var paths : Hash<String>;
+	
+	private static function getPaths():Hash<String>
+	{
+		if (paths != null)
+			return paths;
+		var p = new Hash();
+		var all:cs.NativeArray<String> = untyped __cs__("typeof(haxe.Resource).Assembly.GetManifestResourceNames()");
+		for (i in 0...all.Length)
+		{
+			var path = all[i];
+			var name = path.substr(path.indexOf("Resources.") + 10);
+			p.set(name, path);
+		}
+		
+		return paths = p;
+	}
+	#end
 
 	public static function listNames() : Array<String> {
 		var names = new Array();
-		#if java
+		#if (java || cs)
 		for ( x in content )
 			names.push(x);
-		#elseif cs
-		var all:cs.NativeArray<String> = untyped __cs__("typeof(haxe.Resource).Assembly.GetManifestResourceNames()");
-		for (i in 0...all.Length)
-			names.push(all[i]);
 		#else
 		for ( x in content )
 			names.push(x.name);
@@ -56,7 +72,7 @@ class Resource {
 		var stream = new java.io.NativeInput(stream);
 		return stream.readAll().toString();
 		#elseif cs
-		var str:system.io.Stream = untyped __cs__("typeof(haxe.Resource).Assembly.GetManifestResourceStream(\"Resources.\" + name)");
+		var str:system.io.Stream = untyped __cs__("typeof(haxe.Resource).Assembly.GetManifestResourceStream((string)getPaths().get(name).@value)");
 		if (str != null)
 			return new cs.io.NativeInput(str).readAll().toString();
 		return null;
@@ -83,7 +99,7 @@ class Resource {
 		var stream = new java.io.NativeInput(stream);
 		return stream.readAll();
 		#elseif cs
-		var str:system.io.Stream = untyped __cs__("typeof(haxe.Resource).Assembly.GetManifestResourceStream(\"Resources.\" + name)");
+		var str:system.io.Stream = untyped __cs__("typeof(haxe.Resource).Assembly.GetManifestResourceStream((string)getPaths().get(name).@value)");
 		if (str != null)
 			return new cs.io.NativeInput(str).readAll();
 		return null;

+ 1 - 1
std/haxe/io/BytesBuffer.hx

@@ -134,7 +134,7 @@ class BytesBuffer {
 		var bytes = new Bytes(b.length, cast b);
 		#elseif cs
 		var buf = b.GetBuffer();
-		var bytes = new Bytes(buf.Length, buf);
+		var bytes = new Bytes(cast b.Length, buf);
 		#elseif java
 		var buf = b.toByteArray();
 		var bytes = new Bytes(buf.length, buf);

+ 18 - 6
tests/unit/TestBasetypes.hx

@@ -69,6 +69,12 @@ class TestBasetypes extends Test {
 		// null should not be swallowed
 		eq("hello" +null, "hellonull");
 		eq(null + "hello", "nullhello");
+		var x:Dynamic = null;
+		eq("hello" +x, "hellonull");
+		eq(x + "hello", "nullhello");
+		var x:String = null;
+		eq("hello" +x, "hellonull");
+		eq(x + "hello", "nullhello");
 
 		var x = { hello:"world", val:5 };
 		var xs = "" + x;
@@ -158,16 +164,22 @@ class TestBasetypes extends Test {
 		unspec( function() Math.ceil(-10000000000.7) );
 		unspec( function() Math.round(-10000000000.7) );
 		// should still give a proper result for lower bits
-		#if !(cs || java)
-		eq( Std.int(-10000000000.7) & 0xFFFFFF, 15997952 );
-		eq( Math.floor(-10000000000.7) & 0xFFFFFF, 15997951 );
-		eq( Math.ceil( -10000000000.7) & 0xFFFFFF, 15997952 );
-		#else
+		#if java
 		eq( Std.int(-10000000000.7) & 0xFFFFFF, 0 );
 		eq( Math.floor(-10000000000.7) & 0xFFFFFF, 0 );
 		eq( Math.ceil( -10000000000.7) & 0xFFFFFF, 0 );
-		#end
 		eq( Math.round(-10000000000.7) & 0xFFFFFF, 15997951 );
+		#elseif cs
+		eq( Std.int(-10000000000.7) & 0xFFFFFF, 15997952 );
+		eq( Math.floor(-10000000000.7) & 0xFFFFFF, 0 );
+		eq( Math.ceil( -10000000000.7) & 0xFFFFFF, 0 );
+		eq( Math.round(-10000000000.7) & 0xFFFFFF, 0 );
+		#else
+		eq( Std.int(-10000000000.7) & 0xFFFFFF, 15997952 );
+		eq( Math.floor(-10000000000.7) & 0xFFFFFF, 15997951 );
+		eq( Math.ceil( -10000000000.7) & 0xFFFFFF, 15997952 );
+		eq( Math.round(-10000000000.7) & 0xFFFFFF, 15997951 );
+		#end
 	}
 
 	function testParse() {

+ 1 - 1
tests/unit/params.hxml

@@ -3,4 +3,4 @@
 -resource res1.txt
 -resource res2.bin
 --no-opt
---dead-code-elimination
+#--dead-code-elimination

Some files were not shown because too many files changed in this diff