Reflect.hx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*
  2. * Copyright (c) 2005, The haXe Project Contributors
  3. * All rights reserved.
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. *
  7. * - Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * - Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
  17. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  19. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  20. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  23. * DAMAGE.
  24. */
  25. /**
  26. The Reflect API is a way to manipulate values dynamicly through an
  27. abstract interface in an untyped manner. Use with care.
  28. **/
  29. class Reflect {
  30. /**
  31. Tells if an object has a field set. This doesn't take into account the object prototype (class methods).
  32. **/
  33. public #if php inline #end static function hasField( o : Dynamic, field : String ) : Bool untyped {
  34. #if flash9
  35. return o.hasOwnProperty( field );
  36. #elseif flash
  37. return this["hasOwnProperty"]["call"](o,field);
  38. #elseif js
  39. if( o.hasOwnProperty != null )
  40. return o.hasOwnProperty(field);
  41. var arr = fields(o);
  42. for( t in arr.iterator() )
  43. if( t == field ) return true;
  44. return false;
  45. #elseif neko
  46. return __dollar__typeof(o) == __dollar__tobject && __dollar__objfield(o,__dollar__hash(field.__s));
  47. #elseif php
  48. return __call__("_hx_has_field", o, field);
  49. #else
  50. return false;
  51. #end
  52. }
  53. /**
  54. Returns the field of an object, or null if [o] is not an object or doesn't have this field.
  55. **/
  56. public inline static function field( o : Dynamic, field : String ) : Dynamic untyped {
  57. #if flash9
  58. return (o == null) ? null : o[field];
  59. #elseif flash
  60. return o[field];
  61. #elseif js
  62. var v = null;
  63. try {
  64. v = o[field];
  65. } catch( e : Dynamic ) {
  66. }
  67. return v;
  68. #elseif neko
  69. return if( __dollar__typeof(o) != __dollar__tobject ) null else __dollar__objget(o,__dollar__hash(field.__s));
  70. #elseif php
  71. return __call__("_hx_field", o, field);
  72. #else
  73. return null;
  74. #end
  75. }
  76. /**
  77. Set an object field value.
  78. **/
  79. public #if !php inline #end static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
  80. #if flash
  81. o[field] = value;
  82. #elseif js
  83. o[field] = value;
  84. #elseif neko
  85. if( __dollar__typeof(o) == __dollar__tobject )
  86. __dollar__objset(o,__dollar__hash(field.__s),value);
  87. #elseif php
  88. untyped __php__("$o->$field = $value");
  89. #end
  90. }
  91. /**
  92. Call a method with the given object and arguments.
  93. **/
  94. public #if !php inline #end static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic untyped {
  95. #if flash9
  96. return func.apply(o,args);
  97. #elseif flash
  98. return func["apply"](o,args);
  99. #elseif js
  100. return func.apply(o,args);
  101. #elseif neko
  102. return __dollar__call(func,o,args.__neko());
  103. #elseif php
  104. if(__call__("is_string", o) || __call__("is_array", o)) {
  105. if(args.length == 0) return __call__("call_user_func", field(o, func));
  106. else if(args.length == 1) return __call__("call_user_func", field(o, func), args[0]);
  107. else return __call__("call_user_func", field(o, func), args[0], args[1]);
  108. }
  109. return __php__("call_user_func_array(is_callable($func) ? $func : array($o, $func) , $args)");
  110. #else
  111. return null;
  112. #end
  113. }
  114. /**
  115. Returns the list of fields of an object, excluding its prototype (class methods).
  116. **/
  117. public static function fields( o : Dynamic ) : Array<String> untyped {
  118. if( o == null ) return new Array();
  119. #if flash9
  120. var a : Array<String> = __keys__(o);
  121. var i = 0;
  122. while( i < a.length ){
  123. if( !o.hasOwnProperty(a[i]) )
  124. a.splice(i,1);
  125. else
  126. ++i;
  127. }
  128. return a;
  129. #elseif flash
  130. var a : Array<String> = __keys__(o);
  131. var i = 0;
  132. while( i < a.length ) {
  133. if( !a["hasOwnProperty"]["call"](o,a[i]) )
  134. a.splice(i,1);
  135. else
  136. ++i;
  137. }
  138. return a;
  139. #elseif js
  140. var a = new Array();
  141. if( o.hasOwnProperty ) {
  142. __js__("
  143. for(var i in o)
  144. if( o.hasOwnProperty(i) )
  145. a.push(i);
  146. ");
  147. } else {
  148. var t;
  149. try{ t = o.__proto__; } catch( e : Dynamic ) { t = null; }
  150. if( t != null )
  151. o.__proto__ = null;
  152. __js__("
  153. for(var i in o)
  154. if( i != \"__proto__\" )
  155. a.push(i);
  156. ");
  157. if( t != null )
  158. o.__proto__ = t;
  159. }
  160. return a;
  161. #elseif neko
  162. if( __dollar__typeof(o) != __dollar__tobject )
  163. return new Array<String>();
  164. else {
  165. var a = __dollar__objfields(o);
  166. var i = 0;
  167. var l = __dollar__asize(a);
  168. while( i < l ) {
  169. a[i] = new String(__dollar__field(a[i]));
  170. i++;
  171. }
  172. return Array.new1(a,l);
  173. }
  174. #elseif php
  175. return __call__('is_array', o)
  176. ? __call__('array', 'concat', 'copy', 'insert', 'iterator', 'length', 'join', 'pop', 'push', 'remove', 'reverse', 'shift', 'slice', 'sort', 'splice', 'toString', 'unshift')
  177. : (__call__('is_string', o)
  178. ? __call__('array', 'charAt', 'charCodeAt', 'indexOf', 'lastIndexOf', 'length', 'split', 'substr', 'toLowerCase', 'toString', 'toUpperCase')
  179. : __call__('array_keys', __call__('get_object_vars', o)));
  180. #else
  181. return new Array();
  182. #end
  183. }
  184. /**
  185. Tells if a value is a function or not.
  186. **/
  187. public static function isFunction( f : Dynamic ) : Bool untyped {
  188. #if flash9
  189. return __typeof__(f) == "function";
  190. #elseif flash
  191. return __typeof__(f) == "function" && f.__name__ == null;
  192. #elseif js
  193. return __js__("typeof(f)") == "function" && f.__name__ == null;
  194. #elseif neko
  195. return __dollar__typeof(f) == __dollar__tfunction;
  196. #elseif php
  197. return __php__("(is_array($f) && is_callable($f)) || _hx_is_lambda($f)") || (__php__("is_array($f)") && hasField(f[0], f[1]) && f[1] != "length");
  198. #else
  199. return false;
  200. #end
  201. }
  202. /**
  203. Generic comparison function, does not work for methods, see [compareMethods]
  204. **/
  205. public static function compare<T>( a : T, b : T ) : Int {
  206. #if neko
  207. return untyped __dollar__compare(a,b);
  208. #else
  209. return ( a == b ) ? 0 : (((cast a) > (cast b)) ? 1 : -1);
  210. #end
  211. }
  212. /**
  213. Compare two methods closures. Returns true if it's the same method of the same instance.
  214. Does not work on Neko platform.
  215. **/
  216. public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool {
  217. #if !neko
  218. if( f1 == f2 )
  219. return true;
  220. if( !isFunction(f1) || !isFunction(f2) )
  221. return false;
  222. #end
  223. #if neko
  224. return same_closure(f1,f2);
  225. #elseif flash9
  226. return false; // VM-level closures
  227. #elseif flash
  228. return untyped f1["f"] == f2["f"] && f1["o"] == f2["o"] && f1["f"] != null;
  229. #elseif js
  230. return f1.scope == f2.scope && f1.method == f2.method && f1.method != null;
  231. #elseif php
  232. if(untyped __call__("is_array", f1) && untyped __call__("is_array", f1))
  233. return f1[0] == f2[0] && f1[1] == f2[1];
  234. if(untyped __call__("is_string", f1) && untyped __call__("is_string", f2))
  235. return f1 == f2;
  236. return false;
  237. #else
  238. return false;
  239. #end
  240. }
  241. /**
  242. Tells if a value is an object or not.
  243. **/
  244. public static function isObject( v : Dynamic ) : Bool untyped {
  245. #if neko
  246. return __dollar__typeof(v) == __dollar__tobject && v.__enum__ == null;
  247. #elseif flash9
  248. if( v == null )
  249. return false;
  250. var t = __typeof__(v);
  251. if( t == "object" ) {
  252. try {
  253. if( v.__enum__ == true )
  254. return false;
  255. } catch( e : Dynamic ) {
  256. }
  257. return true;
  258. }
  259. return (t == "string");
  260. #elseif flash
  261. var t = __typeof__(v);
  262. return (t == "string" || (t == "object" && !v.__enum__) || (t == "function" && v.__name__ != null));
  263. #elseif js
  264. if( v == null )
  265. return false;
  266. var t = __js__("typeof(v)");
  267. return (t == "string" || (t == "object" && !v.__enum__) || (t == "function" && v.__name__ != null));
  268. #elseif php
  269. if( v == null )
  270. return false;
  271. if(__call__("is_object", v))
  272. return __php__("$v instanceof _hx_anonymous") || Type.getClass(v) != null;
  273. if(__php__("is_string($v) && !_hx_is_lambda($v)")) return true;
  274. if(__php__("is_array($v) && !is_callable($v)")) return true;
  275. return false;
  276. #else
  277. return false;
  278. #end
  279. }
  280. /**
  281. Delete an object field.
  282. **/
  283. public static function deleteField( o : Dynamic, f : String ) : Bool untyped {
  284. #if flash9
  285. if( o.hasOwnProperty(f) != true ) return false;
  286. __delete__(o,f);
  287. return true;
  288. #elseif flash
  289. if( this["hasOwnProperty"]["call"](o,f) != true ) return false;
  290. __delete__(o,f);
  291. return true;
  292. #elseif js
  293. if( !hasField(o,f) ) return false;
  294. __js__("delete")(o[f]);
  295. return true;
  296. #elseif neko
  297. return __dollar__objremove(o,__dollar__hash(f.__s));
  298. #elseif php
  299. if(!hasField(o,f)) return false;
  300. untyped __php__("unset($o->$f)");
  301. return true;
  302. #else
  303. return false;
  304. #end
  305. }
  306. /**
  307. Make a copy of the fields of an object.
  308. **/
  309. public static function copy<T>( o : T ) : T {
  310. #if neko
  311. return untyped __dollar__new(o);
  312. #else
  313. #if php
  314. if(untyped __call__("is_string", o) || untyped __call__("is_array", o)) return o;
  315. #end
  316. var o2 : Dynamic = {};
  317. for( f in Reflect.fields(o) )
  318. Reflect.setField(o2,f,Reflect.field(o,f));
  319. return o2;
  320. #end
  321. }
  322. /**
  323. Transform a function taking an array of arguments into a function that can
  324. be called with any number of arguments.
  325. **/
  326. public static function makeVarArgs( f : Array<Dynamic> -> Dynamic ) : Dynamic {
  327. #if neko
  328. return untyped __dollar__varargs(function(a) { return f(Array.new1(a,__dollar__asize(a))); });
  329. #elseif flash9
  330. return function(__arguments__) { return f(__arguments__); };
  331. #elseif js
  332. return function() untyped {
  333. var a = new Array();
  334. for( i in 0...arguments.length )
  335. a.push(arguments[i]);
  336. return f(a);
  337. };
  338. #elseif flash
  339. return function() { return f(untyped __arguments__); };
  340. #elseif php
  341. untyped __php__("return array(new _hx_lambda(array('f' => &$f), null, array('args'), 'return call_user_func_array($f, array($args));'), 'makeArgs')");
  342. #else
  343. return null;
  344. #end
  345. }
  346. #if neko
  347. static var same_closure = try neko.Lib.load("std","same_closure",2) catch( e : Dynamic ) function(f1,f2) return f1 == f2;
  348. #end
  349. }