Boot.hx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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)
  31. (cast js.lib.Error).captureStackTrace(this, HaxeError);
  32. }
  33. public static function wrap(val:Dynamic):js.lib.Error {
  34. return if (js.Syntax.instanceof(val, js.lib.Error)) val else new HaxeError(val);
  35. }
  36. static function __init__() {
  37. js.lib.Object.defineProperty((cast HaxeError).prototype, "message", {get: () -> (cast String)(js.Lib.nativeThis.val)});
  38. }
  39. }
  40. @:dox(hide)
  41. class Boot {
  42. static inline function isClass(o:Dynamic):Bool {
  43. return untyped __define_feature__("js.Boot.isClass", o.__name__);
  44. }
  45. static inline function isInterface(o:Class<Dynamic>):Bool {
  46. return untyped __define_feature__("js.Boot.isInterface", o.__isInterface__);
  47. }
  48. static inline function isEnum(e:Dynamic):Bool {
  49. return untyped __define_feature__("js.Boot.isEnum", e.__ename__);
  50. }
  51. @:pure static function getClass(o:Null<Dynamic>):Null<Dynamic> {
  52. if (o == null) {
  53. return null;
  54. } else if (Std.is(o, Array)) {
  55. return Array;
  56. } else {
  57. var cl = untyped __define_feature__("js.Boot.getClass", o.__class__);
  58. if (cl != null)
  59. return cl;
  60. var name = __nativeClassName(o);
  61. if (name != null)
  62. return __resolveNativeClass(name);
  63. return null;
  64. }
  65. }
  66. @:ifFeature("has_enum")
  67. private static function __string_rec(o, s:String) {
  68. untyped {
  69. if (o == null)
  70. return "null";
  71. if (s.length >= 5)
  72. return "<...>"; // too much deep recursion
  73. var t = js.Syntax.typeof(o);
  74. if (t == "function" && (isClass(o) || isEnum(o)))
  75. t = "object";
  76. switch (t) {
  77. case "object":
  78. #if !js_enums_as_arrays
  79. __feature__("has_enum", if (o.__enum__) {
  80. var e = $hxEnums[o.__enum__];
  81. var n = e.__constructs__[o._hx_index];
  82. var con = e[n];
  83. if (con.__params__) {
  84. s += "\t";
  85. return n + "(" + [for (p in (con.__params__ : Array<String>)) __string_rec(o[p], s)].join(",") + ")";
  86. } else {
  87. return n;
  88. }
  89. });
  90. #end
  91. if (js.Syntax.instanceof(o, Array)) {
  92. #if js_enums_as_arrays
  93. __feature__("has_enum", if (o.__enum__) {
  94. if (o.length == 2)
  95. return o[0];
  96. var str = o[0] + "(";
  97. s += "\t";
  98. for (i in 2...o.length) {
  99. if (i != 2)
  100. str += "," + __string_rec(o[i], s);
  101. else
  102. str += __string_rec(o[i], s);
  103. }
  104. return str + ")";
  105. });
  106. #end
  107. var str = "[";
  108. s += "\t";
  109. for (i in 0...o.length)
  110. str += (if (i > 0) "," else "") + __string_rec(o[i], s);
  111. str += "]";
  112. return str;
  113. }
  114. var tostr;
  115. try {
  116. tostr = untyped o.toString;
  117. } catch (e:Dynamic) {
  118. // strange error on IE
  119. return "???";
  120. }
  121. if (tostr != null && tostr != __js__("Object.toString") && js.Syntax.typeof(tostr) == "function") {
  122. var s2 = o.toString();
  123. if (s2 != "[object Object]")
  124. return s2;
  125. }
  126. var str = "{\n";
  127. s += "\t";
  128. var hasp = (o.hasOwnProperty != null);
  129. var k:String = null;
  130. __js__("for( {0} in {1} ) {", k, o);
  131. if (hasp && !o.hasOwnProperty(k))
  132. __js__("continue");
  133. if (k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__")
  134. __js__("continue");
  135. if (str.length != 2)
  136. str += ", \n";
  137. str += s + k + " : " + __string_rec(o[k], s);
  138. __js__("}");
  139. s = s.substring(1);
  140. str += "\n" + s + "}";
  141. return str;
  142. case "function":
  143. return "<function>";
  144. case "string":
  145. return o;
  146. default:
  147. return String(o);
  148. }
  149. }
  150. }
  151. @:pure private static function __interfLoop(cc:Dynamic, cl:Dynamic) {
  152. if (cc == null)
  153. return false;
  154. if (cc == cl)
  155. return true;
  156. if (js.lib.Object.prototype.hasOwnProperty.call(cc, "__interfaces__")) {
  157. var intf:Dynamic = cc.__interfaces__;
  158. for (i in 0...intf.length) {
  159. var i:Dynamic = intf[i];
  160. if (i == cl || __interfLoop(i, cl))
  161. return true;
  162. }
  163. }
  164. return __interfLoop(cc.__super__, cl);
  165. }
  166. @:ifFeature("typed_catch") @:pure private static function __instanceof(o:Dynamic, cl:Dynamic) {
  167. if (cl == null)
  168. return false;
  169. switch (cl) {
  170. case Int:
  171. return js.Syntax.typeof(o) == "number" && js.Syntax.strictEq(o | 0, o);
  172. case Float:
  173. return js.Syntax.typeof(o) == "number";
  174. case Bool:
  175. return js.Syntax.typeof(o) == "boolean";
  176. case String:
  177. return js.Syntax.typeof(o) == "string";
  178. case Array:
  179. return js.Syntax.instanceof(o, Array) #if js_enums_as_arrays && o.__enum__ == null #end;
  180. case Dynamic:
  181. return o != null;
  182. default:
  183. if (o != null) {
  184. // Check if o is an instance of a Haxe class or a native JS object
  185. if (js.Syntax.typeof(cl) == "function") {
  186. if (__downcastCheck(o, cl))
  187. return true;
  188. } else if (js.Syntax.typeof(cl) == "object" && __isNativeObj(cl)) {
  189. if (js.Syntax.instanceof(o, cl))
  190. return true;
  191. }
  192. } else {
  193. return false;
  194. }
  195. // do not use isClass/isEnum here
  196. untyped __feature__("Class.*", if (cl == Class && o.__name__ != null) return true);
  197. untyped __feature__("Enum.*", if (cl == Enum && o.__ename__ != null) return true);
  198. #if js_enums_as_arrays
  199. return o.__enum__ == cl;
  200. #else
  201. return untyped __feature__(
  202. "has_enum",
  203. if (o.__enum__ != null) ($hxEnums[o.__enum__]) == cl else false,
  204. false
  205. );
  206. #end
  207. }
  208. }
  209. static function __downcastCheck(o:Dynamic, cl:Class<Dynamic>):Bool {
  210. return js.Syntax.instanceof(o, cl) || (isInterface(cl) && inline __implements(o, cl));
  211. }
  212. static function __implements(o:Dynamic, iface:Class<Dynamic>):Bool {
  213. return __interfLoop(getClass(o), iface);
  214. }
  215. @:ifFeature("typed_cast") private static function __cast(o:Dynamic, t:Dynamic) {
  216. if (o == null || __instanceof(o, t))
  217. return o;
  218. else
  219. throw "Cannot cast " + Std.string(o) + " to " + Std.string(t);
  220. }
  221. static var __toStr:js.lib.Function;
  222. static function __init__() {
  223. Boot.__toStr = (cast {}).toString;
  224. }
  225. // get native JS [[Class]]
  226. static function __nativeClassName(o:Dynamic):String {
  227. var name:String = __toStr.call(o).slice(8, -1);
  228. // exclude general Object and Function
  229. // also exclude Math and JSON, because instanceof cannot be called on them
  230. if (name == "Object" || name == "Function" || name == "Math" || name == "JSON")
  231. return null;
  232. return name;
  233. }
  234. // check for usable native JS object
  235. static function __isNativeObj(o:Dynamic):Bool {
  236. return __nativeClassName(o) != null;
  237. }
  238. // resolve native JS class in the global scope:
  239. static function __resolveNativeClass(name:String) {
  240. return js.Lib.global[cast name];
  241. }
  242. }