Skip to content

Commit

Permalink
partial support for Reflect.getProperty/setProperty
Browse files Browse the repository at this point in the history
git-svn-id: http://haxe.googlecode.com/svn/trunk@4096 f16182fa-f095-11de-8f43-4547254af6c6
  • Loading branch information
ncannasse committed Dec 4, 2011
1 parent aa34a13 commit 2393d91
Show file tree
Hide file tree
Showing 16 changed files with 247 additions and 32 deletions.
32 changes: 25 additions & 7 deletions codegen.ml
Expand Up @@ -83,6 +83,24 @@ let rec type_constant_value com (e,p) =
| _ ->
error "Constant value expected" p

let rec has_properties c =
List.exists (fun f ->
match f.cf_kind with
| Var { v_read = AccCall _ } -> true
| Var { v_write = AccCall _ } -> true
| _ -> false
) c.cl_ordered_fields || (match c.cl_super with Some (c,_) -> has_properties c | _ -> false)

let get_properties fields =
List.fold_left (fun acc f ->
let acc = (match f.cf_kind with
| Var { v_read = AccCall getter } -> ("get_" ^ f.cf_name , getter) :: acc
| _ -> acc) in
match f.cf_kind with
| Var { v_write = AccCall setter } -> ("set_" ^ f.cf_name , setter) :: acc
| _ -> acc
) [] fields

(* -------------------------------------------------------------------------- *)
(* REMOTING PROXYS *)

Expand Down Expand Up @@ -649,13 +667,13 @@ let captured_vars com e =
(match com.platform with
| Cpp -> e
| _ ->
mk (TCall (
mk_parent (mk (TFunction {
tf_args = List.map (fun v -> v, None) vars;
tf_type = e.etype;
tf_expr = mk_block (mk (TReturn (Some e)) e.etype e.epos);
}) (TFun (List.map (fun v -> v.v_name,false,v.v_type) vars,e.etype)) e.epos),
List.map (fun v -> mk (TLocal v) v.v_type e.epos) vars)
mk (TCall (
mk_parent (mk (TFunction {
tf_args = List.map (fun v -> v, None) vars;
tf_type = e.etype;
tf_expr = mk_block (mk (TReturn (Some e)) e.etype e.epos);
}) (TFun (List.map (fun v -> v.v_name,false,v.v_type) vars,e.etype)) e.epos),
List.map (fun v -> mk (TLocal v) v.v_type e.epos) vars)
) e.etype e.epos)
| _ ->
map_expr (wrap used) e
Expand Down
2 changes: 2 additions & 0 deletions doc/CHANGES.txt
Expand Up @@ -20,6 +20,8 @@
all : allowed abitrary string fields in anonymous objects
all : structure fields which are Null<X> are now optional (for constant values)
all : allowed optional args in functions types (?Int -> Void)
all : added Reflect.getProperty/setProperty
(partial support : neko, js only so far)

2011-09-25: 2.08
js : added js.JQuery
Expand Down
21 changes: 21 additions & 0 deletions genjs.ml
Expand Up @@ -732,6 +732,16 @@ let generate_class ctx c =
newline ctx;
);

let gen_props props =
String.concat "," (List.map (fun (p,v) -> p ^":\""^v^"\"") props)
in

(match Codegen.get_properties c.cl_ordered_statics with
| [] -> ()
| props ->
print ctx "%s.__properties__ = {%s}" p (gen_props props);
newline ctx);

List.iter (gen_class_static_field ctx c) c.cl_ordered_statics;

(match c.cl_super with
Expand All @@ -747,6 +757,17 @@ let generate_class ctx c =
List.iter (fun f -> match f.cf_kind with Var { v_read = AccResolve } -> () | _ -> gen_class_field ctx c f) c.cl_ordered_fields;
newprop ctx;
print ctx "__class__: %s" p;

let props = Codegen.get_properties c.cl_ordered_fields in
(match c.cl_super with
| _ when props = [] -> ()
| Some (csup,_) when Codegen.has_properties csup ->
newprop ctx;
let psup = s_path ctx csup.cl_path in
print ctx "__properties__: $extend(%s.prototype.__properties__,{%s})" psup (gen_props props)
| _ ->
newprop ctx;
print ctx "__properties__: {%s}" (gen_props props));

bend();
print ctx "\n}";
Expand Down
26 changes: 24 additions & 2 deletions genneko.ml
Expand Up @@ -204,6 +204,8 @@ and gen_expr ctx e =
match e.eexpr with
| TConst c ->
gen_constant ctx e.epos c
| TLocal v when v.v_name.[0] = '$' ->
(EConst (Builtin (String.sub v.v_name 1 (String.length v.v_name - 1))),p)
| TLocal v ->
if v.v_capture then
(EArray (ident p v.v_name,int p 0),p)
Expand Down Expand Up @@ -491,18 +493,38 @@ let gen_class ctx c =
let build (f,e) = (EBinop ("=",field p (ident p "@tmp") f,e),p) in
let tmp = (EVars ["@tmp",Some (call p (builtin p "new") [null p])],p) in
let estat = (EBinop ("=", stpath, ident p "@tmp"),p) in
let gen_props props = (EObject (List.map (fun (n,s) -> n,str p s) props),p) in
let sprops = (match Codegen.get_properties c.cl_ordered_statics with
| [] -> []
| l -> ["__properties__",gen_props l]
) in
let sfields = List.map build
(
("prototype",clpath) ::
("prototype",clpath) :: sprops @
PMap.fold (gen_method ctx p) c.cl_statics (fnew @ others)
)
in
let eclass = (EBinop ("=", clpath, ident p "@tmp"),p) in
let mfields = List.map build
(PMap.fold (gen_method ctx p) c.cl_fields (fserialize :: fstring))
in
let props = Codegen.get_properties c.cl_ordered_fields in
let emeta = (EBinop ("=",field p clpath "__class__",stpath),p) ::
match c.cl_path with
(match props with
| [] -> []
| _ ->
let props = gen_props props in
let props = (match c.cl_super with
| Some (csup,_) when Codegen.has_properties csup ->
(EBlock [
(EVars ["@tmp",Some props],p);
call p (builtin p "objsetproto") [ident p "@tmp";field p (field p (gen_type_path p csup.cl_path) "prototype") "__properties__"];
ident p "@tmp"
],p)
| _ -> props
) in
[EBinop ("=",field p clpath "__properties__",props),p])
@ match c.cl_path with
| [] , name -> [(EBinop ("=",field p (ident p "@classes") name,ident p name),p)]
| _ -> []
in
Expand Down
5 changes: 2 additions & 3 deletions lexer.mll
Expand Up @@ -136,9 +136,8 @@ let mk lexbuf t =
mk_tok t (lexeme_start lexbuf) (lexeme_end lexbuf)

let mk_ident lexbuf =
match lexeme lexbuf with
| s ->
mk lexbuf (try Kwd (Hashtbl.find keywords s) with Not_found -> Const (Ident s))
let s = lexeme lexbuf in
mk lexbuf (try Kwd (Hashtbl.find keywords s) with Not_found -> Const (Ident s))

let invalid_char lexbuf =
error (Invalid_character (lexeme_char lexbuf 0)) (lexeme_start lexbuf)
Expand Down
11 changes: 11 additions & 0 deletions std/Reflect.hx
Expand Up @@ -45,6 +45,17 @@ extern class Reflect {
**/
public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void;

/**
Similar to field but also supports property (might be slower).
**/
public static function getProperty( o : Dynamic, field : String ) : Dynamic;

/**
Similar to setField but also supports property (might be slower).
**/
public static function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void;


/**
Call a method with the given object and arguments.
**/
Expand Down
8 changes: 8 additions & 0 deletions std/cpp/_std/Reflect.hx
Expand Up @@ -39,6 +39,14 @@
o.__SetField(field,value);
}

public static inline function getProperty( o : Dynamic, field : String ) : Dynamic {
return Reflect.field(o,field);
}

public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void {
setField(o,field,value);
}

public static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic untyped {
if (func!=null && func.__GetType()==__global__.vtString)
func = o.__Field(func);
Expand Down
8 changes: 8 additions & 0 deletions std/flash/_std/Reflect.hx
Expand Up @@ -37,6 +37,14 @@
o[field] = value;
}

public static inline function getProperty( o : Dynamic, field : String ) : Dynamic {
return Reflect.field(o,field);
}

public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void {
setField(o,field,value);
}

public inline static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic untyped {
return func["apply"](o,args);
}
Expand Down
8 changes: 8 additions & 0 deletions std/flash9/_std/Reflect.hx
Expand Up @@ -38,6 +38,14 @@
o[field] = value;
}

public static inline function getProperty( o : Dynamic, field : String ) : Dynamic {
return Reflect.field(o,field);
}

public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void {
setField(o,field,value);
}

public inline static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic untyped {
return func.apply(o,args);
}
Expand Down
10 changes: 10 additions & 0 deletions std/js/_std/Reflect.hx
Expand Up @@ -47,6 +47,16 @@
o[field] = value;
}

public static inline function getProperty( o : Dynamic, field : String ) : Dynamic untyped {
var tmp;
return if( o == null ) null else if( o.__properties__ && (tmp=o.__properties__["get_"+field]) ) o[tmp]() else o[field];
}

public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
var tmp;
if( o.__properties__ && (tmp=o.__properties__["set_"+field]) ) o[tmp](value) else o[field] = value;
}

public inline static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic untyped {
return func.apply(o,args);
}
Expand Down
8 changes: 5 additions & 3 deletions std/js/_std/Type.hx
Expand Up @@ -117,14 +117,16 @@ enum ValueType {
var a = [];
untyped __js__("for(var i in c.prototype) a.push(i)");
a.remove("__class__");
a.remove("__properties__");
return a;
}

public static function getClassFields( c : Class<Dynamic> ) : Array<String> {
var a = Reflect.fields(c);
a.remove(__unprotect__("__name__"));
a.remove(__unprotect__("__interfaces__"));
a.remove(__unprotect__("__super__"));
a.remove("__name__");
a.remove("__interfaces__");
a.remove("__properties__");
a.remove("__super__");
a.remove("prototype");
return a;
}
Expand Down
42 changes: 27 additions & 15 deletions std/neko/_std/Reflect.hx
Expand Up @@ -26,63 +26,75 @@
@:core_api class Reflect {

public static function hasField( o : Dynamic, field : String ) : Bool untyped {
return __dollar__typeof(o) == __dollar__tobject && __dollar__objfield(o,__dollar__hash(field.__s));
return $typeof(o) == $tobject && $objfield(o,$hash(field.__s));
}

public inline static function field( o : Dynamic, field : String ) : Dynamic untyped {
return if( __dollar__typeof(o) != __dollar__tobject ) null else __dollar__objget(o,__dollar__hash(field.__s));
return if( $typeof(o) != $tobject ) null else $objget(o,$hash(field.__s));
}

public inline static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
if( __dollar__typeof(o) == __dollar__tobject )
__dollar__objset(o,__dollar__hash(field.__s),value);
if( $typeof(o) == $tobject )
$objset(o,$hash(field.__s),value);
}

public static inline function getProperty( o : Dynamic, field : String ) : Dynamic untyped {
var tmp;
return if( $typeof(o) != $tobject ) null else if( o.__properties__ != null && (tmp=$objget(o.__properties__,$hash("get_".__s+field.__s))) != null ) $call($objget(o,$hash(tmp)),o,$array()) else $objget(o,$hash(field.__s));
}

public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
if( $typeof(o) == $tobject ) {
var tmp;
if( o.__properties__ != null && (tmp=$objget(o.__properties__,$hash("set_".__s+field.__s))) != null ) $call($objget(o,$hash(tmp)),o,$array(value)) else $objset(o,$hash(field.__s),value);
}
}

public inline static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic untyped {
return __dollar__call(func,o,args.__neko());
return $call(func,o,args.__neko());
}

public static function fields( o : Dynamic ) : Array<String> untyped {
if( __dollar__typeof(o) != __dollar__tobject )
if( $typeof(o) != $tobject )
return new Array<String>();
else {
var a : neko.NativeArray<Int> = __dollar__objfields(o);
var a : neko.NativeArray<Int> = $objfields(o);
var i = 0;
var l = __dollar__asize(a);
var l = $asize(a);
while( i < l ) {
a[i] = new String(__dollar__field(a[i]));
a[i] = new String($field(a[i]));
i++;
}
return Array.new1(a,l);
}
}

public static function isFunction( f : Dynamic ) : Bool untyped {
return __dollar__typeof(f) == __dollar__tfunction;
return $typeof(f) == $tfunction;
}

public inline static function compare<T>( a : T, b : T ) : Int {
return untyped __dollar__compare(a,b);
return untyped $compare(a,b);
}

public inline static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool {
return same_closure(f1,f2);
}

public static function isObject( v : Dynamic ) : Bool untyped {
return __dollar__typeof(v) == __dollar__tobject && v.__enum__ == null;
return $typeof(v) == $tobject && v.__enum__ == null;
}

public inline static function deleteField( o : Dynamic, f : String ) : Bool untyped {
return __dollar__objremove(o,__dollar__hash(f.__s));
return $objremove(o,$hash(f.__s));
}

public inline static function copy<T>( o : T ) : T {
return untyped __dollar__new(o);
return untyped $new(o);
}

public static function makeVarArgs( f : Array<Dynamic> -> Dynamic ) : Dynamic {
return untyped __dollar__varargs(function(a) { return f(Array.new1(a,__dollar__asize(a))); });
return untyped $varargs(function(a) { return f(Array.new1(a,$asize(a))); });
}

#if neko
Expand Down
4 changes: 3 additions & 1 deletion std/neko/_std/Type.hx
Expand Up @@ -140,6 +140,7 @@ enum ValueType {
a.remove("__class__");
a.remove("__serialize");
a.remove("__string");
a.remove("__properties__");
return a;
}

Expand All @@ -150,6 +151,7 @@ enum ValueType {
a.remove("__super__");
a.remove("__string");
a.remove("__construct__");
a.remove("__properties__");
a.remove("prototype");
a.remove("new");
#if macro
Expand Down Expand Up @@ -211,7 +213,7 @@ enum ValueType {
public inline static function enumIndex( e : Dynamic ) : Int {
return e.index;
}

public static function allEnums<T>( e : Enum<T> ) : Array<T> {
var all = [];
var cst : Array<String> = untyped e.__constructs__;
Expand Down
8 changes: 8 additions & 0 deletions std/php/_std/Reflect.hx
Expand Up @@ -37,6 +37,14 @@
untyped __setfield__(o, field, value);
}

public static inline function getProperty( o : Dynamic, field : String ) : Dynamic {
return Reflect.field(o,field);
}

public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void {
setField(o,field,value);
}

public static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic untyped {
if (__call__("is_string", o) && !__call__("is_array", func)) {
return __call__("call_user_func_array", field(o, func), __field__(args, "»a"));
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/Test.hx
Expand Up @@ -117,7 +117,7 @@ class Test #if swf_mark implements mt.Protect #end #if as3 implements haxe.Publi
}
haxe.Log.trace(msg,pos);
reportCount++;
if( reportCount == 10 ) {
if( reportCount == 20 ) {
trace("Too many errors");
report = function(msg,?pos) {};
}
Expand Down

0 comments on commit 2393d91

Please sign in to comment.