Boot.hx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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.ArrayImpl;
  24. import python.internal.Internal;
  25. import python.internal.StringImpl;
  26. import python.internal.EnumImpl;
  27. import python.internal.HxOverrides;
  28. import python.internal.HxException;
  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. [
  37. "and", "del", "from", "not", "with",
  38. "as", "elif", "global", "or", "yield",
  39. "assert", "else", "if", "pass", "None",
  40. "break", "except", "import", "raise", "True",
  41. "class", "exec", "in", "return", "False",
  42. "continue", "finally", "is", "try",
  43. "def", "for", "lambda", "while",
  44. ]);
  45. inline static function arrayJoin <T>(x:Array<T>, sep:String):String {
  46. return Syntax.field(sep, "join")(Syntax.pythonCode("[{0}(x1,'') for x1 in {1}]", python.Boot.toString1, x));
  47. }
  48. inline static function safeJoin (x:Array<String>, sep:String):String {
  49. return Syntax.field(sep, "join")(Syntax.pythonCode("[x1 for x1 in {0}]", x));
  50. }
  51. inline static function isPyBool(o:Dynamic):Bool {
  52. return UBuiltins.isinstance(o, UBuiltins.bool);
  53. }
  54. inline static function isPyInt(o:Dynamic):Bool {
  55. return UBuiltins.isinstance(o, UBuiltins.int);
  56. }
  57. inline static function isPyFloat(o:Dynamic):Bool {
  58. return UBuiltins.isinstance(o, UBuiltins.float);
  59. }
  60. static inline function isClass(o:Dynamic) : Bool {
  61. return o != null && (o == String || Inspect.isclass(o));
  62. }
  63. static inline function isAnonObject(o:Dynamic) {
  64. return UBuiltins.isinstance(o, AnonObject);
  65. }
  66. @:ifFeature("add_dynamic") private static function _add_dynamic(a:Dynamic,b:Dynamic):Dynamic {
  67. if (UBuiltins.isinstance(a, String) && UBuiltins.isinstance(b, String)) {
  68. return Syntax.binop(a, "+", b);
  69. }
  70. if (UBuiltins.isinstance(a, String) || UBuiltins.isinstance(b, String)) {
  71. return Syntax.binop(toString1(a,""), "+", toString1(b,""));
  72. }
  73. return Syntax.binop(a, "+", b);
  74. }
  75. static inline function toString (o:Dynamic) {
  76. return toString1(o, "");
  77. }
  78. private static function toString1(o:Dynamic,s:String):String {
  79. if( o == null ) return "null";
  80. if (isString(o)) return o;
  81. if (s == null) s = "";
  82. if( s.length >= 5 ) return "<...>"; // too much deep recursion
  83. if (isPyBool(o)) {
  84. if ((o:Bool)) return "true" else return "false";
  85. }
  86. if (isPyInt(o)) {
  87. return UBuiltins.str(o);
  88. }
  89. // 1.0 should be printed as 1
  90. if (isPyFloat(o)) {
  91. try {
  92. if ( (o:Float) == UBuiltins.int(o)) {
  93. return UBuiltins.str(Math.round(o));
  94. } else {
  95. return UBuiltins.str(o);
  96. }
  97. } catch (e:Dynamic) {
  98. return UBuiltins.str(o);
  99. }
  100. }
  101. if (isArray(o))
  102. {
  103. var o1:Array<Dynamic> = o;
  104. var l = o1.length;
  105. var st = "[";
  106. s += "\t";
  107. for( i in 0...l ) {
  108. var prefix = "";
  109. if (i > 0) {
  110. prefix = ",";
  111. }
  112. st += prefix + toString1(o1[i],s);
  113. }
  114. st += "]";
  115. return st;
  116. }
  117. try {
  118. if (UBuiltins.hasattr(o, "toString"))
  119. return Syntax.callField(o, "toString");
  120. } catch (e:Dynamic) {
  121. }
  122. if (Inspect.isfunction(o) || Inspect.ismethod(o)) return "<function>";
  123. if (UBuiltins.hasattr(o, "__class__"))
  124. {
  125. if (isAnonObject(o))
  126. {
  127. var toStr = null;
  128. try
  129. {
  130. var fields = fields(o);
  131. var fieldsStr = [for (f in fields) '$f : ${toString1(simpleField(o,f), s+"\t")}'];
  132. toStr = "{ " + safeJoin(fieldsStr, ", ") + " }";
  133. }
  134. catch (e:Dynamic) {
  135. return "{ ... }";
  136. }
  137. if (toStr == null)
  138. {
  139. return "{ ... }";
  140. }
  141. else
  142. {
  143. return toStr;
  144. }
  145. }
  146. if (UBuiltins.isinstance(o, Enum)) {
  147. var o:EnumImpl = (o:EnumImpl);
  148. var l = UBuiltins.len(o.params);
  149. var hasParams = l > 0;
  150. if (hasParams) {
  151. var paramsStr = "";
  152. for (i in 0...l) {
  153. var prefix = "";
  154. if (i > 0) {
  155. prefix = ",";
  156. }
  157. paramsStr += prefix + toString1(o.params[i],s);
  158. }
  159. return o.tag + "(" + paramsStr + ")";
  160. } else {
  161. return o.tag;
  162. }
  163. }
  164. if (Internal.hasClassName(o)) {
  165. if (Syntax.field(Syntax.field(o, "__class__"), "__name__") != "type") {
  166. var fields = getInstanceFields(o);
  167. var fieldsStr = [for (f in fields) '$f : ${toString1(simpleField(o,f), s+"\t")}'];
  168. var toStr = (Internal.fieldClassName(o):String) + "( " + safeJoin(fieldsStr, ", ") + " )";
  169. return toStr;
  170. } else {
  171. var fields = getClassFields(o);
  172. var fieldsStr = [for (f in fields) '$f : ${toString1(simpleField(o,f), s+"\t")}'];
  173. var toStr = "#" + (Internal.fieldClassName(o):String) + "( " + safeJoin(fieldsStr, ", ") + " )";
  174. return toStr;
  175. }
  176. }
  177. if (isMetaType(o,String)) {
  178. return "#String";
  179. }
  180. if (isMetaType(o,Array)) {
  181. return "#Array";
  182. }
  183. if (UBuiltins.callable(o)) {
  184. return "function";
  185. }
  186. try {
  187. if (UBuiltins.hasattr(o, "__repr__")) {
  188. return Syntax.callField(o, "__repr__");
  189. }
  190. } catch (e:Dynamic) {}
  191. if (UBuiltins.hasattr(o, "__str__")) {
  192. return Syntax.callField(o, "__str__", []);
  193. }
  194. if (UBuiltins.hasattr(o, "__name__")) {
  195. return Syntax.field(o, "__name__");
  196. }
  197. return "???";
  198. } else {
  199. return UBuiltins.str(o);
  200. }
  201. }
  202. static inline function isMetaType(v:Dynamic, t:Dynamic):Bool {
  203. return python.Syntax.binop(v, "==", t);
  204. }
  205. @:analyzer(no_local_dce)
  206. static function fields (o:Dynamic) {
  207. var a = [];
  208. if (o != null) {
  209. if (Internal.hasFields(o)) {
  210. var fields:Array<String> = Internal.fieldFields(o);
  211. return fields.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. static function field( o : Dynamic, field : String ) : Dynamic {
  242. if (field == null) return null;
  243. switch (field) {
  244. case "length" if (isString(o)): return StringImpl.get_length(o);
  245. case "toLowerCase" if (isString(o)): return StringImpl.toLowerCase.bind(o);
  246. case "toUpperCase" if (isString(o)): return StringImpl.toUpperCase.bind(o);
  247. case "charAt" if (isString(o)): return StringImpl.charAt.bind(o);
  248. case "charCodeAt" if (isString(o)): return StringImpl.charCodeAt.bind(o);
  249. case "indexOf" if (isString(o)): return StringImpl.indexOf.bind(o);
  250. case "lastIndexOf" if (isString(o)): return StringImpl.lastIndexOf.bind(o);
  251. case "split" if (isString(o)): return StringImpl.split.bind(o);
  252. case "substr" if (isString(o)): return StringImpl.substr.bind(o);
  253. case "substring" if (isString(o)): return StringImpl.substring.bind(o);
  254. case "toString" if (isString(o)): return StringImpl.toString.bind(o);
  255. case "length" if (isArray(o)): return ArrayImpl.get_length(o);
  256. case "map" if (isArray(o)): return ArrayImpl.map.bind(o);
  257. case "filter" if (isArray(o)): return ArrayImpl.filter.bind(o);
  258. case "concat" if (isArray(o)): return ArrayImpl.concat.bind(o);
  259. case "copy" if (isArray(o)): return function () return ArrayImpl.copy(o);
  260. case "iterator" if (isArray(o)): return ArrayImpl.iterator.bind(o);
  261. case "insert" if (isArray(o)): return ArrayImpl.insert.bind(o);
  262. case "join" if (isArray(o)): return function (sep) return ArrayImpl.join(o, sep);
  263. case "toString" if (isArray(o)): return ArrayImpl.toString.bind(o);
  264. case "pop" if (isArray(o)): return ArrayImpl.pop.bind(o);
  265. case "push" if (isArray(o)): return ArrayImpl.push.bind(o);
  266. case "unshift" if (isArray(o)): return ArrayImpl.unshift.bind(o);
  267. case "indexOf" if (isArray(o)): return ArrayImpl.indexOf.bind(o);
  268. case "lastIndexOf" if (isArray(o)): return ArrayImpl.lastIndexOf.bind(o);
  269. case "remove" if (isArray(o)): return ArrayImpl.remove.bind(o);
  270. case "reverse" if (isArray(o)): return ArrayImpl.reverse.bind(o);
  271. case "shift" if (isArray(o)): return ArrayImpl.shift.bind(o);
  272. case "slice" if (isArray(o)): return ArrayImpl.slice.bind(o);
  273. case "sort" if (isArray(o)): return ArrayImpl.sort.bind(o);
  274. case "splice" if (isArray(o)): return ArrayImpl.splice.bind(o);
  275. }
  276. var field = handleKeywords(field);
  277. return if (UBuiltins.hasattr(o, field)) UBuiltins.getattr(o, field) else null;
  278. }
  279. static function getInstanceFields( c : Class<Dynamic> ) : Array<String> {
  280. var f = if (Internal.hasFields(c)) Internal.fieldFields(c) else [];
  281. if (Internal.hasMethods(c))
  282. f = f.concat(Internal.fieldMethods(c));
  283. var sc = getSuperClass(c);
  284. if (sc == null) {
  285. return f;
  286. } else {
  287. var scArr = getInstanceFields(sc);
  288. var scMap = new Set(scArr);
  289. //var scMap = [for (f in scArr) f => f];
  290. var res = [];
  291. for (f1 in f) {
  292. if (!scMap.has(f1)) {
  293. scArr.push(f1);
  294. }
  295. }
  296. return scArr;
  297. }
  298. }
  299. static function getSuperClass( c : Class<Dynamic> ) : Class<Dynamic> {
  300. if( c == null )
  301. return null;
  302. try {
  303. if (Internal.hasSuper(c)) {
  304. return Internal.fieldSuper(c);
  305. }
  306. return null;
  307. } catch (e:Dynamic) {
  308. }
  309. return null;
  310. }
  311. static function getClassFields( c : Class<Dynamic> ) : Array<String> {
  312. if (Internal.hasStatics(c)) {
  313. var x:Array<String> = Internal.fieldStatics(c);
  314. return x.copy();
  315. } else {
  316. return [];
  317. }
  318. }
  319. static inline function unsafeFastCodeAt (s, index) {
  320. return UBuiltins.ord(python.Syntax.arrayAccess(s, index));
  321. }
  322. static inline function handleKeywords(name:String):String {
  323. return if (keywords.has(name)) {
  324. Internal.getPrefixed(name);
  325. } else if (name.length > 2 && unsafeFastCodeAt(name,0) == "_".code && unsafeFastCodeAt(name,1) == "_".code && unsafeFastCodeAt(name, name.length-1) != "_".code) {
  326. Internal.getPrefixed(name);
  327. }
  328. else name;
  329. }
  330. static var prefixLength = Internal.prefix().length;
  331. static function unhandleKeywords(name:String):String {
  332. if (name.substr(0,prefixLength) == Internal.prefix()) {
  333. var real = name.substr(prefixLength);
  334. if (keywords.has(real)) return real;
  335. }
  336. return name;
  337. }
  338. }