Kaynağa Gözat

[cs] Implemented initial Reflect API:
Fixed bug with not defining reflection methods as override (java/cs); Added correct handling for NativeArray casts; All hashed fields are now added to FieldLookup.fieldIds and FieldLookup.fields; Implemented VarArgs base for VarArgs Methods and for Native Closure handling;
[java] added Reflect.compareMethods for native closures

Caue Waneck 13 yıl önce
ebeveyn
işleme
ff5c6ddec1

+ 7 - 49
gencommon.ml

@@ -5557,8 +5557,6 @@ struct
       rcf_handle_statics = handle_statics;
     }
   
-  let priority = solve_deps name []
-  
   (* 
     methods as a bool option is a little laziness of my part. 
       None means that methods are included with normal fields;
@@ -7367,10 +7365,16 @@ struct
       gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map
     
     let default_config gen baseclass baseinterface basedynamic =
-      configure gen (default_implementation gen baseclass baseinterface basedynamic)
+      let impl = (default_implementation gen baseclass baseinterface basedynamic) in
+      configure gen impl
     
   end;;
   
+  (*
+    Priority: must run AFTER UniversalBaseClass
+  *)
+  let priority = solve_deps name [DAfter UniversalBaseClass.priority]
+  
   let configure ctx =
     let gen = ctx.rcf_gen in
     let run = (fun md -> match md with
@@ -8790,52 +8794,6 @@ struct
   
 end;;
 
-(* ******************************************* *)
-(* Global Namespace Change *)
-(* ******************************************* *)
-
-(*
-  
-  For some parts of the Haxe API implementation, we need to access some
-  otherwise private packages. One of the way to do it is with the 
-  __global__ magic. Like Flash9, it will be accessed like that:
-  __global__("path.to.class").
-  In order to not interfere with normal code, we need to run this filter
-  as the first filter run by expression filters.
-  
-  dependencies:
-    Must be the first expression filter to be run
-  
-*
-
-module GlobalNamespaceChange =
-struct
-
-  let name = "global_namespace"
-  
-  let priority = max_dep
-  
-  let default_implementation gen =
-    let rec run e =
-      match e.eexpr with 
-        | TArray({ eexpr = TLocal { v_name = "__global__" } }, { eexpr = TConst(TString str) }) ->
-          let path = match List.rev (ExtString.String.nsplit f ".") with
-            | [] -> assert false
-            | cl :: pack -> (List.rev pack, cl)
-          in
-          (try
-            match Hashtbl.find path with
-              | TClassDecl cl -> 
-          with | Not_found -> gen.gcon.error ("Package not found: " ^  str) e.epos)
-    in
-    run
-  
-  let configure gen (mapping_func:texpr->texpr) =
-    let map e = Some(mapping_func e) in
-    gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map
-  
-end;;
-*)
 (*
 (* ******************************************* *)
 (* Example *)

+ 66 - 10
gencs.ml

@@ -17,6 +17,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *)
+open Gencommon.ReflectionCFs
 open Ast
 open Common
 open Gencommon
@@ -330,6 +331,7 @@ let handle_type_params gen ifaces =
       let new_v = mk_temp gen "new_arr" to_t in
       let i = mk_temp gen "i" basic.tint in
       let old_len = { eexpr = TField(e, "Length"); etype = basic.tint; epos = e.epos } in
+      let obj_v = mk_temp gen "obj" t_dynamic in
       let block = [
         { 
           eexpr = TVars(
@@ -354,15 +356,32 @@ let handle_type_params gen ifaces =
               etype = basic.tbool;
               epos = e.epos
             },
-            {
-              eexpr = TBinop(
-                Ast.OpAssign,
-                { eexpr = TArray(mk_local new_v e.epos, mk_local i e.epos); etype = new_param; epos = e.epos },
-                mk_cast new_param (mk_cast t_dynamic { eexpr = TArray(e, mk_local i e.epos); etype = old_param; epos = e.epos })
-              );
-              etype = new_param;
-              epos = e.epos
-            },
+            { eexpr = TBlock [
+              {
+                eexpr = TVars([obj_v, Some (mk_cast t_dynamic { eexpr = TArray(e, mk_local i e.epos); etype = old_param; epos = e.epos })]);
+                etype = basic.tvoid;
+                epos = e.epos
+              };
+              {
+                eexpr = TIf({
+                  eexpr = TBinop(Ast.OpNotEq, mk_local obj_v e.epos, null e.etype e.epos);
+                  etype = basic.tbool;
+                  epos = e.epos
+                }, 
+                {
+                  eexpr = TBinop(
+                    Ast.OpAssign,
+                    { eexpr = TArray(mk_local new_v e.epos, mk_local i e.epos); etype = new_param; epos = e.epos },
+                    mk_cast new_param (mk_local obj_v e.epos)
+                  );
+                  etype = new_param;
+                  epos = e.epos
+                },
+                None);
+                etype = basic.tvoid;
+                epos = e.epos
+              }
+            ]; etype = basic.tvoid; epos = e.epos },
             Ast.NormalWhile
           );
           etype = basic.tvoid;
@@ -945,7 +964,14 @@ let configure gen =
       | Method (MethDynamic) -> 
         if not is_interface then begin 
           let access, modifiers = get_fun_modifiers cf.cf_meta "public" [] in
-          print w "%s %s%s %s %s;" access (if is_static then "static " else "") (String.concat " " modifiers) (t_s (run_follow gen cf.cf_type)) (change_field name)
+          (match cf.cf_expr with
+            | Some e ->
+              print w "%s %s%s %s %s = " access (if is_static then "static " else "") (String.concat " " modifiers) (t_s (run_follow gen cf.cf_type)) (change_field name);
+              expr_s w e;
+              write w ";"
+            | None ->
+              print w "%s %s%s %s %s;" access (if is_static then "static " else "") (String.concat " " modifiers) (t_s (run_follow gen cf.cf_type)) (change_field name)
+          )
         end (* TODO see how (get,set) variable handle when they are interfaces *)
       | Method mkind -> 
         let is_virtual = not is_final && match mkind with | MethInline -> false | _ when not is_new -> true | _ -> false in
@@ -1375,6 +1401,8 @@ let configure gen =
   
   let closure_func = ReflectionCFs.implement_closure_cl rcf_ctx ( get_cl (Hashtbl.find gen.gtypes (["haxe";"lang"],"Closure")) ) in
   
+  ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) );
+  
   ReflectionCFs.configure rcf_ctx;
   
   let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in
@@ -1596,6 +1624,34 @@ let configure gen =
   CSharpSpecificSynf.configure gen (CSharpSpecificSynf.traverse gen runtime_cl);
   
   run_filters gen;
+  (* after the filters have been run, add all hashed fields to FieldLookup *)
+  
+  let hashes = Hashtbl.fold (fun i s acc -> (i,s) :: acc) rcf_ctx.rcf_hash_fields [] in
+  let hashes = List.sort (fun (i,s) (i2,s2) -> compare i i2) hashes in
+  
+  let flookup_cl = get_cl (Hashtbl.find gen.gtypes (["haxe";"lang"], "FieldLookup")) in
+  (try
+    let basic = gen.gcon.basic in
+    let change_array = ArrayDeclSynf.default_implementation gen native_arr_cl in
+    let cl = flookup_cl in
+    let field_ids = PMap.find "fieldIds" cl.cl_statics in
+    let fields = PMap.find "fields" cl.cl_statics in
+    
+    field_ids.cf_expr <- Some (change_array { 
+      eexpr = TArrayDecl(List.map (fun (i,s) -> { eexpr = TConst(TInt ( Int32.of_int i)); etype = basic.tint; epos = field_ids.cf_pos }) hashes);
+      etype = basic.tarray basic.tint;
+      epos = field_ids.cf_pos
+    });
+    
+    fields.cf_expr <- Some (change_array {
+      eexpr = TArrayDecl(List.map (fun (i,s) -> { eexpr = TConst(TString s); etype = basic.tstring; epos = fields.cf_pos }) hashes);
+      etype = basic.tarray basic.tstring;
+      epos = fields.cf_pos
+    })
+    
+  with | Not_found -> 
+    gen.gcon.error "Fields 'fieldIds' and 'fields' were not found in class haxe.lang.FieldLookup" flookup_cl.cl_pos
+  );
   
   TypeParams.RenameTypeParameters.run gen;
   

+ 90 - 2
std/cs/_std/Reflect.hx

@@ -1,3 +1,4 @@
+import haxe.lang.Function;
 /*
  * Copyright (c) 2005, The haXe Project Contributors
  * All rights reserved.
@@ -32,6 +33,12 @@
 	/**
 		Tells if an object has a field set. This doesn't take into account the object prototype (class methods).
 	**/
+	@:functionBody('
+		if (o is haxe.lang.IHxObject)
+		return ((haxe.lang.IHxObject) o).__hx_getField(field, haxe.lang.FieldLookup.hash(field), false, false, true) != haxe.lang.Runtime.undefined;
+		
+		return haxe.lang.Runtime.slowHasField(o, field);
+	')
 	public static function hasField( o : Dynamic, field : String ) : Bool
 	{
 		return false;
@@ -40,6 +47,12 @@
 	/**
 		Returns the field of an object, or null if [o] is not an object or doesn't have this field.
 	**/
+	@:functionBody('
+		if (o is haxe.lang.IHxObject)
+		return ((haxe.lang.IHxObject) o).__hx_getField(field, haxe.lang.FieldLookup.hash(field), false, false, false);
+		
+		return haxe.lang.Runtime.slowGetField(o, field, false);
+	')
 	public static function field( o : Dynamic, field : String ) : Dynamic
 	{
 		return null;
@@ -49,6 +62,12 @@
 	/**
 		Set an object field value.
 	**/
+	@:functionBody('
+		if (o is haxe.lang.IHxObject)
+			((haxe.lang.IHxObject) o).__hx_setField(field, haxe.lang.FieldLookup.hash(field), false, value);
+		
+		 haxe.lang.Runtime.slowSetField(o, field, value);
+	')
 	public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void
 	{
 		
@@ -73,6 +92,9 @@
 	/**
 		Call a method with the given object and arguments.
 	**/
+	@:functionBody('
+		return ((haxe.lang.Function) func).__hx_invokeDynamic(args);
+	')
 	public static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic
 	{
 		return null;
@@ -81,6 +103,39 @@
 	/**
 		Returns the list of fields of an object, excluding its prototype (class methods).
 	**/
+	@:functionBody('
+		if (o is haxe.lang.IHxObject)
+		{
+			Array<object> ret = new Array<object>();
+			((haxe.lang.IHxObject) o).__hx_getFields(ret, false);
+			return ret;
+		} else {
+			Array<object> ret = new Array<object>();
+			
+			if (o is System.Type)
+			{
+				System.Type cl = (System.Type) o;
+				
+				foreach(System.Reflection.FieldInfo fi in cl.GetFields(System.Reflection.BindingFlags.Static))
+				{
+					ret.push(fi.Name);
+				}
+				
+				string last = null;
+				foreach(System.Reflection.MethodInfo mi in cl.GetMethods(System.Reflection.BindingFlags.Static))
+				{
+					string name = mi.Name;
+					if (last != name)
+					{
+						ret.push(name);
+						last = name;
+					}
+				}
+			}
+			
+			return ret;
+		}
+	')
 	public static function fields( o : Dynamic ) : Array<String>
 	{
 		return null;
@@ -89,6 +144,9 @@
 	/**
 		Tells if a value is a function or not.
 	**/
+	@:functionBody('
+		return f is haxe.lang.Function;
+	')
 	public static function isFunction( f : Dynamic ) : Bool
 	{
 		return false;
@@ -97,6 +155,9 @@
 	/**
 		Generic comparison function, does not work for methods, see [compareMethods]
 	**/
+	@:functionBody('
+		return haxe.lang.Runtime.compare(a, b);
+	')
 	public static function compare<T>( a : T, b : T ) : Int
 	{
 		return 0;
@@ -105,6 +166,24 @@
 	/**
 		Compare two methods closures. Returns true if it's the same method of the same instance.
 	**/
+	@:functionBody('
+		if (f1 == f2) 
+			return true;
+		
+		if (f1 is haxe.lang.Closure && f2 is haxe.lang.Closure)
+		{
+			haxe.lang.Closure f1c = (haxe.lang.Closure) f1;
+			haxe.lang.Closure f2c = (haxe.lang.Closure) f2;
+			
+			return haxe.lang.Runtime.refEq(f1c.target, f2c.target) && f1c.field.Equals(f2c.field);
+		} else if (f1 is haxe.lang.NativeMethodFunction && f2 is haxe.lang.NativeMethodFunction) {
+			haxe.lang.NativeMethodFunction f1n = (haxe.lang.NativeMethodFunction) f1;
+			haxe.lang.NativeMethodFunction f2n = (haxe.lang.NativeMethodFunction) f2;
+			return haxe.lang.Runtime.refEq(f1n.obj, f2n.obj) && f1n.field.Equals(f2n.field);
+		}
+		
+		return false;
+	')
 	public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool
 	{
 		return false;
@@ -114,6 +193,9 @@
 		Tells if a value is an object or not.
 
 	**/
+	@:functionBody('
+		return v is haxe.lang.DynamicObject;
+	')
 	public static function isObject( v : Dynamic ) : Bool
 	{
 		return false;
@@ -122,6 +204,9 @@
 	/**
 		Delete an object field.
 	**/
+	@:functionBody('
+		return (o is haxe.lang.DynamicObject && ((haxe.lang.DynamicObject) o).__hx_deleteField(f, haxe.lang.FieldLookup.hash(f)));
+	')
 	public static function deleteField( o : Dynamic, f : String ) : Bool
 	{
 		return false;
@@ -132,7 +217,10 @@
 	**/
 	public static function copy<T>( o : T ) : T
 	{
-		return null;
+		var o2 : Dynamic = {};
+		for( f in Reflect.fields(o) )
+			Reflect.setField(o2,f,Reflect.field(o,f));
+		return cast o2;
 	}
 
 	/**
@@ -141,7 +229,7 @@
 	**/
 	public static function makeVarArgs( f : Array<Dynamic> -> Dynamic ) : Dynamic
 	{
-		return null;
+		return new VarArgsFunction(f);
 	}
 
 }

+ 3 - 3
std/cs/_std/haxe/lang/FieldLookup.hx

@@ -28,7 +28,7 @@ package haxe.lang;
 		
 		while (min < max)
 		{
-			var mid = Std.int(min + (max - min) / 2); //overflow safe
+			var mid = min + Std.int((max - min) / 2);
 			var imid = ids[mid];
 			if (key < imid)
 			{
@@ -66,8 +66,8 @@ package haxe.lang;
 			} else {
 				var field = fields[mid];
 				if (field != s)
-					return -(key + 1); //special case
-				return mid;
+					return ~key; //special case
+				return key;
 			}
 		}
 		//if not found, min holds the value where we should insert the key

+ 43 - 4
std/cs/_std/haxe/lang/Function.hx

@@ -9,7 +9,10 @@ package haxe.lang;
  */
 @:abstract @:nativegen @:native("haxe.lang.Function") private class Function 
 {
-	
+	function new(arity:Int, type:Int)
+	{
+		
+	}
 }
 
 @:nativegen @:native("haxe.lang.Closure") private class Closure extends Function
@@ -17,8 +20,44 @@ package haxe.lang;
 	
 }
 
-/*
-@:nativegen @:native("haxe.lang.VarArgsFunction") private class VarArgsFunction extends Function
+@:nativegen @:native("haxe.lang.VarArgsBase") private class VarArgsBase extends Function
+{
+	public function __hx_invokeDynamic(dynArgs:Array<Dynamic>):Dynamic
+	{
+		throw "Abstract implementation";
+	}
+}
+
+@:nativegen class VarArgsFunction extends VarArgsBase
+{
+	private var fun:Array<Dynamic>->Dynamic;
+	
+	public function new(fun)
+	{
+		super(-1, -1);
+		this.fun = fun;
+	}
+	
+	override public function __hx_invokeDynamic(dynArgs:Array<Dynamic>):Dynamic
+	{
+		return fun(dynArgs);
+	}
+}
+
+@:nativegen class NativeMethodFunction extends VarArgsBase
 {
+	private var obj:Dynamic;
+	private var field:String;
+	
+	public function new(obj, field)
+	{
+		super(-1, -1);
+		this.obj = obj;
+		this.field = field;
+	}
 	
-}*/
+	override public function __hx_invokeDynamic(dynArgs:Array<Dynamic>):Dynamic 
+	{
+		return untyped __cs__("haxe.lang.Runtime.slowCallField(this.obj, this.field, dynArgs)");
+	}
+}

+ 52 - 13
std/cs/_std/haxe/lang/Runtime.hx

@@ -38,7 +38,20 @@ package haxe.lang;
 ')
 @:keep private class Runtime 
 {
-	public static var undefined:Dynamic = {};
+	public static var undefined:Dynamic = { };
+	
+	@:functionBody('
+		if (obj is haxe.lang.IHxObject)
+		{
+			return new haxe.lang.Closure(field, hash, (haxe.lang.IHxObject)obj);
+		} else {
+			return new haxe.lang.NativeMethodFunction(obj, field);
+		}
+	')
+	public static function closure(obj:Dynamic, hash:Int, field:String):Dynamic
+	{
+		return null;
+	}
 	
 	@:functionBody('
 			if (System.Object.ReferenceEquals(v1, v2))
@@ -195,19 +208,45 @@ package haxe.lang;
 		} else {
 			System.Reflection.PropertyInfo prop = t.GetProperty(field, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance);
 			if (prop == null)
-				if (throwErrors) 
-					throw HaxeException.wrap("Cannot access field \'" + field + "\'.");
-				else
-					return null;
+			{
+				System.Reflection.MethodInfo m = t.GetMethod(field,  System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance);
+				if (m != null)
+				{
+					return new haxe.lang.NativeMethodFunction(obj, field);
+				} else {
+					if (throwErrors) 
+						throw HaxeException.wrap("Cannot access field \'" + field + "\'.");
+					else
+						return null;
+				}
+			}
 			return prop.GetValue(obj, null);
 		}
 	
 	')
-	public static function slowGetField(obj:Dynamic, field:String, fieldHash:Int, throwErrors:Bool):Dynamic
+	public static function slowGetField(obj:Dynamic, field:String, throwErrors:Bool):Dynamic
 	{
 		return null;
 	}
 	
+	@:functionBody('
+		if (obj == null) return false;
+		System.Type t = obj as System.Type;
+        if (t == null)
+		{
+			t = obj.GetType();
+		} else {
+			obj = null;
+		}
+
+		System.Reflection.MemberInfo[] mi = t.GetMember(field, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance);
+		return mi != null && mi.Length > 0;
+	')
+	public static function slowHasField(obj:Dynamic, field:String):Bool
+	{
+		return false;
+	}
+	
 	@:functionBody('
 		if (obj == null)
 			throw new System.NullReferenceException("Cannot access field \'" + field + "\' of null.");
@@ -233,7 +272,7 @@ package haxe.lang;
 		}
 		
 	')
-	public static function slowSetField(obj:Dynamic, field:String, fieldHash:Int, value:Dynamic):Dynamic
+	public static function slowSetField(obj:Dynamic, field:String, value:Dynamic):Dynamic
 	{
 		//not implemented yet;
 		throw "Not implemented";
@@ -264,7 +303,7 @@ package haxe.lang;
 		System.Reflection.MethodInfo mi = t.GetMethod(field, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance, null, ts, null);
 		return mi.Invoke(obj, oargs);
 	')
-	public static function slowCallField(obj:Dynamic, field:String, fieldHash:Int, args:Array<Dynamic>):Dynamic
+	public static function slowCallField(obj:Dynamic, field:String, args:Array<Dynamic>):Dynamic
 	{
 		throw "not implemented";
 	}
@@ -274,7 +313,7 @@ package haxe.lang;
 		if (hxObj != null)
 			return hxObj.__hx_invokeField(field, (fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash, false, args);
 		
-		return slowCallField(obj, field, fieldHash, args);
+		return slowCallField(obj, field, args);
 	')
 	public static function callField(obj:Dynamic, field:String, fieldHash:Int, args:Array<Dynamic>):Dynamic
 	{
@@ -287,7 +326,7 @@ package haxe.lang;
 		if (hxObj != null)
 			return hxObj.__hx_getField(field, (fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash, false, throwErrors, false);
 		
-		return slowGetField(obj, field, fieldHash, throwErrors);
+		return slowGetField(obj, field, throwErrors);
 	
 	')
 	public static function getField(obj:Dynamic, field:String, fieldHash:Int, throwErrors:Bool):Dynamic
@@ -301,7 +340,7 @@ package haxe.lang;
 		if (hxObj != null)
 			return hxObj.__hx_getField_f(field, (fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash, false, throwErrors);
 		
-		return (double)slowGetField(obj, field, fieldHash, throwErrors);
+		return (double)slowGetField(obj, field, throwErrors);
 	
 	')
 	public static function getField_f(obj:Dynamic, field:String, fieldHash:Int, throwErrors:Bool):Float
@@ -315,7 +354,7 @@ package haxe.lang;
 		if (hxObj != null)
 			return hxObj.__hx_setField(field, (fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash, false, value);
 		
-		return slowSetField(obj, field, fieldHash, value);
+		return slowSetField(obj, field, value);
 	
 	')
 	public static function setField(obj:Dynamic, field:String, fieldHash:Int, value:Dynamic):Dynamic
@@ -329,7 +368,7 @@ package haxe.lang;
 		if (hxObj != null)
 			return hxObj.__hx_setField_f(field, (fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash, false, value);
 		
-		return (double)slowSetField(obj, field, fieldHash, value);
+		return (double)slowSetField(obj, field, value);
 	
 	')
 	public static function setField_f(obj:Dynamic, field:String, fieldHash:Int, value:Float):Float

+ 4 - 0
std/java/_std/Reflect.hx

@@ -173,6 +173,10 @@ import java.Boot;
 			haxe.lang.Closure f2c = (haxe.lang.Closure) f2;
 			
 			return haxe.lang.Runtime.refEq(f1c.target, f2c.target) && f1c.field.equals(f2c.field);
+		} else if (f1 instanceof haxe.lang.NativeMethodFunction && f2 instanceof haxe.lang.NativeMethodFunction) {
+			haxe.lang.NativeMethodFunction f1n = (haxe.lang.NativeMethodFunction) f1;
+			haxe.lang.NativeMethodFunction f2n = (haxe.lang.NativeMethodFunction) f2;
+			return haxe.lang.Runtime.refEq(f1n.obj, f2n.obj) && f1n.field.equals(f2n.field);
 		}