Boot.hx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. package python;
  2. import python.internal.ArrayImpl;
  3. import python.internal.Internal;
  4. import python.internal.StringImpl;
  5. import python.internal.EnumImpl;
  6. import python.internal.HxOverrides;
  7. import python.internal.HxException;
  8. import python.internal.AnonObject;
  9. import python.lib.Builtin;
  10. import python.lib.Inspect;
  11. import python.lib.Set;
  12. import python.Syntax;
  13. typedef HxClassBase = {
  14. _hx_class:Dynamic,
  15. _hx_class_name:String
  16. }
  17. private typedef HxAbstract = {
  18. >HxClassBase,
  19. }
  20. private typedef HxEnum = {
  21. >HxClassBase,
  22. _hx_constructs:Array<String>
  23. }
  24. private typedef HxClass = {
  25. >HxClassBase,
  26. _hx_fields:Array<String>,
  27. _hx_props:Array<String>,
  28. _hx_methods:Array<String>,
  29. _hx_statics:Array<String>,
  30. _hx_interfaces:Array<HxClassBase>,
  31. _hx_super:HxClass
  32. }
  33. @:keep
  34. @:nativeGen
  35. @:native("_hx_ClassRegistry")
  36. private class ClassRegistry extends python.lib.Dict<String, HxClassBase> {
  37. function _register(cls:HxClassBase, name:String):Void {
  38. cls._hx_class = cls;
  39. cls._hx_class_name = name;
  40. set(name, cls);
  41. }
  42. function registerAbstract(name:String):HxAbstract->HxAbstract {
  43. function wrapper(cls:HxAbstract):HxAbstract {
  44. _register(cls, name);
  45. return cls;
  46. }
  47. return wrapper;
  48. }
  49. function registerEnum(name:String, constructs:Array<String>):HxEnum->HxEnum {
  50. function wrapper(cls:HxEnum):HxEnum {
  51. _register(cls, name);
  52. cls._hx_constructs = constructs;
  53. return cls;
  54. }
  55. return wrapper;
  56. }
  57. function registerClass(name:String, ?fields:Array<String>, ?props:Array<String>, ?methods:Array<String>, ?statics:Array<String>, ?interfaces:Array<HxClassBase>, ?superClass:HxClass):HxClass->HxClass {
  58. if (fields == null) fields = [];
  59. if (props == null) props = [];
  60. if (methods == null) methods = [];
  61. if (statics == null) statics = [];
  62. if (interfaces == null) interfaces = [];
  63. function wrapper(cls:HxClass):HxClass {
  64. _register(cls, name);
  65. cls._hx_fields = fields;
  66. cls._hx_props = props;
  67. cls._hx_methods = methods;
  68. cls._hx_statics = statics;
  69. cls._hx_interfaces = interfaces;
  70. if (superClass != null)
  71. cls._hx_super = superClass;
  72. return cls;
  73. }
  74. return wrapper;
  75. }
  76. }
  77. @:preCode("_hx_classes = _hx_ClassRegistry()")
  78. @:keep class Boot {
  79. static var keywords:Set<String> = new Set(
  80. [
  81. "and", "del", "from", "not", "while",
  82. "as", "elif", "global", "or", "with",
  83. "assert", "else", "if", "pass", "yield",
  84. "break", "except", "import", "print", "float",
  85. "class", "exec", "in", "raise",
  86. "continue", "finally", "is", "return",
  87. "def", "for", "lambda", "try",
  88. "None", "list", "True", "False"
  89. ]);
  90. inline static function arrayJoin <T>(x:Array<T>, sep:String):String {
  91. return Syntax.field(sep, "join")(Syntax.pythonCode("[{0}(x1,'') for x1 in {1}]", python.Boot.toString1, x));
  92. }
  93. inline static function isPyBool(o:Dynamic):Bool {
  94. return Builtin.isinstance(o, Builtin.bool);
  95. }
  96. inline static function isPyInt(o:Dynamic):Bool {
  97. return Builtin.isinstance(o, Builtin.int);
  98. }
  99. inline static function isPyFloat(o:Dynamic):Bool {
  100. return Builtin.isinstance(o, Builtin.float);
  101. }
  102. static inline function isClass(o:Dynamic) : Bool {
  103. return o != null && (o == String || Inspect.isclass(o));
  104. }
  105. static inline function isAnonObject(o:Dynamic) {
  106. return Builtin.isinstance(o, AnonObject);
  107. }
  108. private static function _add_dynamic(a:Dynamic,b:Dynamic):Dynamic {
  109. if (Builtin.isinstance(a, String) || Builtin.isinstance(b, String)) {
  110. return Syntax.binop(toString1(a,""), "+", toString1(b,""));
  111. }
  112. return Syntax.binop(a, "+", b);
  113. }
  114. static inline function toString (o:Dynamic) {
  115. return toString1(o, "");
  116. }
  117. private static function toString1(o:Dynamic,s:String):String {
  118. if( o == null ) return "null";
  119. if (isString(o)) return o;
  120. if (s == null) s = "";
  121. if( s.length >= 5 ) return "<...>"; // too much deep recursion
  122. if (isPyBool(o)) {
  123. if ((o:Bool)) return "true" else return "false";
  124. }
  125. if (isPyInt(o)) {
  126. return Builtin.str(o);
  127. }
  128. // 1.0 should be printed as 1
  129. if (isPyFloat(o)) {
  130. try {
  131. if ( (o:Float) == Builtin.int(o)) {
  132. return Builtin.str(Math.round(o));
  133. } else {
  134. return Builtin.str(o);
  135. }
  136. } catch (e:Dynamic) {
  137. return Builtin.str(o);
  138. }
  139. }
  140. if (isArray(o))
  141. {
  142. var o1:Array<Dynamic> = o;
  143. var l = o1.length;
  144. var st = "[";
  145. s += "\t";
  146. for( i in 0...l ) {
  147. var prefix = "";
  148. if (i > 0) {
  149. prefix = ",";
  150. }
  151. st += prefix + toString1(o1[i],s);
  152. }
  153. st += "]";
  154. return st;
  155. }
  156. try {
  157. if (Builtin.hasattr(o, "toString"))
  158. return Syntax.callField(o, "toString");
  159. } catch (e:Dynamic) {
  160. }
  161. if (Inspect.isfunction(o) || Inspect.ismethod(o)) return "<function>";
  162. if (Builtin.hasattr(o, "__class__"))
  163. {
  164. if (isAnonObject(o))
  165. {
  166. var toStr = null;
  167. try
  168. {
  169. var fields = fields(o);
  170. var fieldsStr = [for (f in fields) '$f : ${toString1(field(o,f), s+"\t")}'];
  171. toStr = "{ " + arrayJoin(fieldsStr, ", ") + " }";
  172. }
  173. catch (e:Dynamic) {
  174. return "{ ... }";
  175. }
  176. if (toStr == null)
  177. {
  178. return "{ ... }";
  179. }
  180. else
  181. {
  182. return toStr;
  183. }
  184. }
  185. if (Builtin.isinstance(o, Enum)) {
  186. var o:EnumImpl = o;
  187. var l = Builtin.len(o.params);
  188. var hasParams = l > 0;
  189. if (hasParams) {
  190. var paramsStr = "";
  191. for (i in 0...l) {
  192. var prefix = "";
  193. if (i > 0) {
  194. prefix = ",";
  195. }
  196. paramsStr += prefix + toString1(o.params[i],s);
  197. }
  198. return o.tag + "(" + paramsStr + ")";
  199. } else {
  200. return o.tag;
  201. }
  202. }
  203. if (Internal.hasClassName(o)) {
  204. if (Syntax.field(Syntax.field(o, "__class__"), "__name__") != "type") {
  205. var fields = getInstanceFields(o);
  206. var fieldsStr = [for (f in fields) '$f : ${toString1(field(o,f), s+"\t")}'];
  207. var toStr = Internal.fieldClassName(o) + "( " + arrayJoin(fieldsStr, ", ") + " )";
  208. return toStr;
  209. } else {
  210. var fields = getClassFields(o);
  211. var fieldsStr = [for (f in fields) '$f : ${toString1(field(o,f), s+"\t")}'];
  212. var toStr = "#" + Internal.fieldClassName(o) + "( " + arrayJoin(fieldsStr, ", ") + " )";
  213. return toStr;
  214. }
  215. }
  216. if (isMetaType(o,String)) {
  217. return "#String";
  218. }
  219. if (isMetaType(o,Array)) {
  220. return "#Array";
  221. }
  222. if (Builtin.callable(o)) {
  223. return "function";
  224. }
  225. try {
  226. if (Builtin.hasattr(o, "__repr__")) {
  227. return Syntax.callField(o, "__repr__");
  228. }
  229. } catch (e:Dynamic) {}
  230. if (Builtin.hasattr(o, "__str__")) {
  231. return Syntax.callField(o, "__str__", []);
  232. }
  233. if (Builtin.hasattr(o, "__name__")) {
  234. return Syntax.field(o, "__name__");
  235. }
  236. return "???";
  237. } else {
  238. return Builtin.str(o);
  239. }
  240. }
  241. static inline function isMetaType(v:Dynamic, t:Dynamic):Bool {
  242. return python.Syntax.binop(v, "==", t);
  243. }
  244. @:analyzer(no_local_dce)
  245. static function fields (o:Dynamic) {
  246. var a = [];
  247. if (o != null) {
  248. if (Internal.hasFields(o)) {
  249. var fields:Array<String> = Internal.fieldFields(o);
  250. return fields.copy();
  251. }
  252. if (isAnonObject(o)) {
  253. var d = Syntax.field(o, "__dict__");
  254. var keys = Syntax.callField(d, "keys");
  255. var handler = unhandleKeywords;
  256. Syntax.pythonCode("for k in keys:");
  257. Syntax.pythonCode(" a.append(handler(k))");
  258. }
  259. else if (Builtin.hasattr(o, "__dict__")) {
  260. var a = [];
  261. var d = Syntax.field(o, "__dict__");
  262. var keys1 = Syntax.callField(d, "keys");
  263. Syntax.pythonCode("for k in keys1:");
  264. Syntax.pythonCode(" a.append(k)");
  265. }
  266. }
  267. return a;
  268. }
  269. static inline function isString (o:Dynamic):Bool {
  270. return Builtin.isinstance(o, Builtin.str);
  271. }
  272. static inline function isArray (o:Dynamic):Bool {
  273. return Builtin.isinstance(o, Builtin.list);
  274. }
  275. static function field( o : Dynamic, field : String ) : Dynamic {
  276. if (field == null) return null;
  277. switch (field) {
  278. case "length" if (isString(o)): return StringImpl.get_length(o);
  279. case "toLowerCase" if (isString(o)): return StringImpl.toLowerCase.bind(o);
  280. case "toUpperCase" if (isString(o)): return StringImpl.toUpperCase.bind(o);
  281. case "charAt" if (isString(o)): return StringImpl.charAt.bind(o);
  282. case "charCodeAt" if (isString(o)): return StringImpl.charCodeAt.bind(o);
  283. case "indexOf" if (isString(o)): return StringImpl.indexOf.bind(o);
  284. case "lastIndexOf" if (isString(o)): return StringImpl.lastIndexOf.bind(o);
  285. case "split" if (isString(o)): return StringImpl.split.bind(o);
  286. case "substr" if (isString(o)): return StringImpl.substr.bind(o);
  287. case "substring" if (isString(o)): return StringImpl.substring.bind(o);
  288. case "toString" if (isString(o)): return StringImpl.toString.bind(o);
  289. case "length" if (isArray(o)): return ArrayImpl.get_length(o);
  290. case "map" if (isArray(o)): return ArrayImpl.map.bind(o);
  291. case "filter" if (isArray(o)): return ArrayImpl.filter.bind(o);
  292. case "concat" if (isArray(o)): return ArrayImpl.concat.bind(o);
  293. case "copy" if (isArray(o)): return function () return ArrayImpl.copy(o);
  294. case "iterator" if (isArray(o)): return ArrayImpl.iterator.bind(o);
  295. case "insert" if (isArray(o)): return ArrayImpl.insert.bind(o);
  296. case "join" if (isArray(o)): return function (sep) return ArrayImpl.join(o, sep);
  297. case "toString" if (isArray(o)): return ArrayImpl.toString.bind(o);
  298. case "pop" if (isArray(o)): return ArrayImpl.pop.bind(o);
  299. case "push" if (isArray(o)): return ArrayImpl.push.bind(o);
  300. case "unshift" if (isArray(o)): return ArrayImpl.unshift.bind(o);
  301. case "indexOf" if (isArray(o)): return ArrayImpl.indexOf.bind(o);
  302. case "lastIndexOf" if (isArray(o)): return ArrayImpl.lastIndexOf.bind(o);
  303. case "remove" if (isArray(o)): return ArrayImpl.remove.bind(o);
  304. case "reverse" if (isArray(o)): return ArrayImpl.reverse.bind(o);
  305. case "shift" if (isArray(o)): return ArrayImpl.shift.bind(o);
  306. case "slice" if (isArray(o)): return ArrayImpl.slice.bind(o);
  307. case "sort" if (isArray(o)): return ArrayImpl.sort.bind(o);
  308. case "splice" if (isArray(o)): return ArrayImpl.splice.bind(o);
  309. }
  310. var field = handleKeywords(field);
  311. return if (Builtin.hasattr(o, field)) Builtin.getattr(o, field) else null;
  312. }
  313. static function getInstanceFields( c : Class<Dynamic> ) : Array<String> {
  314. var f = if (Internal.hasFields(c)) {
  315. var x:Array<String> = Internal.fieldFields(c);
  316. var x2:Array<String> = Internal.fieldMethods(c);
  317. x.concat(x2);
  318. } else {
  319. [];
  320. }
  321. var sc = getSuperClass(c);
  322. if (sc == null) {
  323. return f;
  324. } else {
  325. var scArr = getInstanceFields(sc);
  326. var scMap = [for (f in scArr) f => f];
  327. var res = [];
  328. for (f1 in f) {
  329. if (!scMap.exists(f1)) {
  330. scArr.push(f1);
  331. }
  332. }
  333. return scArr;
  334. }
  335. }
  336. static function getSuperClass( c : Class<Dynamic> ) : Class<Dynamic> {
  337. if( c == null )
  338. return null;
  339. try {
  340. if (Internal.hasSuper(c)) {
  341. return Internal.fieldSuper(c);
  342. }
  343. return null;
  344. } catch (e:Dynamic) {
  345. }
  346. return null;
  347. }
  348. static function getClassFields( c : Class<Dynamic> ) : Array<String> {
  349. if (Internal.hasStatics(c)) {
  350. var x:Array<String> = Internal.fieldStatics(c);
  351. return x.copy();
  352. } else {
  353. return [];
  354. }
  355. }
  356. static inline function unsafeFastCodeAt (s, index) {
  357. return Builtin.ord(python.Syntax.arrayAccess(s, index));
  358. }
  359. static inline function handleKeywords(name:String):String {
  360. return if (keywords.has(name)) {
  361. Internal.getPrefixed(name);
  362. } else if (name.length > 2 && unsafeFastCodeAt(name,0) == "_".code && unsafeFastCodeAt(name,1) == "_".code && unsafeFastCodeAt(name, name.length-1) != "_".code) {
  363. Internal.getPrefixed(name);
  364. }
  365. else name;
  366. }
  367. static var prefixLength = Internal.prefix().length;
  368. static function unhandleKeywords(name:String):String {
  369. if (name.substr(0,prefixLength) == Internal.prefix()) {
  370. var real = name.substr(prefixLength);
  371. if (keywords.has(real)) return real;
  372. }
  373. return name;
  374. }
  375. }