Browse Source

added Reflect specification (part 1)

Simon Krajewski 12 years ago
parent
commit
833cb2b3dd

+ 55 - 13
std/Reflect.hx

@@ -26,44 +26,79 @@
 extern class Reflect {
 extern class Reflect {
 
 
 	/**
 	/**
-		Tells if an object has a field set. This doesn't take into account the object prototype (class methods).
+		Tells if structure [o] has a field named [field].
+		
+		This is only guaranteed to work for anonymous structures. Refer to
+		[Type.getInstanceFields()] for a function supporting class instances.
+		
+		If [o] or [field] are null, the result is unspecified.
 	**/
 	**/
 	public static function hasField( o : Dynamic, field : String ) : Bool;
 	public static function hasField( o : Dynamic, field : String ) : Bool;
 
 
 	/**
 	/**
-		Returns the field of an object, or null if [o] is not an object or doesn't have this field.
+		Returns the value of the field named [field] on object [o].
+		
+		If [o] is not an object or has no field named [field], the result is
+		null.
+		
+		If the field is defined as a property, its accessors are ignored. Refer
+		to [Reflect.getProperty()] for a function supporting property accessors.
+		
+		If [field] is null, the result is unspecified.
 	**/
 	**/
 	public static function field( o : Dynamic, field : String ) : Dynamic;
 	public static function field( o : Dynamic, field : String ) : Dynamic;
 
 
-
 	/**
 	/**
-		Set an object field value.
+		Sets the field named [field] of object [o] to value [value].
+		
+		If [o] has no field named [field], this function is only guaranteed to
+		work for anonymous structures.
+		
+		If [o] or [field] are null, the result is unspecified.
 	**/
 	**/
 	public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void;
 	public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void;
 
 
 	/**
 	/**
-		Similar to field but also supports property (might be slower).
+		Returns the value of the field named [field] on object [o], taking
+		property getter functions into account.
+		
+		If the field is not a property, this function behaves like
+		[Reflect.field], but might be slower.
+		
+		If [o] or [field] are null, the result is unspecified.
 	**/
 	**/
 	public static function getProperty( o : Dynamic, field : String ) : Dynamic;
 	public static function getProperty( o : Dynamic, field : String ) : Dynamic;
 
 
 	/**
 	/**
-		Similar to setField but also supports property (might be slower).
+		Sets the field named [field] of object [o] to value [value], taking
+		property setter functions into account.
+		
+		If the field is not a property, this function behaves like
+		[Reflect.setField], but might be slower.
+		
+		If [field] is null, the result is unspecified.		
 	**/
 	**/
 	public static function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void;
 	public static function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void;
 
 
-
 	/**
 	/**
 		Call a method with the given object and arguments.
 		Call a method with the given object and arguments.
 	**/
 	**/
 	public static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic;
 	public static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic;
 
 
 	/**
 	/**
-		Returns the list of fields of an object, excluding its prototype (class methods).
+		Returns the fields of structure [o].
+		
+		This method is only guaranteed to work on anonymous structures. Refer to
+		[Type.getInstancefields()] for a function supporting class instances.
+		
+		If [o] is null, the result is unspecified.
 	**/
 	**/
 	public static function fields( o : Dynamic ) : Array<String>;
 	public static function fields( o : Dynamic ) : Array<String>;
 
 
 	/**
 	/**
-		Tells if a value is a function or not.
+		Returns true if [f] is a function, false otherwise.
+		
+		If [f] is null, the result is false.
 	**/
 	**/
 	public static function isFunction( f : Dynamic ) : Bool;
 	public static function isFunction( f : Dynamic ) : Bool;
 
 
@@ -79,17 +114,24 @@ extern class Reflect {
 
 
 	/**
 	/**
 		Tells if a value is an object or not.
 		Tells if a value is an object or not.
-
 	**/
 	**/
 	public static function isObject( v : Dynamic ) : Bool;
 	public static function isObject( v : Dynamic ) : Bool;
 
 
 	/**
 	/**
-		Delete an object field.
+		Removes the field named [field] from structure [o].
+		
+		This method is only guaranteed to work on anonymous structures.
+		
+		If [o] or [field] are null, the result is unspecified. 
 	**/
 	**/
-	public static function deleteField( o : Dynamic, f : String ) : Bool;
+	public static function deleteField( o : Dynamic, field : String ) : Bool;
 
 
 	/**
 	/**
-		Make a copy of the fields of an object.
+		Copies the fields of structure [o].
+		
+		This is only guaranteed to work on anonymous structures.
+		
+		If [o] is null, the result is unspecified.
 	**/
 	**/
 	public static function copy<T>( o : T ) : T;
 	public static function copy<T>( o : T ) : T;
 
 

+ 2 - 2
std/cpp/_std/Reflect.hx

@@ -80,9 +80,9 @@
 				t==__global__.vtArray;
 				t==__global__.vtArray;
 	}
 	}
 
 
-	public static function deleteField( o : Dynamic, f : String ) : Bool untyped {
+	public static function deleteField( o : Dynamic, field : String ) : Bool untyped {
 		if (o==null) return false;
 		if (o==null) return false;
-		return untyped __global__.__hxcpp_anon_remove(o,f);
+		return untyped __global__.__hxcpp_anon_remove(o,field);
 	}
 	}
 
 
 	public static function copy<T>( o : T ) : T {
 	public static function copy<T>( o : T ) : T {

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

@@ -220,7 +220,7 @@ import cs.internal.Function;
 	@:functionCode('
 	@:functionCode('
 		return (o is haxe.lang.DynamicObject && ((haxe.lang.DynamicObject) o).__hx_deleteField(f, haxe.lang.FieldLookup.hash(f)));
 		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
+	public static function deleteField( o : Dynamic, field : String ) : Bool
 	{
 	{
 		return false;
 		return false;
 	}
 	}

+ 3 - 3
std/flash/_std/Reflect.hx

@@ -108,9 +108,9 @@
 		return (t == "string");
 		return (t == "string");
 	}
 	}
 
 
-	public static function deleteField( o : Dynamic, f : String ) : Bool untyped {
-		if( o.hasOwnProperty(f) != true ) return false;
-		__delete__(o,f);
+	public static function deleteField( o : Dynamic, field : String ) : Bool untyped {
+		if( o.hasOwnProperty(field) != true ) return false;
+		__delete__(o,field);
 		return true;
 		return true;
 	}
 	}
 
 

+ 3 - 3
std/flash8/_std/Reflect.hx

@@ -93,9 +93,9 @@
 		return (t == "string" || (t == "object" && !v.__enum__) || (t == "function" && v.__name__ != null));
 		return (t == "string" || (t == "object" && !v.__enum__) || (t == "function" && v.__name__ != null));
 	}
 	}
 
 
-	public static function deleteField( o : Dynamic, f : String ) : Bool untyped {
-		if( __this__["hasOwnProperty"]["call"](o,f) != true ) return false;
-		__delete__(o,f);
+	public static function deleteField( o : Dynamic, field : String ) : Bool untyped {
+		if( __this__["hasOwnProperty"]["call"](o,field) != true ) return false;
+		__delete__(o,field);
 		return true;
 		return true;
 	}
 	}
 
 

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

@@ -222,7 +222,7 @@ import java.Boot;
 	@:functionCode('
 	@:functionCode('
 		return (o instanceof haxe.lang.DynamicObject && ((haxe.lang.DynamicObject) o).__hx_deleteField(f));
 		return (o instanceof haxe.lang.DynamicObject && ((haxe.lang.DynamicObject) o).__hx_deleteField(f));
 	')
 	')
-	public static function deleteField( o : Dynamic, f : String ) : Bool
+	public static function deleteField( o : Dynamic, field : String ) : Bool
 	{
 	{
 		return false;
 		return false;
 	}
 	}

+ 3 - 3
std/js/_std/Reflect.hx

@@ -86,9 +86,9 @@
 		return (t == "string" || (t == "object" && !v.__enum__) || (t == "function" && (js.Boot.isClass(v) || js.Boot.isEnum(v))));
 		return (t == "string" || (t == "object" && !v.__enum__) || (t == "function" && (js.Boot.isClass(v) || js.Boot.isEnum(v))));
 	}
 	}
 
 
-	public static function deleteField( o : Dynamic, f : String ) : Bool untyped {
-		if( !hasField(o,f) ) return false;
-		__js__("delete")(o[f]);
+	public static function deleteField( o : Dynamic, field : String ) : Bool untyped {
+		if( !hasField(o,field) ) return false;
+		__js__("delete")(o[field]);
 		return true;
 		return true;
 	}
 	}
 
 

+ 2 - 2
std/neko/_std/Reflect.hx

@@ -86,8 +86,8 @@
 		return $typeof(v) == $tobject && v.__enum__ == null;
 		return $typeof(v) == $tobject && v.__enum__ == null;
 	}
 	}
 
 
-	public inline static function deleteField( o : Dynamic, f : String ) : Bool untyped {
-		return $objremove(o,$fasthash(f.__s));
+	public inline static function deleteField( o : Dynamic, field : String ) : Bool untyped {
+		return $objremove(o,$fasthash(field.__s));
 	}
 	}
 
 
 	public inline static function copy<T>( o : T ) : T {
 	public inline static function copy<T>( o : T ) : T {

+ 3 - 3
std/php/_std/Reflect.hx

@@ -93,9 +93,9 @@
 		return untyped __php__("is_string($v) && !_hx_is_lambda($v)");
 		return untyped __php__("is_string($v) && !_hx_is_lambda($v)");
 	}
 	}
 
 
-	public static function deleteField( o : Dynamic, f : String ) : Bool {
-		if(!hasField(o,f)) return false;
-		untyped __php__("if(isset($o->__dynamics[$f])) unset($o->__dynamics[$f]); else if($o instanceof _hx_anonymous) unset($o->$f); else $o->$f = null");
+	public static function deleteField( o : Dynamic, field : String ) : Bool {
+		if(!hasField(o,field)) return false;
+		untyped __php__("if(isset($o->__dynamics[$field])) unset($o->__dynamics[$field]); else if($o instanceof _hx_anonymous) unset($o->$f); else $o->$f = null");
 		return true;
 		return true;
 	}
 	}
 
 

+ 21 - 1
tests/unit/TestSpecification.hx

@@ -10,7 +10,6 @@ typedef T = {
 	public function func() { }
 	public function func() { }
 	public var v:String;
 	public var v:String;
 	public var prop(default, null):String;
 	public var prop(default, null):String;
-
 	static function staticFunc() { }
 	static function staticFunc() { }
 	static public var staticVar:String;
 	static public var staticVar:String;
 	static var staticProp(default, null):String;
 	static var staticProp(default, null):String;
@@ -23,6 +22,27 @@ typedef T = {
 	}
 	}
 }
 }
 
 
+@:keep class C2 {
+	public function func() { return "foo"; }
+	public var v:String;
+	public var prop(default, null):String;
+	@:isVar public var propAcc(get, set):String;
+
+	public function new() {
+		v = "var";
+		prop = "prop";
+		propAcc = "0";
+	}
+	
+	public function get_propAcc() {
+		return "1";
+	}
+	
+	public function set_propAcc(v) {
+		return this.propAcc = v.toUpperCase();
+	}	
+}
+
 class CChild extends C { }
 class CChild extends C { }
 
 
 class CDyn extends C implements Dynamic { }
 class CDyn extends C implements Dynamic { }

+ 81 - 0
tests/unit/unitstd/Reflect.unit.hx

@@ -0,0 +1,81 @@
+// hasField
+var x = { a: 1, b: null };
+Reflect.hasField(x, "a") == true;
+Reflect.hasField(x, "b") == true;
+Reflect.hasField(x, "c") == false;
+
+// field
+Reflect.field(x, "a") == 1;
+Reflect.field(x, "b") == null;
+Reflect.field(x, "c") == null;
+var c = new C2();
+Reflect.field(c, "v") == "var";
+Reflect.field(c, "prop") == "prop";
+Reflect.field(c, "func")() == "foo";
+Reflect.field(c, "propAcc") == "0";
+Reflect.field(null, null) == null;
+Reflect.field(1, "foo") == null;
+
+// setField
+Reflect.setField(x, "a", 2);
+x.a == 2;
+Reflect.setField(x, "c", "foo");
+Reflect.field(x, "c") == "foo";
+var c = new C2();
+Reflect.setField(c, "v", "bar");
+c.v == "bar";
+//Reflect.setField(c, "v2", "bar2");
+//c.v2 == "bar";
+//Reflect.setField(c, "func2", function() return "x");
+//Reflect.field(c, "func2")() == "x";
+
+// getProperty
+var c = new C2();
+Reflect.getProperty(c, "v") == "var";
+Reflect.getProperty(c, "prop") == "prop";
+//Reflect.getProperty(c, "func")() == "foo";
+Reflect.getProperty(c, "propAcc") == "1";
+//Reflect.getProperty(null, "a") == null;
+//Reflect.getProperty(null, null) == null;
+
+// setProperty
+Reflect.setProperty(x, "a", 2);
+x.a == 2;
+Reflect.setProperty(x, "c", "foo");
+Reflect.field(x, "c") == "foo";
+var c = new C2();
+Reflect.setProperty(c, "v", "bar");
+c.v == "bar";
+//Reflect.setProperty(c, "v2", "bar2");
+//c.v2 == "bar";
+//Reflect.setProperty(c, "func2", function() return "x");
+//Reflect.field(c, "func2")() == "x";
+Reflect.setProperty(c, "propAcc", "abc");
+Reflect.field(c, "propAcc") == "ABC";
+
+// fields
+var names = ["a", "b", "c"];
+for (name in Reflect.fields(x)) {
+	names.remove(name);
+}
+names == [];
+
+// isFunction
+var c = new C2();
+Reflect.isFunction(function() return 1) == true;
+Reflect.isFunction(1) == false;
+Reflect.isFunction(null) == false;
+Reflect.isFunction(Reflect.field(c, "func")) == true;
+
+// deleteField
+Reflect.hasField(x, "c") == true;
+Reflect.deleteField(x, "c");
+Reflect.hasField(x, "c") == false;
+Reflect.deleteField(x, "c");
+Reflect.hasField(x, "c") == false;
+
+// copy
+var y = Reflect.copy(x);
+Reflect.field(y, "a") == 2;
+Reflect.field(y, "b") == null;
+Reflect.field(y, "c") == null;