Boot.hx 12 KB

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