forked from LeenkxTeam/LNXSDK
478 lines
13 KiB
Haxe
478 lines
13 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 python;
|
||
|
|
||
|
import python.internal.MethodClosure;
|
||
|
import python.internal.ArrayImpl;
|
||
|
import python.internal.Internal;
|
||
|
import python.internal.StringImpl;
|
||
|
import python.internal.EnumImpl;
|
||
|
import python.internal.HxOverrides;
|
||
|
import python.internal.AnonObject;
|
||
|
import python.internal.UBuiltins;
|
||
|
import python.lib.Inspect;
|
||
|
import python.Syntax;
|
||
|
|
||
|
@:dox(hide)
|
||
|
class Boot {
|
||
|
static var keywords:Set<String> = new Set([
|
||
|
"and", "del", "from", "not", "with", "as", "elif", "global", "or", "yield", "assert", "else", "if", "pass", "None", "break", "except", "import",
|
||
|
"raise", "True", "class", "exec", "in", "return", "False", "continue", "finally", "is", "try", "def", "for", "lambda", "while",
|
||
|
]);
|
||
|
|
||
|
inline static function arrayJoin<T>(x:Array<T>, sep:String):String {
|
||
|
return Syntax.field(sep, "join")(Syntax.code("[{0}(x1,'') for x1 in {1}]", python.Boot.toString1, x));
|
||
|
}
|
||
|
|
||
|
inline static function safeJoin(x:Array<String>, sep:String):String {
|
||
|
return Syntax.field(sep, "join")(Syntax.code("[x1 for x1 in {0}]", x));
|
||
|
}
|
||
|
|
||
|
inline static function isPyBool(o:Dynamic):Bool {
|
||
|
return UBuiltins.isinstance(o, UBuiltins.bool);
|
||
|
}
|
||
|
|
||
|
inline static function isPyInt(o:Dynamic):Bool {
|
||
|
// for historic reasons bool extends int
|
||
|
return UBuiltins.isinstance(o, UBuiltins.int) && !isPyBool(o);
|
||
|
}
|
||
|
|
||
|
inline static function isPyFloat(o:Dynamic):Bool {
|
||
|
return UBuiltins.isinstance(o, UBuiltins.float);
|
||
|
}
|
||
|
|
||
|
static inline function isClass(o:Dynamic):Bool {
|
||
|
return o != null && (o == String || Inspect.isclass(o));
|
||
|
}
|
||
|
|
||
|
static inline function isAnonObject(o:Dynamic) {
|
||
|
return UBuiltins.isinstance(o, AnonObject);
|
||
|
}
|
||
|
|
||
|
@:ifFeature("add_dynamic") private static function _add_dynamic(a:Dynamic, b:Dynamic):Dynamic {
|
||
|
if (UBuiltins.isinstance(a, String) && UBuiltins.isinstance(b, String)) {
|
||
|
return Syntax.binop(a, "+", b);
|
||
|
}
|
||
|
if (UBuiltins.isinstance(a, String) || UBuiltins.isinstance(b, String)) {
|
||
|
return Syntax.binop(toString1(a, ""), "+", toString1(b, ""));
|
||
|
}
|
||
|
return Syntax.binop(a, "+", b);
|
||
|
}
|
||
|
|
||
|
static inline function toString(o:Dynamic) {
|
||
|
return toString1(o, "");
|
||
|
}
|
||
|
|
||
|
private static function toString1(o:Dynamic, s:String):String {
|
||
|
if (o == null)
|
||
|
return "null";
|
||
|
|
||
|
if (isString(o))
|
||
|
return o;
|
||
|
|
||
|
if (s == null)
|
||
|
s = "";
|
||
|
if (s.length >= 5)
|
||
|
return "<...>"; // too much deep recursion
|
||
|
|
||
|
if (isPyBool(o)) {
|
||
|
if ((o : Bool))
|
||
|
return "true"
|
||
|
else
|
||
|
return "false";
|
||
|
}
|
||
|
if (isPyInt(o)) {
|
||
|
return UBuiltins.str(o);
|
||
|
}
|
||
|
// 1.0 should be printed as 1
|
||
|
if (isPyFloat(o)) {
|
||
|
try {
|
||
|
if ((o : Float) == UBuiltins.int(o)) {
|
||
|
return UBuiltins.str(Math.round(o));
|
||
|
} else {
|
||
|
return UBuiltins.str(o);
|
||
|
}
|
||
|
} catch (e:Dynamic) {
|
||
|
return UBuiltins.str(o);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (isArray(o)) {
|
||
|
var o1:Array<Dynamic> = o;
|
||
|
|
||
|
var l = o1.length;
|
||
|
|
||
|
var st = "[";
|
||
|
s += "\t";
|
||
|
for (i in 0...l) {
|
||
|
var prefix = "";
|
||
|
if (i > 0) {
|
||
|
prefix = ",";
|
||
|
}
|
||
|
st += prefix + toString1(o1[i], s);
|
||
|
}
|
||
|
st += "]";
|
||
|
return st;
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
if (UBuiltins.hasattr(o, "toString"))
|
||
|
return Syntax.callField(o, "toString");
|
||
|
} catch (e:Dynamic) {}
|
||
|
|
||
|
if (UBuiltins.hasattr(o, "__class__")) {
|
||
|
if (isAnonObject(o)) {
|
||
|
var toStr = null;
|
||
|
try {
|
||
|
var fields = fields(o);
|
||
|
var fieldsStr = [for (f in fields) '$f : ${toString1(simpleField(o, f), s + "\t")}'];
|
||
|
toStr = "{ " + safeJoin(fieldsStr, ", ") + " }";
|
||
|
} catch (e:Dynamic) {
|
||
|
return "{ ... }";
|
||
|
}
|
||
|
|
||
|
if (toStr == null) {
|
||
|
return "{ ... }";
|
||
|
} else {
|
||
|
return toStr;
|
||
|
}
|
||
|
}
|
||
|
if (UBuiltins.isinstance(o, Enum)) {
|
||
|
var o:EnumImpl = (o : EnumImpl);
|
||
|
|
||
|
var l = UBuiltins.len(o.params);
|
||
|
var hasParams = l > 0;
|
||
|
if (hasParams) {
|
||
|
var paramsStr = "";
|
||
|
for (i in 0...l) {
|
||
|
var prefix = "";
|
||
|
if (i > 0) {
|
||
|
prefix = ",";
|
||
|
}
|
||
|
paramsStr += prefix + toString1(o.params[i], s);
|
||
|
}
|
||
|
return o.tag + "(" + paramsStr + ")";
|
||
|
} else {
|
||
|
return o.tag;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Internal.hasClassName(o)) {
|
||
|
if (Syntax.field(Syntax.field(o, "__class__"), "__name__") != "type") {
|
||
|
var fields = getInstanceFields(o);
|
||
|
var fieldsStr = [for (f in fields) '$f : ${toString1(simpleField(o, f), s + "\t")}'];
|
||
|
|
||
|
var toStr = (Internal.fieldClassName(o) : String) + "( " + safeJoin(fieldsStr, ", ") + " )";
|
||
|
return toStr;
|
||
|
} else {
|
||
|
var fields = getClassFields(o);
|
||
|
var fieldsStr = [for (f in fields) '$f : ${toString1(simpleField(o, f), s + "\t")}'];
|
||
|
var toStr = "#" + (Internal.fieldClassName(o) : String) + "( " + safeJoin(fieldsStr, ", ") + " )";
|
||
|
return toStr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (isMetaType(o, String)) {
|
||
|
return "#String";
|
||
|
}
|
||
|
|
||
|
if (isMetaType(o, Array)) {
|
||
|
return "#Array";
|
||
|
}
|
||
|
|
||
|
if (UBuiltins.callable(o)) {
|
||
|
return "function";
|
||
|
}
|
||
|
try {
|
||
|
if (UBuiltins.hasattr(o, "__repr__")) {
|
||
|
return Syntax.callField(o, "__repr__");
|
||
|
}
|
||
|
} catch (e:Dynamic) {}
|
||
|
|
||
|
if (UBuiltins.hasattr(o, "__str__")) {
|
||
|
return Syntax.callField(o, "__str__", []);
|
||
|
}
|
||
|
|
||
|
if (UBuiltins.hasattr(o, "__name__")) {
|
||
|
return Syntax.field(o, "__name__");
|
||
|
}
|
||
|
return "???";
|
||
|
} else {
|
||
|
return UBuiltins.str(o);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline function isMetaType(v:Dynamic, t:Dynamic):Bool {
|
||
|
return Syntax.binop(Syntax.binop(Syntax.call(UBuiltins.type, [v]), "==", UBuiltins.type), "and", Syntax.binop(v, "==", t));
|
||
|
}
|
||
|
|
||
|
@:analyzer(no_local_dce)
|
||
|
static function fields(o:Dynamic) {
|
||
|
var a = [];
|
||
|
if (o != null) {
|
||
|
if (Internal.hasFields(o)) {
|
||
|
var fields = Internal.fieldFields(o);
|
||
|
if (fields != null) {
|
||
|
return (fields : Array<String>).copy();
|
||
|
}
|
||
|
}
|
||
|
if (isAnonObject(o)) {
|
||
|
var d = Syntax.field(o, "__dict__");
|
||
|
var keys = Syntax.callField(d, "keys");
|
||
|
var handler = unhandleKeywords;
|
||
|
|
||
|
Syntax.code("for k in keys:");
|
||
|
Syntax.code(" if (k != '_hx_disable_getattr'):");
|
||
|
Syntax.code(" a.append(handler(k))");
|
||
|
} else if (UBuiltins.hasattr(o, "__dict__")) {
|
||
|
var a = [];
|
||
|
var d = Syntax.field(o, "__dict__");
|
||
|
var keys1 = Syntax.callField(d, "keys");
|
||
|
Syntax.code("for k in keys1:");
|
||
|
Syntax.code(" a.append(k)");
|
||
|
}
|
||
|
}
|
||
|
return a;
|
||
|
}
|
||
|
|
||
|
static inline function isString(o:Dynamic):Bool {
|
||
|
return UBuiltins.isinstance(o, UBuiltins.str);
|
||
|
}
|
||
|
|
||
|
static inline function isArray(o:Dynamic):Bool {
|
||
|
return UBuiltins.isinstance(o, UBuiltins.list);
|
||
|
}
|
||
|
|
||
|
static function simpleField(o:Dynamic, field:String):Dynamic {
|
||
|
if (field == null)
|
||
|
return null;
|
||
|
|
||
|
var field = handleKeywords(field);
|
||
|
return if (UBuiltins.hasattr(o, field)) UBuiltins.getattr(o, field) else null;
|
||
|
}
|
||
|
|
||
|
@:ifFeature("closure_Array", "closure_String")
|
||
|
static inline function createClosure(obj:Dynamic, func:Dynamic):Dynamic {
|
||
|
return new MethodClosure(obj, func);
|
||
|
}
|
||
|
|
||
|
static function hasField(o:Dynamic, field:String):Bool {
|
||
|
if (isAnonObject(o)) {
|
||
|
return Syntax.code('{0}._hx_hasattr({1})', o, field);
|
||
|
}
|
||
|
return UBuiltins.hasattr(o, handleKeywords(field));
|
||
|
}
|
||
|
|
||
|
static function field(o:Dynamic, field:String):Dynamic {
|
||
|
if (field == null)
|
||
|
return null;
|
||
|
|
||
|
inline function def() {
|
||
|
var field = handleKeywords(field);
|
||
|
return if (UBuiltins.hasattr(o, field)) UBuiltins.getattr(o, field) else null;
|
||
|
}
|
||
|
|
||
|
return if (isString(o)) {
|
||
|
switch (field) {
|
||
|
case "length":
|
||
|
StringImpl.get_length(o);
|
||
|
case "toLowerCase":
|
||
|
createClosure(o, StringImpl.toLowerCase);
|
||
|
case "toUpperCase":
|
||
|
createClosure(o, StringImpl.toUpperCase);
|
||
|
case "charAt":
|
||
|
createClosure(o, StringImpl.charAt);
|
||
|
case "charCodeAt":
|
||
|
createClosure(o, StringImpl.charCodeAt);
|
||
|
case "indexOf":
|
||
|
createClosure(o, StringImpl.indexOf);
|
||
|
case "lastIndexOf":
|
||
|
createClosure(o, StringImpl.lastIndexOf);
|
||
|
case "split":
|
||
|
createClosure(o, StringImpl.split);
|
||
|
case "substr":
|
||
|
createClosure(o, StringImpl.substr);
|
||
|
case "substring":
|
||
|
createClosure(o, StringImpl.substring);
|
||
|
case "toString":
|
||
|
createClosure(o, StringImpl.toString);
|
||
|
default:
|
||
|
def();
|
||
|
}
|
||
|
} else if (isArray(o)) {
|
||
|
switch (field) {
|
||
|
case "length":
|
||
|
ArrayImpl.get_length(o);
|
||
|
case "map":
|
||
|
createClosure(o, ArrayImpl.map);
|
||
|
case "filter":
|
||
|
createClosure(o, ArrayImpl.filter);
|
||
|
case "concat":
|
||
|
createClosure(o, ArrayImpl.concat);
|
||
|
case "copy":
|
||
|
createClosure(o, ArrayImpl.copy);
|
||
|
case "iterator":
|
||
|
createClosure(o, ArrayImpl.iterator);
|
||
|
case "keyValueIterator":
|
||
|
createClosure(o, ArrayImpl.keyValueIterator);
|
||
|
case "insert":
|
||
|
createClosure(o, ArrayImpl.insert);
|
||
|
case "join":
|
||
|
createClosure(o, ArrayImpl.join);
|
||
|
case "toString":
|
||
|
createClosure(o, ArrayImpl.toString);
|
||
|
case "pop":
|
||
|
createClosure(o, ArrayImpl.pop);
|
||
|
case "push":
|
||
|
createClosure(o, ArrayImpl.push);
|
||
|
case "unshift":
|
||
|
createClosure(o, ArrayImpl.unshift);
|
||
|
case "indexOf":
|
||
|
createClosure(o, ArrayImpl.indexOf);
|
||
|
case "lastIndexOf":
|
||
|
createClosure(o, ArrayImpl.lastIndexOf);
|
||
|
case "contains":
|
||
|
createClosure(o, ArrayImpl.contains);
|
||
|
case "remove":
|
||
|
createClosure(o, ArrayImpl.remove);
|
||
|
case "reverse":
|
||
|
createClosure(o, ArrayImpl.reverse);
|
||
|
case "shift":
|
||
|
createClosure(o, ArrayImpl.shift);
|
||
|
case "slice":
|
||
|
createClosure(o, ArrayImpl.slice);
|
||
|
case "sort":
|
||
|
createClosure(o, ArrayImpl.sort);
|
||
|
case "splice":
|
||
|
createClosure(o, ArrayImpl.splice);
|
||
|
default:
|
||
|
def();
|
||
|
}
|
||
|
} else {
|
||
|
def();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static function getInstanceFields(c:Class<Dynamic>):Array<String> {
|
||
|
var f = if (Internal.hasFields(c)) (Internal.fieldFields(c) : Array<String>).copy() else [];
|
||
|
if (Internal.hasMethods(c))
|
||
|
f = f.concat(Internal.fieldMethods(c));
|
||
|
|
||
|
var sc = getSuperClass(c);
|
||
|
|
||
|
if (sc == null) {
|
||
|
return f;
|
||
|
} else {
|
||
|
var scArr = getInstanceFields(sc);
|
||
|
var scMap = new Set(scArr);
|
||
|
for (f1 in f) {
|
||
|
if (!scMap.has(f1)) {
|
||
|
scArr.push(f1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return scArr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static function getSuperClass(c:Class<Dynamic>):Class<Dynamic> {
|
||
|
if (c == null)
|
||
|
return null;
|
||
|
|
||
|
try {
|
||
|
if (Internal.hasSuper(c)) {
|
||
|
return Internal.fieldSuper(c);
|
||
|
}
|
||
|
return null;
|
||
|
} catch (e:Dynamic) {}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
static function getClassFields(c:Class<Dynamic>):Array<String> {
|
||
|
if (Internal.hasStatics(c)) {
|
||
|
var x:Array<String> = Internal.fieldStatics(c);
|
||
|
return x.copy();
|
||
|
} else {
|
||
|
return [];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline function unsafeFastCodeAt(s:String, index:Int) {
|
||
|
return UBuiltins.ord(python.Syntax.arrayAccess(s, index));
|
||
|
}
|
||
|
|
||
|
static inline function handleKeywords(name:String):String {
|
||
|
return if (keywords.has(name)) {
|
||
|
Internal.getPrefixed(name);
|
||
|
} else if (name.length > 2
|
||
|
&& unsafeFastCodeAt(name, 0) == "_".code
|
||
|
&& unsafeFastCodeAt(name, 1) == "_".code
|
||
|
&& unsafeFastCodeAt(name, name.length - 1) != "_".code) {
|
||
|
Internal.getPrefixed(name);
|
||
|
} else
|
||
|
name;
|
||
|
}
|
||
|
|
||
|
static var prefixLength = Internal.prefix().length;
|
||
|
|
||
|
static function unhandleKeywords(name:String):String {
|
||
|
if (name.substr(0, prefixLength) == Internal.prefix()) {
|
||
|
var real = name.substr(prefixLength);
|
||
|
if (keywords.has(real))
|
||
|
return real;
|
||
|
}
|
||
|
return name;
|
||
|
}
|
||
|
|
||
|
static inline function implementsInterface(value:Dynamic, cls:Class<Dynamic>):Bool {
|
||
|
function loop(intf) {
|
||
|
var f:Array<Dynamic> = if (Internal.hasInterfaces(intf)) Internal.fieldInterfaces(intf) else [];
|
||
|
if (f != null) {
|
||
|
for (i in f) {
|
||
|
if (i == cls) {
|
||
|
return true;
|
||
|
} else {
|
||
|
var l = loop(i);
|
||
|
if (l) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
var currentClass = Syntax.field(value, "__class__");
|
||
|
var result = false;
|
||
|
while (currentClass != null) {
|
||
|
if (loop(currentClass)) {
|
||
|
result = true;
|
||
|
break;
|
||
|
}
|
||
|
currentClass = getSuperClass(currentClass);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
}
|