247 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
			
		
		
	
	
			247 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
/*
 | 
						|
 * 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];
 | 
						|
	}
 | 
						|
}
 |