Boot.hx 12 KB

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