Boot.hx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /*
  2. * Copyright (C)2005-2019 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package python;
  23. import python.internal.MethodClosure;
  24. import python.internal.ArrayImpl;
  25. import python.internal.Internal;
  26. import python.internal.StringImpl;
  27. import python.internal.EnumImpl;
  28. import python.internal.HxOverrides;
  29. import python.internal.HxException;
  30. import python.internal.AnonObject;
  31. import python.internal.UBuiltins;
  32. import python.lib.Inspect;
  33. import python.Syntax;
  34. @:dox(hide)
  35. class Boot {
  36. static var keywords:Set<String> = new Set([
  37. "and", "del", "from", "not", "with", "as", "elif", "global", "or", "yield", "assert", "else", "if", "pass", "None", "break", "except", "import",
  38. "raise", "True", "class", "exec", "in", "return", "False", "continue", "finally", "is", "try", "def", "for", "lambda", "while",
  39. ]);
  40. inline static function arrayJoin<T>(x:Array<T>, sep:String):String {
  41. return Syntax.field(sep, "join")(Syntax.code("[{0}(x1,'') for x1 in {1}]", python.Boot.toString1, x));
  42. }
  43. inline static function safeJoin(x:Array<String>, sep:String):String {
  44. return Syntax.field(sep, "join")(Syntax.code("[x1 for x1 in {0}]", x));
  45. }
  46. inline static function isPyBool(o:Dynamic):Bool {
  47. return UBuiltins.isinstance(o, UBuiltins.bool);
  48. }
  49. inline static function isPyInt(o:Dynamic):Bool {
  50. // for historic reasons bool extends int
  51. return UBuiltins.isinstance(o, UBuiltins.int) && !isPyBool(o);
  52. }
  53. inline static function isPyFloat(o:Dynamic):Bool {
  54. return UBuiltins.isinstance(o, UBuiltins.float);
  55. }
  56. static inline function isClass(o:Dynamic):Bool {
  57. return o != null && (o == String || Inspect.isclass(o));
  58. }
  59. static inline function isAnonObject(o:Dynamic) {
  60. return UBuiltins.isinstance(o, AnonObject);
  61. }
  62. @:ifFeature("add_dynamic") private static function _add_dynamic(a:Dynamic, b:Dynamic):Dynamic {
  63. if (UBuiltins.isinstance(a, String) && UBuiltins.isinstance(b, String)) {
  64. return Syntax.binop(a, "+", b);
  65. }
  66. if (UBuiltins.isinstance(a, String) || UBuiltins.isinstance(b, String)) {
  67. return Syntax.binop(toString1(a, ""), "+", toString1(b, ""));
  68. }
  69. return Syntax.binop(a, "+", b);
  70. }
  71. static inline function toString(o:Dynamic) {
  72. return toString1(o, "");
  73. }
  74. private static function toString1(o:Dynamic, s:String):String {
  75. if (o == null)
  76. return "null";
  77. if (isString(o))
  78. return o;
  79. if (s == null)
  80. s = "";
  81. if (s.length >= 5)
  82. return "<...>"; // too much deep recursion
  83. if (isPyBool(o)) {
  84. if ((o : Bool))
  85. return "true"
  86. else
  87. return "false";
  88. }
  89. if (isPyInt(o)) {
  90. return UBuiltins.str(o);
  91. }
  92. // 1.0 should be printed as 1
  93. if (isPyFloat(o)) {
  94. try {
  95. if ((o : Float) == UBuiltins.int(o)) {
  96. return UBuiltins.str(Math.round(o));
  97. } else {
  98. return UBuiltins.str(o);
  99. }
  100. } catch (e:Dynamic) {
  101. return UBuiltins.str(o);
  102. }
  103. }
  104. if (isArray(o)) {
  105. var o1:Array<Dynamic> = o;
  106. var l = o1.length;
  107. var st = "[";
  108. s += "\t";
  109. for (i in 0...l) {
  110. var prefix = "";
  111. if (i > 0) {
  112. prefix = ",";
  113. }
  114. st += prefix + toString1(o1[i], s);
  115. }
  116. st += "]";
  117. return st;
  118. }
  119. try {
  120. if (UBuiltins.hasattr(o, "toString"))
  121. return Syntax.callField(o, "toString");
  122. } catch (e:Dynamic) {}
  123. if (UBuiltins.hasattr(o, "__class__")) {
  124. if (isAnonObject(o)) {
  125. var toStr = null;
  126. try {
  127. var fields = fields(o);
  128. var fieldsStr = [for (f in fields) '$f : ${toString1(simpleField(o, f), s + "\t")}'];
  129. toStr = "{ " + safeJoin(fieldsStr, ", ") + " }";
  130. } catch (e:Dynamic) {
  131. return "{ ... }";
  132. }
  133. if (toStr == null) {
  134. return "{ ... }";
  135. } else {
  136. return toStr;
  137. }
  138. }
  139. if (UBuiltins.isinstance(o, Enum)) {
  140. var o:EnumImpl = (o : EnumImpl);
  141. var l = UBuiltins.len(o.params);
  142. var hasParams = l > 0;
  143. if (hasParams) {
  144. var paramsStr = "";
  145. for (i in 0...l) {
  146. var prefix = "";
  147. if (i > 0) {
  148. prefix = ",";
  149. }
  150. paramsStr += prefix + toString1(o.params[i], s);
  151. }
  152. return o.tag + "(" + paramsStr + ")";
  153. } else {
  154. return o.tag;
  155. }
  156. }
  157. if (Internal.hasClassName(o)) {
  158. if (Syntax.field(Syntax.field(o, "__class__"), "__name__") != "type") {
  159. var fields = getInstanceFields(o);
  160. var fieldsStr = [for (f in fields) '$f : ${toString1(simpleField(o, f), s + "\t")}'];
  161. var toStr = (Internal.fieldClassName(o) : String) + "( " + safeJoin(fieldsStr, ", ") + " )";
  162. return toStr;
  163. } else {
  164. var fields = getClassFields(o);
  165. var fieldsStr = [for (f in fields) '$f : ${toString1(simpleField(o, f), s + "\t")}'];
  166. var toStr = "#" + (Internal.fieldClassName(o) : String) + "( " + safeJoin(fieldsStr, ", ") + " )";
  167. return toStr;
  168. }
  169. }
  170. if (isMetaType(o, String)) {
  171. return "#String";
  172. }
  173. if (isMetaType(o, Array)) {
  174. return "#Array";
  175. }
  176. if (UBuiltins.callable(o)) {
  177. return "function";
  178. }
  179. try {
  180. if (UBuiltins.hasattr(o, "__repr__")) {
  181. return Syntax.callField(o, "__repr__");
  182. }
  183. } catch (e:Dynamic) {}
  184. if (UBuiltins.hasattr(o, "__str__")) {
  185. return Syntax.callField(o, "__str__", []);
  186. }
  187. if (UBuiltins.hasattr(o, "__name__")) {
  188. return Syntax.field(o, "__name__");
  189. }
  190. return "???";
  191. } else {
  192. return UBuiltins.str(o);
  193. }
  194. }
  195. static inline function isMetaType(v:Dynamic, t:Dynamic):Bool {
  196. return python.Syntax.binop(v, "==", t);
  197. }
  198. @:analyzer(no_local_dce)
  199. static function fields(o:Dynamic) {
  200. var a = [];
  201. if (o != null) {
  202. if (Internal.hasFields(o)) {
  203. var fields = Internal.fieldFields(o);
  204. if (fields != null) {
  205. return (fields : Array<String>).copy();
  206. }
  207. }
  208. if (isAnonObject(o)) {
  209. var d = Syntax.field(o, "__dict__");
  210. var keys = Syntax.callField(d, "keys");
  211. var handler = unhandleKeywords;
  212. Syntax.code("for k in keys:");
  213. Syntax.code(" if (k != '_hx_disable_getattr'):");
  214. Syntax.code(" a.append(handler(k))");
  215. } else if (UBuiltins.hasattr(o, "__dict__")) {
  216. var a = [];
  217. var d = Syntax.field(o, "__dict__");
  218. var keys1 = Syntax.callField(d, "keys");
  219. Syntax.code("for k in keys1:");
  220. Syntax.code(" a.append(k)");
  221. }
  222. }
  223. return a;
  224. }
  225. static inline function isString(o:Dynamic):Bool {
  226. return UBuiltins.isinstance(o, UBuiltins.str);
  227. }
  228. static inline function isArray(o:Dynamic):Bool {
  229. return UBuiltins.isinstance(o, UBuiltins.list);
  230. }
  231. static function simpleField(o:Dynamic, field:String):Dynamic {
  232. if (field == null)
  233. return null;
  234. var field = handleKeywords(field);
  235. return if (UBuiltins.hasattr(o, field)) UBuiltins.getattr(o, field) else null;
  236. }
  237. @:ifFeature("closure_Array", "closure_String")
  238. static inline function createClosure(obj:Dynamic, func:Dynamic):Dynamic {
  239. return new MethodClosure(obj, func);
  240. }
  241. static function hasField(o:Dynamic, field:String):Bool {
  242. if (isAnonObject(o)) {
  243. return Syntax.code('{0}._hx_hasattr({1})', o, field);
  244. }
  245. return UBuiltins.hasattr(o, handleKeywords(field));
  246. }
  247. static function field(o:Dynamic, field:String):Dynamic {
  248. if (field == null)
  249. return null;
  250. inline function def() {
  251. var field = handleKeywords(field);
  252. return if (UBuiltins.hasattr(o, field)) UBuiltins.getattr(o, field) else null;
  253. }
  254. return if (isString(o)) {
  255. switch (field) {
  256. case "length":
  257. StringImpl.get_length(o);
  258. case "toLowerCase":
  259. createClosure(o, StringImpl.toLowerCase);
  260. case "toUpperCase":
  261. createClosure(o, StringImpl.toUpperCase);
  262. case "charAt":
  263. createClosure(o, StringImpl.charAt);
  264. case "charCodeAt":
  265. createClosure(o, StringImpl.charCodeAt);
  266. case "indexOf":
  267. createClosure(o, StringImpl.indexOf);
  268. case "lastIndexOf":
  269. createClosure(o, StringImpl.lastIndexOf);
  270. case "split":
  271. createClosure(o, StringImpl.split);
  272. case "substr":
  273. createClosure(o, StringImpl.substr);
  274. case "substring":
  275. createClosure(o, StringImpl.substring);
  276. case "toString":
  277. createClosure(o, StringImpl.toString);
  278. default:
  279. def();
  280. }
  281. } else if (isArray(o)) {
  282. switch (field) {
  283. case "length":
  284. ArrayImpl.get_length(o);
  285. case "map":
  286. createClosure(o, ArrayImpl.map);
  287. case "filter":
  288. createClosure(o, ArrayImpl.filter);
  289. case "concat":
  290. createClosure(o, ArrayImpl.concat);
  291. case "copy":
  292. createClosure(o, ArrayImpl.copy);
  293. case "iterator":
  294. createClosure(o, ArrayImpl.iterator);
  295. case "insert":
  296. createClosure(o, ArrayImpl.insert);
  297. case "join":
  298. createClosure(o, ArrayImpl.join);
  299. case "toString":
  300. createClosure(o, ArrayImpl.toString);
  301. case "pop":
  302. createClosure(o, ArrayImpl.pop);
  303. case "push":
  304. createClosure(o, ArrayImpl.push);
  305. case "unshift":
  306. createClosure(o, ArrayImpl.unshift);
  307. case "indexOf":
  308. createClosure(o, ArrayImpl.indexOf);
  309. case "lastIndexOf":
  310. createClosure(o, ArrayImpl.lastIndexOf);
  311. case "remove":
  312. createClosure(o, ArrayImpl.remove);
  313. case "reverse":
  314. createClosure(o, ArrayImpl.reverse);
  315. case "shift":
  316. createClosure(o, ArrayImpl.shift);
  317. case "slice":
  318. createClosure(o, ArrayImpl.slice);
  319. case "sort":
  320. createClosure(o, ArrayImpl.sort);
  321. case "splice":
  322. createClosure(o, ArrayImpl.splice);
  323. default:
  324. def();
  325. }
  326. } else {
  327. def();
  328. }
  329. }
  330. static function getInstanceFields(c:Class<Dynamic>):Array<String> {
  331. var f = if (Internal.hasFields(c)) (Internal.fieldFields(c) : Array<String>).copy() else [];
  332. if (Internal.hasMethods(c))
  333. f = f.concat(Internal.fieldMethods(c));
  334. var sc = getSuperClass(c);
  335. if (sc == null) {
  336. return f;
  337. } else {
  338. var scArr = getInstanceFields(sc);
  339. var scMap = new Set(scArr);
  340. for (f1 in f) {
  341. if (!scMap.has(f1)) {
  342. scArr.push(f1);
  343. }
  344. }
  345. return scArr;
  346. }
  347. }
  348. static function getSuperClass(c:Class<Dynamic>):Class<Dynamic> {
  349. if (c == null)
  350. return null;
  351. try {
  352. if (Internal.hasSuper(c)) {
  353. return Internal.fieldSuper(c);
  354. }
  355. return null;
  356. } catch (e:Dynamic) {}
  357. return null;
  358. }
  359. static function getClassFields(c:Class<Dynamic>):Array<String> {
  360. if (Internal.hasStatics(c)) {
  361. var x:Array<String> = Internal.fieldStatics(c);
  362. return x.copy();
  363. } else {
  364. return [];
  365. }
  366. }
  367. static inline function unsafeFastCodeAt(s:String, index:Int) {
  368. return UBuiltins.ord(python.Syntax.arrayAccess(s, index));
  369. }
  370. static inline function handleKeywords(name:String):String {
  371. return if (keywords.has(name)) {
  372. Internal.getPrefixed(name);
  373. } else if (name.length > 2
  374. && unsafeFastCodeAt(name, 0) == "_".code
  375. && unsafeFastCodeAt(name, 1) == "_".code
  376. && unsafeFastCodeAt(name, name.length - 1) != "_".code) {
  377. Internal.getPrefixed(name);
  378. } else
  379. name;
  380. }
  381. static var prefixLength = Internal.prefix().length;
  382. static function unhandleKeywords(name:String):String {
  383. if (name.substr(0, prefixLength) == Internal.prefix()) {
  384. var real = name.substr(prefixLength);
  385. if (keywords.has(real))
  386. return real;
  387. }
  388. return name;
  389. }
  390. static inline function implementsInterface(value:Dynamic, cls:Class<Dynamic>):Bool {
  391. function loop(intf) {
  392. var f:Array<Dynamic> = if (Internal.hasInterfaces(intf)) Internal.fieldInterfaces(intf) else [];
  393. if (f != null) {
  394. for (i in f) {
  395. if (i == cls) {
  396. return true;
  397. } else {
  398. var l = loop(i);
  399. if (l) {
  400. return true;
  401. }
  402. }
  403. }
  404. return false;
  405. } else {
  406. return false;
  407. }
  408. }
  409. var currentClass = Syntax.field(value, "__class__");
  410. var result = false;
  411. while (currentClass != null) {
  412. if (loop(currentClass)) {
  413. result = true;
  414. break;
  415. }
  416. currentClass = getSuperClass(currentClass);
  417. }
  418. return result;
  419. }
  420. }