Boot.hx 14 KB

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