123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- /*
- * Copyright (C)2005-2019 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- package js;
- import js.Syntax; // import it here so it's always available in the compiler
- @:dox(hide)
- class Boot {
- static inline function isClass(o:Dynamic):Bool {
- return untyped __define_feature__("js.Boot.isClass", o.__name__);
- }
- static inline function isInterface(o:Class<Dynamic>):Bool {
- return untyped __define_feature__("js.Boot.isInterface", o.__isInterface__);
- }
- static inline function isEnum(e:Dynamic):Bool {
- return untyped __define_feature__("js.Boot.isEnum", e.__ename__);
- }
- @:pure static function getClass(o:Null<Dynamic>):Null<Dynamic> {
- if (o == null) {
- return null;
- } else if (Std.isOfType(o, Array)) {
- return Array;
- } else {
- var cl = untyped __define_feature__("js.Boot.getClass", o.__class__);
- if (cl != null)
- return cl;
- var name = __nativeClassName(o);
- if (name != null)
- return __resolveNativeClass(name);
- return null;
- }
- }
- @:ifFeature("has_enum")
- private static function __string_rec(o, s:String) {
- untyped {
- if (o == null)
- return "null";
- if (s.length >= 5)
- return "<...>"; // too much deep recursion
- var t = js.Syntax.typeof(o);
- if (t == "function" && (isClass(o) || isEnum(o)))
- t = "object";
- switch (t) {
- case "object":
- #if !js_enums_as_arrays
- __feature__("has_enum", if (o.__enum__) {
- var e = $hxEnums[o.__enum__];
- var con = e.__constructs__[o._hx_index];
- var n = con._hx_name;
- if (con.__params__) {
- s += "\t";
- return n + "(" + [for (p in (con.__params__ : Array<String>)) __string_rec(o[p], s)].join(",") + ")";
- } else {
- return n;
- }
- });
- #end
- if (js.Syntax.instanceof(o, Array)) {
- #if js_enums_as_arrays
- __feature__("has_enum", if (o.__enum__) {
- if (o.length == 2)
- return o[0];
- var str = o[0] + "(";
- s += "\t";
- for (i in 2...o.length) {
- if (i != 2)
- str += "," + __string_rec(o[i], s);
- else
- str += __string_rec(o[i], s);
- }
- return str + ")";
- });
- #end
- var str = "[";
- s += "\t";
- for (i in 0...o.length)
- str += (if (i > 0) "," else "") + __string_rec(o[i], s);
- str += "]";
- return str;
- }
- var tostr;
- try {
- tostr = untyped o.toString;
- } catch (e:Dynamic) {
- // strange error on IE
- return "???";
- }
- if (tostr != null && tostr != js.Syntax.code("Object.toString") && js.Syntax.typeof(tostr) == "function") {
- var s2 = o.toString();
- if (s2 != "[object Object]")
- return s2;
- }
- var str = "{\n";
- s += "\t";
- var hasp = (o.hasOwnProperty != null);
- var k:String = null;
- js.Syntax.code("for( {0} in {1} ) {", k, o);
- if (hasp && !o.hasOwnProperty(k))
- js.Syntax.code("continue");
- if (k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__")
- js.Syntax.code("continue");
- if (str.length != 2)
- str += ", \n";
- str += s + k + " : " + __string_rec(o[k], s);
- js.Syntax.code("}");
- s = s.substring(1);
- str += "\n" + s + "}";
- return str;
- case "function":
- return "<function>";
- case "string":
- return o;
- default:
- return String(o);
- }
- }
- }
- @:pure private static function __interfLoop(cc:Dynamic, cl:Dynamic) {
- if (cc == null)
- return false;
- if (cc == cl)
- return true;
- var intf:Dynamic = cc.__interfaces__;
- if (intf != null
- // ES6 classes inherit statics, so we want to avoid accessing inherited `__interfaces__`
- #if (js_es >= 6) && (cc.__super__ == null || cc.__super__.__interfaces__ != intf) #end
- ) {
- for (i in 0...intf.length) {
- var i:Dynamic = intf[i];
- if (i == cl || __interfLoop(i, cl))
- return true;
- }
- }
- return __interfLoop(cc.__super__, cl);
- }
- @:pure private static function __instanceof(o:Dynamic, cl:Dynamic) {
- if (cl == null)
- return false;
- switch (cl) {
- case Int:
- return js.Syntax.typeof(o) == "number" && js.Syntax.strictEq(o | 0, o);
- case Float:
- return js.Syntax.typeof(o) == "number";
- case Bool:
- return js.Syntax.typeof(o) == "boolean";
- case String:
- return js.Syntax.typeof(o) == "string";
- case Array:
- return js.Syntax.instanceof(o, Array) #if js_enums_as_arrays && o.__enum__ == null #end;
- case Dynamic:
- return o != null;
- default:
- if (o != null) {
- // Check if o is an instance of a Haxe class or a native JS object
- if (js.Syntax.typeof(cl) == "function") {
- if (__downcastCheck(o, cl))
- return true;
- } else if (js.Syntax.typeof(cl) == "object" && __isNativeObj(cl)) {
- if (js.Syntax.instanceof(o, cl))
- return true;
- }
- } else {
- return false;
- }
- // do not use isClass/isEnum here
- untyped __feature__("Class.*", if (cl == Class && o.__name__ != null) return true);
- untyped __feature__("Enum.*", if (cl == Enum && o.__ename__ != null) return true);
- #if js_enums_as_arrays
- return o.__enum__ == cl;
- #else
- return untyped __feature__(
- "has_enum",
- if (o.__enum__ != null) ($hxEnums[o.__enum__]) == cl else false,
- false
- );
- #end
- }
- }
- static function __downcastCheck(o:Dynamic, cl:Class<Dynamic>):Bool {
- return js.Syntax.instanceof(o, cl) || (isInterface(cl) && inline __implements(o, cl));
- }
- static function __implements(o:Dynamic, iface:Class<Dynamic>):Bool {
- return __interfLoop(getClass(o), iface);
- }
- @:ifFeature("typed_cast") private static function __cast(o:Dynamic, t:Dynamic) {
- if (o == null || __instanceof(o, t))
- return o;
- else
- throw "Cannot cast " + Std.string(o) + " to " + Std.string(t);
- }
- static var __toStr:js.lib.Function;
- static function __init__() {
- Boot.__toStr = (cast {}).toString;
- }
- // get native JS [[Class]]
- static function __nativeClassName(o:Dynamic):String {
- var name:String = __toStr.call(o).slice(8, -1);
- // exclude general Object and Function
- // also exclude Math and JSON, because instanceof cannot be called on them
- if (name == "Object" || name == "Function" || name == "Math" || name == "JSON")
- return null;
- return name;
- }
- // check for usable native JS object
- static function __isNativeObj(o:Dynamic):Bool {
- return __nativeClassName(o) != null;
- }
- // resolve native JS class in the global scope:
- static function __resolveNativeClass(name:String) {
- return js.Lib.global[cast name];
- }
- }
|