Boot.hx 12 KB

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