2
0

Boot.hx 13 KB

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