Boot.hx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * Copyright (C)2005-2019 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package js;
  23. import js.Syntax; // import it here so it's always available in the compiler
  24. private class HaxeError extends js.lib.Error {
  25. var val:Dynamic;
  26. @:pure
  27. public function new(val:Dynamic) {
  28. super();
  29. this.val = val;
  30. if ((cast js.lib.Error).captureStackTrace) (cast js.lib.Error).captureStackTrace(this, HaxeError);
  31. }
  32. public static function wrap(val:Dynamic):js.lib.Error {
  33. return if (js.Syntax.instanceof(val, js.lib.Error)) val else new HaxeError(val);
  34. }
  35. static function __init__() {
  36. js.lib.Object.defineProperty((cast HaxeError).prototype, "message", {get: () -> (cast String)(js.Lib.nativeThis.val)});
  37. }
  38. }
  39. @:dox(hide)
  40. class Boot {
  41. static inline function isClass(o:Dynamic) : Bool {
  42. return untyped __define_feature__("js.Boot.isClass", o.__name__);
  43. }
  44. static inline function isEnum(e:Dynamic) : Bool {
  45. return untyped __define_feature__("js.Boot.isEnum", e.__ename__);
  46. }
  47. static function getClass(o:Dynamic) : Dynamic {
  48. if (Std.is(o, Array))
  49. return Array;
  50. else {
  51. var cl = untyped __define_feature__("js.Boot.getClass", o.__class__);
  52. if (cl != null)
  53. return cl;
  54. var name = __nativeClassName(o);
  55. if (name != null)
  56. return __resolveNativeClass(name);
  57. return null;
  58. }
  59. }
  60. @:ifFeature("has_enum")
  61. private static function __string_rec(o,s:String) {
  62. untyped {
  63. if( o == null )
  64. return "null";
  65. if( s.length >= 5 )
  66. return "<...>"; // too much deep recursion
  67. var t = js.Syntax.typeof(o);
  68. if( t == "function" && (isClass(o) || isEnum(o)) )
  69. t = "object";
  70. switch( t ) {
  71. case "object":
  72. #if !js_enums_as_arrays
  73. if (o.__enum__) {
  74. var e = $hxEnums[o.__enum__];
  75. var n = e.__constructs__[o._hx_index];
  76. var con = e[n];
  77. if (con.__params__) {
  78. s += "\t";
  79. return n + "(" +
  80. [for (p in (con.__params__:Array<String>)) __string_rec(o[p],s)].join(",") + ")";
  81. } else {
  82. return n;
  83. }
  84. }
  85. #end
  86. if( js.Syntax.instanceof(o, Array) ) {
  87. #if js_enums_as_arrays
  88. if( o.__enum__ ) {
  89. if( o.length == 2 )
  90. return o[0];
  91. var str = o[0]+"(";
  92. s += "\t";
  93. for( i in 2...o.length ) {
  94. if( i != 2 )
  95. str += "," + __string_rec(o[i],s);
  96. else
  97. str += __string_rec(o[i],s);
  98. }
  99. return str + ")";
  100. }
  101. #end
  102. var str = "[";
  103. s += "\t";
  104. for( i in 0...o.length )
  105. str += (if (i > 0) "," else "")+__string_rec(o[i],s);
  106. str += "]";
  107. return str;
  108. }
  109. var tostr;
  110. try {
  111. tostr = untyped o.toString;
  112. } catch( e : Dynamic ) {
  113. // strange error on IE
  114. return "???";
  115. }
  116. if( tostr != null && tostr != __js__("Object.toString") && js.Syntax.typeof(tostr) == "function" ) {
  117. var s2 = o.toString();
  118. if( s2 != "[object Object]")
  119. return s2;
  120. }
  121. var str = "{\n";
  122. s += "\t";
  123. var hasp = (o.hasOwnProperty != null);
  124. var k : String = null;
  125. __js__("for( {0} in {1} ) {", k, o);
  126. if( hasp && !o.hasOwnProperty(k) )
  127. __js__("continue");
  128. if( k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__" )
  129. __js__("continue");
  130. if( str.length != 2 )
  131. str += ", \n";
  132. str += s + k + " : "+__string_rec(o[k],s);
  133. __js__("}");
  134. s = s.substring(1);
  135. str += "\n" + s + "}";
  136. return str;
  137. case "function":
  138. return "<function>";
  139. case "string":
  140. return o;
  141. default:
  142. return String(o);
  143. }
  144. }
  145. }
  146. private static function __interfLoop(cc : Dynamic,cl : Dynamic) {
  147. if( cc == null )
  148. return false;
  149. if( cc == cl )
  150. return true;
  151. if( js.lib.Object.prototype.hasOwnProperty.call(cc, "__interfaces__") ) {
  152. var intf : Dynamic = cc.__interfaces__;
  153. for( i in 0...intf.length ) {
  154. var i : Dynamic = intf[i];
  155. if( i == cl || __interfLoop(i,cl) )
  156. return true;
  157. }
  158. }
  159. return __interfLoop(cc.__super__,cl);
  160. }
  161. @:ifFeature("typed_catch") @:pure private static function __instanceof(o : Dynamic,cl : Dynamic) {
  162. if( cl == null )
  163. return false;
  164. switch( cl ) {
  165. case Int:
  166. return js.Syntax.typeof(o) == "number" && js.Syntax.strictEq(o | 0, o);
  167. case Float:
  168. return js.Syntax.typeof(o) == "number";
  169. case Bool:
  170. return js.Syntax.typeof(o) == "boolean";
  171. case String:
  172. return js.Syntax.typeof(o) == "string";
  173. case Array:
  174. return js.Syntax.instanceof(o, Array) #if js_enums_as_arrays && o.__enum__ == null #end;
  175. case Dynamic:
  176. return o != null;
  177. default:
  178. if( o != null ) {
  179. // Check if o is an instance of a Haxe class or a native JS object
  180. if( js.Syntax.typeof(cl) == "function" ) {
  181. if( js.Syntax.instanceof(o, cl) )
  182. return true;
  183. if( __interfLoop(getClass(o),cl) )
  184. return true;
  185. }
  186. else if ( js.Syntax.typeof(cl) == "object" && __isNativeObj(cl) ) {
  187. if( js.Syntax.instanceof(o, cl) )
  188. return true;
  189. }
  190. } else {
  191. return false;
  192. }
  193. // do not use isClass/isEnum here
  194. untyped __feature__("Class.*",if( cl == Class && o.__name__ != null ) return true);
  195. untyped __feature__("Enum.*",if( cl == Enum && o.__ename__ != null ) return true);
  196. #if js_enums_as_arrays
  197. return o.__enum__ == cl;
  198. #else
  199. return if (o.__enum__ != null) (untyped $hxEnums[o.__enum__]) == cl else false;
  200. #end
  201. }
  202. }
  203. @:ifFeature("typed_cast") private static function __cast(o : Dynamic, t : Dynamic) {
  204. if (o == null || __instanceof(o, t)) return o;
  205. else throw "Cannot cast " +Std.string(o) + " to " +Std.string(t);
  206. }
  207. static var __toStr:js.lib.Function;
  208. static function __init__() {
  209. Boot.__toStr = (cast {}).toString;
  210. }
  211. // get native JS [[Class]]
  212. static function __nativeClassName(o:Dynamic):String {
  213. var name:String = __toStr.call(o).slice(8, -1);
  214. // exclude general Object and Function
  215. // also exclude Math and JSON, because instanceof cannot be called on them
  216. if (name == "Object" || name == "Function" || name == "Math" || name == "JSON")
  217. return null;
  218. return name;
  219. }
  220. // check for usable native JS object
  221. static function __isNativeObj(o:Dynamic):Bool {
  222. return __nativeClassName(o) != null;
  223. }
  224. // resolve native JS class in the global scope:
  225. static function __resolveNativeClass(name:String) {
  226. return js.Lib.global[cast name];
  227. }
  228. }