Browse Source

[cs] Added cs.Ref / cs.Out implementations . Started unsafe implementations

Caue Waneck 13 years ago
parent
commit
9bf0a5059b
8 changed files with 261 additions and 12 deletions
  1. 50 6
      gencs.ml
  2. 90 1
      std/cs/Lib.hx
  3. 9 0
      std/cs/Out.hx
  4. 28 0
      std/cs/Pointer.hx
  5. 9 0
      std/cs/Ref.hx
  6. 0 5
      std/java/lang/Number.hx
  7. 3 0
      tests/unit/Test.hx
  8. 72 0
      tests/unit/TestCSharp.hx

+ 50 - 6
gencs.ml

@@ -545,6 +545,8 @@ let configure gen =
       | TType ({ t_path = ["cs"],"Int16" },[])
       | TType ({ t_path = ["cs"],"UInt16" },[]) 
       | TType ({ t_path = ["cs"],"Char16" },[])
+      | TType ({ t_path = ["cs"],"Ref" },_)
+      | TType ({ t_path = ["cs"],"Out" },_)
       | TType ({ t_path = [],"Single" },[]) -> Some t
 			| TInst( { cl_path = ([], "EnumValue") }, _  ) -> Some t_dynamic
       | _ -> None);
@@ -658,6 +660,8 @@ let configure gen =
       | TInst ({ cl_path = ["haxe"],"Int32" },[]) -> "int"
       | TInst ({ cl_path = ["haxe"],"Int64" },[]) -> "long"
       | TInst ({ cl_path = ([], "Dynamic") }, _) -> "object"
+      | TType ({ t_path = ["cs"],"Out" },[t])
+      | TType ({ t_path = ["cs"],"Ref" },[t]) -> t_s t
       | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) ->
         let rec check_t_s t =
           match real_type t with
@@ -692,6 +696,13 @@ let configure gen =
       | TEnum ({e_path = ([], "Void")}, []) -> "void"
       | _ -> t_s t
   in
+  
+  let argt_s t =
+    match t with
+      | TType ({ t_path = (["cs"], "Ref") }, [t]) -> "ref " ^ t_s t
+      | TType ({ t_path = (["cs"], "Out") }, [t]) -> "out " ^ t_s t
+      | _ -> t_s t
+  in
 
   let escape ichar b =
     match ichar with
@@ -863,12 +874,45 @@ let configure gen =
               write w ">"
           );
           
+          let rec ensure_local e explain =
+            match e.eexpr with 
+              | TLocal _ -> e
+              | TCast(e,_)
+              | TParenthesis e -> ensure_local e explain
+              | _ -> gen.gcon.error ("The function argument of type " ^ explain ^ " must be a local variable.") e.epos; e
+          in
+          
+          let rec loop acc elist tlist =
+            match elist, tlist with
+              | e :: etl, (_,_,t) :: ttl ->
+                (if acc <> 0 then write w ", ");
+                (match real_type t with
+                  | TType({ t_path = (["cs"], "Ref") }, _) ->
+                    let e = ensure_local e "cs.Ref" in
+                    write w "ref ";
+                    expr_s w e
+                  | TType({ t_path = (["cs"], "Out") }, _) ->
+                    let e = ensure_local e "cs.Out" in
+                    write w "out ";
+                    expr_s w e
+                  | _ ->
+                    expr_s w e
+                );
+                loop (acc + 1) etl ttl
+              | e :: etl, [] ->
+                (if acc <> 0 then write w ", ");
+                expr_s w e;
+                loop (acc + 1) etl []
+              | _ -> ()
+          in
           write w "(";
-          ignore (List.fold_left (fun acc e ->
-            (if acc <> 0 then write w ", ");
-            expr_s w e;
-            acc + 1
-          ) 0 el);
+          let ft = match follow e.etype with
+            | TFun(args,_) -> args
+            | _ -> []
+          in
+          
+          loop 0 el ft;
+          
           write w ")"
         | TNew (({ cl_path = (["cs"], "NativeArray") } as cl), params, [ size ]) ->
           let rec check_t_s t times =
@@ -1121,7 +1165,7 @@ let configure gen =
         print w "%s %s %s %s %s" (visibility) v_n (String.concat " " modifiers) (if is_new then "" else rett_s (run_follow gen ret_type)) (change_field name);
         let params, params_ext = get_string_params cf.cf_params in
         (* <T>(string arg1, object arg2) with T : object *)
-        print w "%s(%s)%s" (params) (String.concat ", " (List.map (fun (name, _, t) -> sprintf "%s %s" (t_s (run_follow gen t)) (change_id name)) args)) (params_ext);
+        print w "%s(%s)%s" (params) (String.concat ", " (List.map (fun (name, _, t) -> sprintf "%s %s" (argt_s (run_follow gen t)) (change_id name)) args)) (params_ext);
         if is_interface then
           write w ";"
         else begin

+ 90 - 1
std/cs/Lib.hx

@@ -42,7 +42,7 @@ class Lib
 		
 		If equalLengthRequired is true, the result might be a copy of an array with the correct size.
 	**/
-	public static function toNativeReadOnlyArray<T>(arr:Array<T>, equalLengthRequired:Bool):NativeArray<T>
+	public static function nativeArray<T>(arr:Array<T>, equalLengthRequired:Bool):NativeArray<T>
 	{
 		var native:NativeArray<T> = untyped arr.__a;
 		var len = arr.length;
@@ -117,4 +117,93 @@ class Lib
 	{
 		return untyped Array.alloc(size);
 	}
+	
+	
+	//Unsafe code manipulation
+	#if unsafe
+	/**
+		Marks its parameters as fixed objects inside the defined block.
+		Usage:
+			cs.Lib.fixed(obj1, obj2, obj3, 
+			{
+				//inside here obj1, obj2 and obj3 are fixed
+			});
+		
+		This method only exists at compile-time, so it can't be called via reflection.
+	**/
+	@:extern public static inline function fixed(?p1:Dynamic, ?p2:Dynamic, ?p3:Dynamic, ?p4:Dynamic, ?p5:Dynamic, ?p6:Dynamic, ?p7:Dynamic, ?p8:Dynamic, ?p9:Dynamic, ?p10:Dynamic):Void
+	{
+		untyped __fixed__(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+	}
+	
+	/**
+		Marks the contained block as an unsafe block, meaning that it can contain unsafe code.
+		Usage:
+			cs.Lib.unsafe({
+				//unsafe code is allowed inside here
+			});
+		
+		This method only exists at compile-time, so it can't be called via reflection.
+	**/
+	@:extern public static inline function unsafe(block:Dynamic):Void
+	{
+		untyped __unsafe__(block);
+	}
+	
+	/**
+		Gets the pointer to the address of current local. Equivalent to the "&" operator in C#
+		Usage:
+			var x:Int = 0;
+			cs.Lib.unsafe({
+				var addr = cs.Lib.addressOf(x);
+				x[0] = 42;
+			});
+			trace(x); //42
+		
+		This method only exists at compile-time, so it can't be called via reflection.
+		Warning: This method will only work if a local variable is passed as an argument.
+	**/
+	@:extern public static inline function addressOf<T>(variable:T):cs.Pointer<T>
+	{
+		return untyped __addressOf__(variable);
+	}
+	
+	/**
+		Gets the value of the pointer address.
+		Usage:
+			var x:Int = 0;
+			cs.Lib.unsafe({
+				var addr = cs.Lib.addressOf(x);
+				trace(cs.Lib.valueOf(addr)); //0
+				x[0] = 42;
+				trace(cs.Lib.valueOf(addr)); //42
+			});
+			trace(x); //42
+		
+		This method only exists at compile-time, so it can't be called via reflection.
+	**/
+	@:extern public static inline function valueOf<T>(pointer:cs.Pointer<T>):T
+	{
+		return untyped __valueOf__(pointer, idx);
+	}
+	
+	/**
+		Transforms a managed native array into a Pointer.
+		Usage:
+			var x:cs.NativeArray<Int> = new cs.NativeArray(1);
+			cs.Lib.unsafe({
+				var addr = cs.Lib.pointerOfArray(x);
+				trace(cs.Lib.valueOf(addr)); //0
+				x[0] = 42;
+				trace(cs.Lib.valueOf(addr)); //42
+			});
+			trace(x[0]); //42
+		
+		This method only exists at compile-time, so it can't be called via reflection.
+	**/
+	@:extern public static inline function pointerOfArray<T>(array:cs.NativeArray<T>):cs.Pointer<T>
+	{
+		return cast array;
+	}
+	#end
 }

+ 9 - 0
std/cs/Out.hx

@@ -0,0 +1,9 @@
+package cs;
+
+/**
+	This type represents "out" types for C# function parameters. 
+	It only has effect on function parameters, and conversion to/from the referenced type is automatic.
+	
+	Note: Using this type should be considered a bad practice unless overriding a native function is needed.
+**/
+typedef Out<T> = T;

+ 28 - 0
std/cs/Pointer.hx

@@ -0,0 +1,28 @@
+package cs;
+
+/**
+	This type represents pointer types for C# function parameters. It should only
+	be used inside an unsafe context (not checked by the Haxe compiler)
+	
+	C# code:
+		int[] src;
+		fixed (int* pSrc = src)
+		{
+			...
+		}
+	Haxe code:
+		var pSrc:cs.Pointer<Int>;
+		cs.Lib.fixed(pSrc = cast src,
+		{
+			...
+		});
+	
+**/
+#if !unsafe
+#error "You need to define 'unsafe' to be able to use unsafe code in hxcs"
+#else
+extern class Pointer<T> extends Int, implements ArrayAccess<T>
+{
+	
+}
+#end

+ 9 - 0
std/cs/Ref.hx

@@ -0,0 +1,9 @@
+package cs;
+
+/**
+	This type represents "ref" types for C# function parameters. 
+	It only has effect on function parameters, and conversion to/from the referenced type is automatic.
+	
+	Note: Using this type should be considered a bad practice unless overriding a native function is needed.
+**/
+typedef Ref<T> = T;

+ 0 - 5
std/java/lang/Number.hx

@@ -4,11 +4,6 @@ import java.StdTypes;
 
 private typedef StdFloat = Float;
 
-/**
- * ...
- * @author waneck
- */
-
 @:abstract extern class Number 
 {
 	

+ 3 - 0
tests/unit/Test.hx

@@ -199,6 +199,9 @@ package unit;
 			new TestReflect(),
 			new TestSerialize(),
 			new TestMeta(),
+			#if cs
+			new TestCSharp(),
+			#end
 			//new TestUnspecified(),
 			//new TestRemoting(),
 		];

+ 72 - 0
tests/unit/TestCSharp.hx

@@ -0,0 +1,72 @@
+package unit;
+import haxe.Int32;
+using haxe.Int32;
+
+//C#-specific tests, like unsafe code
+class TestCSharp extends Test 
+{
+	#if cs
+	
+	@:skipReflection private function refTest(i:cs.Ref<Int>):Void
+	{
+		i *= 2;
+	}
+	
+	@:skipReflection private function outTest(out:cs.Out<Int>, x:Int):Void
+	{
+		out = x * 2;
+	}
+	
+	public function testRef()
+	{
+		var i = 10;
+		refTest(i);
+		eq(i, 20);
+	}
+	
+	public function testOut()
+	{
+		var i = 0;
+		outTest(i, 10);
+		eq(i, 20);
+	}
+	
+	#if unsafe
+	
+	@:unsafe public function testUnsafe()
+	{
+		var x:cs.NativeArray<Int> = new cs.NativeArray(10);
+		var p;
+		cs.Lib.fixed(p = cs.Lib.pointerOfArray(x),
+		{
+			for (i in 0...10)
+			{
+				p[0] = i;
+				p++;
+			}
+		});
+		
+		cs.Lib.fixed(p = cs.Lib.pointerOfArray(x),
+		{
+			for (i in 0...10)
+			{
+				eq(p[i], i);
+			}
+		});
+		
+		var x:Int = 0;
+		var addr = cs.Lib.addressOf(x);
+		eq(cs.Lib.valueOf(addr), 0);
+		eq(addr[0], 0);
+		x[0] = 42;
+		eq(cs.Lib.valueOf(addr), 42);
+		eq(addr[0], 42);
+		eq(x, 42);
+		
+		
+	}
+	
+	#end
+	
+	#end
+}