misceval.js.html 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: misceval.js</title>
  6. <script src="scripts/prettify/prettify.js"> </script>
  7. <script src="scripts/prettify/lang-css.js"> </script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
  13. </head>
  14. <body>
  15. <div id="main">
  16. <h1 class="page-title">Source: misceval.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>/**
  20. * @namespace Sk.misceval
  21. *
  22. */
  23. Sk.misceval = {};
  24. /*
  25. Suspension object format:
  26. {resume: function() {...}, // the continuation - returns either another suspension or the return value
  27. data: &lt;copied down from innermost level>,
  28. optional: &lt;if true, can be resumed immediately (eg debug stops)>,
  29. child: &lt;Suspension, or null if we are the innermost level>,
  30. $blk: &lt;>, $loc: &lt;>, $gbl: &lt;>, $exc: &lt;>, $err: &lt;>, [$cell: &lt;>],
  31. }
  32. */
  33. /**
  34. *
  35. * Hi kids lets make a suspension...
  36. * @constructor
  37. * @param{function(?)=} resume A function to be called on resume. child is resumed first and its return value is passed to this function.
  38. * @param{Object=} child A child suspension. 'optional' will be copied from here if supplied.
  39. * @param{Object=} data Data attached to this suspension. Will be copied from child if not supplied.
  40. */
  41. Sk.misceval.Suspension = function Suspension(resume, child, data) {
  42. this.isSuspension = true;
  43. if (resume !== undefined &amp;&amp; child !== undefined) {
  44. this.resume = function() { return resume(child.resume()); };
  45. }
  46. this.child = child;
  47. this.optional = child !== undefined &amp;&amp; child.optional;
  48. if (data === undefined &amp;&amp; child !== undefined) {
  49. this.data = child.data;
  50. } else {
  51. this.data = data;
  52. }
  53. };
  54. goog.exportSymbol("Sk.misceval.Suspension", Sk.misceval.Suspension);
  55. /**
  56. *
  57. * Well this seems pretty obvious by the name what it should do..
  58. *
  59. * @param{Sk.misceval.Suspension} susp
  60. * @param{string=} message
  61. */
  62. Sk.misceval.retryOptionalSuspensionOrThrow = function (susp, message) {
  63. while (susp instanceof Sk.misceval.Suspension) {
  64. if (!susp.optional) {
  65. throw new Sk.builtin.SuspensionError(message || "Cannot call a function that blocks or suspends here");
  66. }
  67. susp = susp.resume();
  68. }
  69. return susp;
  70. };
  71. goog.exportSymbol("Sk.misceval.retryOptionalSuspensionOrThrow", Sk.misceval.retryOptionalSuspensionOrThrow);
  72. /**
  73. * Check if the given object is valid to use as an index. Only ints, or if the object has an `__index__` method.
  74. * @param o
  75. * @returns {boolean}
  76. */
  77. Sk.misceval.isIndex = function (o) {
  78. if (Sk.builtin.checkInt(o)) {
  79. return true;
  80. }
  81. if (Sk.abstr.lookupSpecial(o, "__index__")) {
  82. return true;
  83. }
  84. return false;
  85. };
  86. goog.exportSymbol("Sk.misceval.isIndex", Sk.misceval.isIndex);
  87. Sk.misceval.asIndex = function (o) {
  88. var idxfn, ret;
  89. if (!Sk.misceval.isIndex(o)) {
  90. return undefined;
  91. }
  92. if (o === null) {
  93. return undefined;
  94. }
  95. if (o === true) {
  96. return 1;
  97. }
  98. if (o === false) {
  99. return 0;
  100. }
  101. if (typeof o === "number") {
  102. return o;
  103. }
  104. if (o.constructor === Sk.builtin.int_) {
  105. return o.v;
  106. }
  107. if (o.constructor === Sk.builtin.lng) {
  108. return o.tp$index();
  109. }
  110. if (o.constructor === Sk.builtin.bool) {
  111. return Sk.builtin.asnum$(o);
  112. }
  113. idxfn = Sk.abstr.lookupSpecial(o, "__index__");
  114. if (idxfn) {
  115. ret = Sk.misceval.callsim(idxfn, o);
  116. if (!Sk.builtin.checkInt(ret)) {
  117. throw new Sk.builtin.TypeError("__index__ returned non-(int,long) (type " +
  118. Sk.abstr.typeName(ret) + ")");
  119. }
  120. return Sk.builtin.asnum$(ret);
  121. }
  122. goog.asserts.fail("todo asIndex;");
  123. };
  124. /**
  125. * return u[v:w]
  126. */
  127. Sk.misceval.applySlice = function (u, v, w, canSuspend) {
  128. var ihigh;
  129. var ilow;
  130. if (u.sq$slice &amp;&amp; Sk.misceval.isIndex(v) &amp;&amp; Sk.misceval.isIndex(w)) {
  131. ilow = Sk.misceval.asIndex(v);
  132. if (ilow === undefined) {
  133. ilow = 0;
  134. }
  135. ihigh = Sk.misceval.asIndex(w);
  136. if (ihigh === undefined) {
  137. ihigh = 1e100;
  138. }
  139. return Sk.abstr.sequenceGetSlice(u, ilow, ihigh);
  140. }
  141. return Sk.abstr.objectGetItem(u, new Sk.builtin.slice(v, w, null), canSuspend);
  142. };
  143. goog.exportSymbol("Sk.misceval.applySlice", Sk.misceval.applySlice);
  144. /**
  145. * u[v:w] = x
  146. */
  147. Sk.misceval.assignSlice = function (u, v, w, x, canSuspend) {
  148. var slice;
  149. var ihigh;
  150. var ilow;
  151. if (u.sq$ass_slice &amp;&amp; Sk.misceval.isIndex(v) &amp;&amp; Sk.misceval.isIndex(w)) {
  152. ilow = Sk.misceval.asIndex(v) || 0;
  153. ihigh = Sk.misceval.asIndex(w) || 1e100;
  154. if (x === null) {
  155. Sk.abstr.sequenceDelSlice(u, ilow, ihigh);
  156. } else {
  157. Sk.abstr.sequenceSetSlice(u, ilow, ihigh, x);
  158. }
  159. } else {
  160. slice = new Sk.builtin.slice(v, w);
  161. if (x === null) {
  162. return Sk.abstr.objectDelItem(u, slice);
  163. } else {
  164. return Sk.abstr.objectSetItem(u, slice, x, canSuspend);
  165. }
  166. }
  167. };
  168. goog.exportSymbol("Sk.misceval.assignSlice", Sk.misceval.assignSlice);
  169. /**
  170. * Used by min() and max() to get an array from arbitrary input.
  171. * Note that this does no validation, just coercion.
  172. */
  173. Sk.misceval.arrayFromArguments = function (args) {
  174. // If args is not a single thing return as is
  175. var it, i;
  176. var res;
  177. var arg;
  178. if (args.length != 1) {
  179. return args;
  180. }
  181. arg = args[0];
  182. if (arg instanceof Sk.builtin.set) {
  183. // this is a Sk.builtin.set
  184. arg = arg.tp$iter().$obj;
  185. } else if (arg instanceof Sk.builtin.dict) {
  186. // this is a Sk.builtin.list
  187. arg = Sk.builtin.dict.prototype["keys"].func_code(arg);
  188. }
  189. // shouldn't else if here as the above may output lists to arg.
  190. if (arg instanceof Sk.builtin.list || arg instanceof Sk.builtin.tuple) {
  191. return arg.v;
  192. } else if (Sk.builtin.checkIterable(arg)) {
  193. // handle arbitrary iterable (strings, generators, etc.)
  194. res = [];
  195. for (it = Sk.abstr.iter(arg), i = it.tp$iternext();
  196. i !== undefined; i = it.tp$iternext()) {
  197. res.push(i);
  198. }
  199. return res;
  200. }
  201. throw new Sk.builtin.TypeError("'" + Sk.abstr.typeName(arg) + "' object is not iterable");
  202. };
  203. goog.exportSymbol("Sk.misceval.arrayFromArguments", Sk.misceval.arrayFromArguments);
  204. /**
  205. * for reversed comparison: Gt -> Lt, etc.
  206. */
  207. Sk.misceval.swappedOp_ = {
  208. "Eq" : "Eq",
  209. "NotEq": "NotEq",
  210. "Lt" : "GtE",
  211. "LtE" : "Gt",
  212. "Gt" : "LtE",
  213. "GtE" : "Lt",
  214. "Is" : "IsNot",
  215. "IsNot": "Is",
  216. "In_" : "NotIn",
  217. "NotIn": "In_"
  218. };
  219. Sk.misceval.richCompareBool = function (v, w, op) {
  220. // v and w must be Python objects. will return Javascript true or false for internal use only
  221. // if you want to return a value from richCompareBool to Python you must wrap as Sk.builtin.bool first
  222. var wname,
  223. vname,
  224. ret,
  225. swapped_method,
  226. method,
  227. swapped_shortcut,
  228. shortcut,
  229. v_has_shortcut,
  230. w_has_shortcut,
  231. op2method,
  232. op2shortcut,
  233. vcmp,
  234. wcmp,
  235. w_seq_type,
  236. w_num_type,
  237. v_seq_type,
  238. v_num_type,
  239. sequence_types,
  240. numeric_types,
  241. w_type,
  242. v_type;
  243. goog.asserts.assert((v !== null) &amp;&amp; (v !== undefined), "passed null or undefined parameter to Sk.misceval.richCompareBool");
  244. goog.asserts.assert((w !== null) &amp;&amp; (w !== undefined), "passed null or undefined parameter to Sk.misceval.richCompareBool");
  245. v_type = new Sk.builtin.type(v);
  246. w_type = new Sk.builtin.type(w);
  247. // Python has specific rules when comparing two different builtin types
  248. // currently, this code will execute even if the objects are not builtin types
  249. // but will fall through and not return anything in this section
  250. if ((v_type !== w_type) &amp;&amp;
  251. (op === "GtE" || op === "Gt" || op === "LtE" || op === "Lt")) {
  252. // note: sets are omitted here because they can only be compared to other sets
  253. numeric_types = [Sk.builtin.float_.prototype.ob$type,
  254. Sk.builtin.int_.prototype.ob$type,
  255. Sk.builtin.lng.prototype.ob$type,
  256. Sk.builtin.bool.prototype.ob$type];
  257. sequence_types = [Sk.builtin.dict.prototype.ob$type,
  258. Sk.builtin.enumerate.prototype.ob$type,
  259. Sk.builtin.list.prototype.ob$type,
  260. Sk.builtin.str.prototype.ob$type,
  261. Sk.builtin.tuple.prototype.ob$type];
  262. v_num_type = numeric_types.indexOf(v_type);
  263. v_seq_type = sequence_types.indexOf(v_type);
  264. w_num_type = numeric_types.indexOf(w_type);
  265. w_seq_type = sequence_types.indexOf(w_type);
  266. // NoneTypes are considered less than any other type in Python
  267. // note: this only handles comparing NoneType with any non-NoneType.
  268. // Comparing NoneType with NoneType is handled further down.
  269. if (v_type === Sk.builtin.none.prototype.ob$type) {
  270. switch (op) {
  271. case "Lt":
  272. return true;
  273. case "LtE":
  274. return true;
  275. case "Gt":
  276. return false;
  277. case "GtE":
  278. return false;
  279. }
  280. }
  281. if (w_type === Sk.builtin.none.prototype.ob$type) {
  282. switch (op) {
  283. case "Lt":
  284. return false;
  285. case "LtE":
  286. return false;
  287. case "Gt":
  288. return true;
  289. case "GtE":
  290. return true;
  291. }
  292. }
  293. // numeric types are always considered smaller than sequence types in Python
  294. if (v_num_type !== -1 &amp;&amp; w_seq_type !== -1) {
  295. switch (op) {
  296. case "Lt":
  297. return true;
  298. case "LtE":
  299. return true;
  300. case "Gt":
  301. return false;
  302. case "GtE":
  303. return false;
  304. }
  305. }
  306. if (v_seq_type !== -1 &amp;&amp; w_num_type !== -1) {
  307. switch (op) {
  308. case "Lt":
  309. return false;
  310. case "LtE":
  311. return false;
  312. case "Gt":
  313. return true;
  314. case "GtE":
  315. return true;
  316. }
  317. }
  318. // in Python, different sequence types are ordered alphabetically
  319. // by name so that dict &lt; list &lt; str &lt; tuple
  320. if (v_seq_type !== -1 &amp;&amp; w_seq_type !== -1) {
  321. switch (op) {
  322. case "Lt":
  323. return v_seq_type &lt; w_seq_type;
  324. case "LtE":
  325. return v_seq_type &lt;= w_seq_type;
  326. case "Gt":
  327. return v_seq_type > w_seq_type;
  328. case "GtE":
  329. return v_seq_type >= w_seq_type;
  330. }
  331. }
  332. }
  333. // handle identity and membership comparisons
  334. if (op === "Is") {
  335. if (v instanceof Sk.builtin.int_ &amp;&amp; w instanceof Sk.builtin.int_) {
  336. return v.numberCompare(w) === 0;
  337. } else if (v instanceof Sk.builtin.float_ &amp;&amp; w instanceof Sk.builtin.float_) {
  338. return v.numberCompare(w) === 0;
  339. } else if (v instanceof Sk.builtin.lng &amp;&amp; w instanceof Sk.builtin.lng) {
  340. return v.longCompare(w) === 0;
  341. }
  342. return v === w;
  343. }
  344. if (op === "IsNot") {
  345. if (v instanceof Sk.builtin.int_ &amp;&amp; w instanceof Sk.builtin.int_) {
  346. return v.numberCompare(w) !== 0;
  347. } else if (v instanceof Sk.builtin.float_ &amp;&amp; w instanceof Sk.builtin.float_) {
  348. return v.numberCompare(w) !== 0;
  349. }else if (v instanceof Sk.builtin.lng &amp;&amp; w instanceof Sk.builtin.lng) {
  350. return v.longCompare(w) !== 0;
  351. }
  352. return v !== w;
  353. }
  354. if (op === "In") {
  355. return Sk.misceval.isTrue(Sk.abstr.sequenceContains(w, v));
  356. }
  357. if (op === "NotIn") {
  358. return !Sk.misceval.isTrue(Sk.abstr.sequenceContains(w, v));
  359. }
  360. // Call Javascript shortcut method if exists for either object
  361. op2shortcut = {
  362. "Eq" : "ob$eq",
  363. "NotEq": "ob$ne",
  364. "Gt" : "ob$gt",
  365. "GtE" : "ob$ge",
  366. "Lt" : "ob$lt",
  367. "LtE" : "ob$le"
  368. };
  369. shortcut = op2shortcut[op];
  370. v_has_shortcut = v.constructor.prototype.hasOwnProperty(shortcut);
  371. if (v_has_shortcut) {
  372. if ((ret = v[shortcut](w)) !== Sk.builtin.NotImplemented.NotImplemented$) {
  373. return Sk.misceval.isTrue(ret);
  374. }
  375. }
  376. swapped_shortcut = op2shortcut[Sk.misceval.swappedOp_[op]];
  377. w_has_shortcut = w.constructor.prototype.hasOwnProperty(swapped_shortcut);
  378. if (w_has_shortcut) {
  379. if ((ret = w[swapped_shortcut](v)) !== Sk.builtin.NotImplemented.NotImplemented$) {
  380. return Sk.misceval.isTrue(ret);
  381. }
  382. }
  383. // use comparison methods if they are given for either object
  384. if (v.tp$richcompare &amp;&amp; (ret = v.tp$richcompare(w, op)) !== undefined) {
  385. if (ret != Sk.builtin.NotImplemented.NotImplemented$) {
  386. return Sk.misceval.isTrue(ret);
  387. }
  388. }
  389. if (w.tp$richcompare &amp;&amp; (ret = w.tp$richcompare(v, Sk.misceval.swappedOp_[op])) !== undefined) {
  390. if (ret != Sk.builtin.NotImplemented.NotImplemented$) {
  391. return Sk.misceval.isTrue(ret);
  392. }
  393. }
  394. // depending on the op, try left:op:right, and if not, then
  395. // right:reversed-top:left
  396. op2method = {
  397. "Eq" : "__eq__",
  398. "NotEq": "__ne__",
  399. "Gt" : "__gt__",
  400. "GtE" : "__ge__",
  401. "Lt" : "__lt__",
  402. "LtE" : "__le__"
  403. };
  404. method = Sk.abstr.lookupSpecial(v, op2method[op]);
  405. if (method &amp;&amp; !v_has_shortcut) {
  406. ret = Sk.misceval.callsim(method, v, w);
  407. if (ret != Sk.builtin.NotImplemented.NotImplemented$) {
  408. return Sk.misceval.isTrue(ret);
  409. }
  410. }
  411. swapped_method = Sk.abstr.lookupSpecial(w, op2method[Sk.misceval.swappedOp_[op]]);
  412. if (swapped_method &amp;&amp; !w_has_shortcut) {
  413. ret = Sk.misceval.callsim(swapped_method, w, v);
  414. if (ret != Sk.builtin.NotImplemented.NotImplemented$) {
  415. return Sk.misceval.isTrue(ret);
  416. }
  417. }
  418. vcmp = Sk.abstr.lookupSpecial(v, "__cmp__");
  419. if (vcmp) {
  420. try {
  421. ret = Sk.misceval.callsim(vcmp, v, w);
  422. if (Sk.builtin.checkNumber(ret)) {
  423. ret = Sk.builtin.asnum$(ret);
  424. if (op === "Eq") {
  425. return ret === 0;
  426. } else if (op === "NotEq") {
  427. return ret !== 0;
  428. } else if (op === "Lt") {
  429. return ret &lt; 0;
  430. } else if (op === "Gt") {
  431. return ret > 0;
  432. } else if (op === "LtE") {
  433. return ret &lt;= 0;
  434. } else if (op === "GtE") {
  435. return ret >= 0;
  436. }
  437. }
  438. if (ret !== Sk.builtin.NotImplemented.NotImplemented$) {
  439. throw new Sk.builtin.TypeError("comparison did not return an int");
  440. }
  441. } catch (e) {
  442. throw new Sk.builtin.TypeError("comparison did not return an int");
  443. }
  444. }
  445. wcmp = Sk.abstr.lookupSpecial(w, "__cmp__");
  446. if (wcmp) {
  447. // note, flipped on return value and call
  448. try {
  449. ret = Sk.misceval.callsim(wcmp, w, v);
  450. if (Sk.builtin.checkNumber(ret)) {
  451. ret = Sk.builtin.asnum$(ret);
  452. if (op === "Eq") {
  453. return ret === 0;
  454. } else if (op === "NotEq") {
  455. return ret !== 0;
  456. } else if (op === "Lt") {
  457. return ret > 0;
  458. } else if (op === "Gt") {
  459. return ret &lt; 0;
  460. } else if (op === "LtE") {
  461. return ret >= 0;
  462. } else if (op === "GtE") {
  463. return ret &lt;= 0;
  464. }
  465. }
  466. if (ret !== Sk.builtin.NotImplemented.NotImplemented$) {
  467. throw new Sk.builtin.TypeError("comparison did not return an int");
  468. }
  469. } catch (e) {
  470. throw new Sk.builtin.TypeError("comparison did not return an int");
  471. }
  472. }
  473. // handle special cases for comparing None with None or Bool with Bool
  474. if (((v instanceof Sk.builtin.none) &amp;&amp; (w instanceof Sk.builtin.none)) ||
  475. ((v instanceof Sk.builtin.bool) &amp;&amp; (w instanceof Sk.builtin.bool))) {
  476. // Javascript happens to return the same values when comparing null
  477. // with null or true/false with true/false as Python does when
  478. // comparing None with None or True/False with True/False
  479. if (op === "Eq") {
  480. return v.v === w.v;
  481. }
  482. if (op === "NotEq") {
  483. return v.v !== w.v;
  484. }
  485. if (op === "Gt") {
  486. return v.v > w.v;
  487. }
  488. if (op === "GtE") {
  489. return v.v >= w.v;
  490. }
  491. if (op === "Lt") {
  492. return v.v &lt; w.v;
  493. }
  494. if (op === "LtE") {
  495. return v.v &lt;= w.v;
  496. }
  497. }
  498. // handle equality comparisons for any remaining objects
  499. if (op === "Eq") {
  500. if ((v instanceof Sk.builtin.str) &amp;&amp; (w instanceof Sk.builtin.str)) {
  501. return v.v === w.v;
  502. }
  503. return v === w;
  504. }
  505. if (op === "NotEq") {
  506. if ((v instanceof Sk.builtin.str) &amp;&amp; (w instanceof Sk.builtin.str)) {
  507. return v.v !== w.v;
  508. }
  509. return v !== w;
  510. }
  511. vname = Sk.abstr.typeName(v);
  512. wname = Sk.abstr.typeName(w);
  513. throw new Sk.builtin.ValueError("don't know how to compare '" + vname + "' and '" + wname + "'");
  514. };
  515. goog.exportSymbol("Sk.misceval.richCompareBool", Sk.misceval.richCompareBool);
  516. Sk.misceval.objectRepr = function (v) {
  517. goog.asserts.assert(v !== undefined, "trying to repr undefined");
  518. if ((v === null) || (v instanceof Sk.builtin.none)) {
  519. return new Sk.builtin.str("None");
  520. } else if (v === true) {
  521. // todo; these should be consts
  522. return new Sk.builtin.str("True");
  523. } else if (v === false) {
  524. return new Sk.builtin.str("False");
  525. } else if (typeof v === "number") {
  526. return new Sk.builtin.str("" + v);
  527. } else if (!v["$r"]) {
  528. if (v.tp$name) {
  529. return new Sk.builtin.str("&lt;" + v.tp$name + " object>");
  530. } else {
  531. return new Sk.builtin.str("&lt;unknown>");
  532. }
  533. } else if (v.constructor === Sk.builtin.float_) {
  534. if (v.v === Infinity) {
  535. return new Sk.builtin.str("inf");
  536. } else if (v.v === -Infinity) {
  537. return new Sk.builtin.str("-inf");
  538. } else {
  539. return v["$r"]();
  540. }
  541. } else if (v.constructor === Sk.builtin.int_) {
  542. return v["$r"]();
  543. } else {
  544. return v["$r"]();
  545. }
  546. };
  547. goog.exportSymbol("Sk.misceval.objectRepr", Sk.misceval.objectRepr);
  548. Sk.misceval.opAllowsEquality = function (op) {
  549. switch (op) {
  550. case "LtE":
  551. case "Eq":
  552. case "GtE":
  553. return true;
  554. }
  555. return false;
  556. };
  557. goog.exportSymbol("Sk.misceval.opAllowsEquality", Sk.misceval.opAllowsEquality);
  558. Sk.misceval.isTrue = function (x) {
  559. var ret;
  560. if (x === true) {
  561. return true;
  562. }
  563. if (x === false) {
  564. return false;
  565. }
  566. if (x === null) {
  567. return false;
  568. }
  569. if (x.constructor === Sk.builtin.none) {
  570. return false;
  571. }
  572. if (x.constructor === Sk.builtin.NotImplemented) {
  573. return false;
  574. }
  575. if (x.constructor === Sk.builtin.bool) {
  576. return x.v;
  577. }
  578. if (typeof x === "number") {
  579. return x !== 0;
  580. }
  581. if (x instanceof Sk.builtin.lng) {
  582. return x.nb$nonzero();
  583. }
  584. if (x.constructor === Sk.builtin.int_) {
  585. return x.v !== 0;
  586. }
  587. if (x.constructor === Sk.builtin.float_) {
  588. return x.v !== 0;
  589. }
  590. if (x["__nonzero__"]) {
  591. ret = Sk.misceval.callsim(x["__nonzero__"], x);
  592. if (!Sk.builtin.checkInt(ret)) {
  593. throw new Sk.builtin.TypeError("__nonzero__ should return an int");
  594. }
  595. return Sk.builtin.asnum$(ret) !== 0;
  596. }
  597. if (x["__len__"]) {
  598. ret = Sk.misceval.callsim(x["__len__"], x);
  599. if (!Sk.builtin.checkInt(ret)) {
  600. throw new Sk.builtin.TypeError("__len__ should return an int");
  601. }
  602. return Sk.builtin.asnum$(ret) !== 0;
  603. }
  604. if (x.mp$length) {
  605. return Sk.builtin.asnum$(x.mp$length()) !== 0;
  606. }
  607. if (x.sq$length) {
  608. return Sk.builtin.asnum$(x.sq$length()) !== 0;
  609. }
  610. return true;
  611. };
  612. goog.exportSymbol("Sk.misceval.isTrue", Sk.misceval.isTrue);
  613. Sk.misceval.softspace_ = false;
  614. Sk.misceval.print_ = function (x) {
  615. // this was function print(x) not sure why...
  616. var isspace;
  617. var s;
  618. if (Sk.misceval.softspace_) {
  619. if (x !== "\n") {
  620. Sk.output(" ");
  621. }
  622. Sk.misceval.softspace_ = false;
  623. }
  624. s = new Sk.builtin.str(x);
  625. Sk.output(s.v);
  626. isspace = function (c) {
  627. return c === "\n" || c === "\t" || c === "\r";
  628. };
  629. if (s.v.length === 0 || !isspace(s.v[s.v.length - 1]) || s.v[s.v.length - 1] === " ") {
  630. Sk.misceval.softspace_ = true;
  631. }
  632. };
  633. goog.exportSymbol("Sk.misceval.print_", Sk.misceval.print_);
  634. /**
  635. * @param {string} name
  636. * @param {Object=} other generally globals
  637. */
  638. Sk.misceval.loadname = function (name, other) {
  639. var bi;
  640. var v = other[name];
  641. if (v !== undefined) {
  642. return v;
  643. }
  644. bi = Sk.builtins[name];
  645. if (bi !== undefined) {
  646. return bi;
  647. }
  648. name = name.replace("_$rw$", "");
  649. name = name.replace("_$rn$", "");
  650. throw new Sk.builtin.NameError("name '" + name + "' is not defined");
  651. };
  652. goog.exportSymbol("Sk.misceval.loadname", Sk.misceval.loadname);
  653. /**
  654. *
  655. * Notes on necessity for 'call()':
  656. *
  657. * Classes are callable in python to create an instance of the class. If
  658. * we're calling "C()" we cannot tell at the call site whether we're
  659. * calling a standard function, or instantiating a class.
  660. *
  661. * JS does not support user-level callables. So, we can't use the normal
  662. * prototype hierarchy to make the class inherit from a 'class' type
  663. * where the various tp$getattr, etc. methods would live.
  664. *
  665. * Instead, we must copy all the methods from the prototype of our class
  666. * type onto every instance of the class constructor function object.
  667. * That way, both "C()" and "C.tp$getattr(...)" can still work. This is
  668. * of course quite expensive.
  669. *
  670. * The alternative would be to indirect all calls (whether classes or
  671. * regular functions) through something like C.$call(...). In the case
  672. * of class construction, $call could then call the constructor after
  673. * munging arguments to pass them on. This would impose a penalty on
  674. * regular function calls unfortunately, as they would have to do the
  675. * same thing.
  676. *
  677. * Note that the same problem exists for function objects too (a "def"
  678. * creates a function object that also has properties). It just happens
  679. * that attributes on classes in python are much more useful and common
  680. * that the attributes on functions.
  681. *
  682. * Also note, that for full python compatibility we have to do the $call
  683. * method because any python object could have a __call__ method which
  684. * makes the python object callable too. So, unless we were to make
  685. * *all* objects simply (function(){...}) and use the dict to create
  686. * hierarchy, there would be no way to call that python user function. I
  687. * think I'm prepared to sacrifice __call__ support, or only support it
  688. * post-ECMA5 or something.
  689. *
  690. * Is using (function(){...}) as the only object type too crazy?
  691. * Probably. Better or worse than having two levels of function
  692. * invocation for every function call?
  693. *
  694. * For a class `C' with instance `inst' we have the following cases:
  695. *
  696. * 1. C.attr
  697. *
  698. * 2. C.staticmeth()
  699. *
  700. * 3. x = C.staticmeth; x()
  701. *
  702. * 4. inst = C()
  703. *
  704. * 5. inst.attr
  705. *
  706. * 6. inst.meth()
  707. *
  708. * 7. x = inst.meth; x()
  709. *
  710. * 8. inst(), where C defines a __call__
  711. *
  712. * Because in general these are accomplished by a helper function
  713. * (tp$getattr/setattr/slice/ass_slice/etc.) it seems appropriate to add
  714. * a call that generally just calls through, but sometimes handles the
  715. * unusual cases. Once ECMA-5 is more broadly supported we can revisit
  716. * and hopefully optimize.
  717. *
  718. * @param {Object} func the thing to call
  719. * @param {Object=} kwdict **kwargs
  720. * @param {Object=} varargseq **args
  721. * @param {Object=} kws keyword args or undef
  722. * @param {...*} args stuff to pass it
  723. *
  724. *
  725. * TODO I think all the above is out of date.
  726. */
  727. Sk.misceval.call = function (func, kwdict, varargseq, kws, args) {
  728. args = Array.prototype.slice.call(arguments, 4);
  729. // todo; possibly inline apply to avoid extra stack frame creation
  730. return Sk.misceval.apply(func, kwdict, varargseq, kws, args);
  731. };
  732. goog.exportSymbol("Sk.misceval.call", Sk.misceval.call);
  733. /**
  734. * @param {?Object} suspensionHandlers
  735. * @param {Object} func the thing to call
  736. * @param {Object=} kwdict **kwargs
  737. * @param {Object=} varargseq **args
  738. * @param {Object=} kws keyword args or undef
  739. * @param {...*} args stuff to pass it
  740. *
  741. *
  742. * TODO I think all the above is out of date.
  743. */
  744. Sk.misceval.callAsync = function (suspensionHandlers, func, kwdict, varargseq, kws, args) {
  745. args = Array.prototype.slice.call(arguments, 5);
  746. // todo; possibly inline apply to avoid extra stack frame creation
  747. return Sk.misceval.applyAsync(suspensionHandlers, func, kwdict, varargseq, kws, args);
  748. };
  749. goog.exportSymbol("Sk.misceval.callAsync", Sk.misceval.callAsync);
  750. Sk.misceval.callOrSuspend = function (func, kwdict, varargseq, kws, args) {
  751. args = Array.prototype.slice.call(arguments, 4);
  752. // todo; possibly inline apply to avoid extra stack frame creation
  753. return Sk.misceval.applyOrSuspend(func, kwdict, varargseq, kws, args);
  754. };
  755. goog.exportSymbol("Sk.misceval.callOrSuspend", Sk.misceval.callOrSuspend);
  756. /**
  757. * @param {Object} func the thing to call
  758. * @param {...*} args stuff to pass it
  759. */
  760. Sk.misceval.callsim = function (func, args) {
  761. args = Array.prototype.slice.call(arguments, 1);
  762. return Sk.misceval.apply(func, undefined, undefined, undefined, args);
  763. };
  764. goog.exportSymbol("Sk.misceval.callsim", Sk.misceval.callsim);
  765. /**
  766. * @param {?Object} suspensionHandlers any custom suspension handlers
  767. * @param {Object} func the thing to call
  768. * @param {...*} args stuff to pass it
  769. */
  770. Sk.misceval.callsimAsync = function (suspensionHandlers, func, args) {
  771. args = Array.prototype.slice.call(arguments, 2);
  772. return Sk.misceval.applyAsync(suspensionHandlers, func, undefined, undefined, undefined, args);
  773. };
  774. goog.exportSymbol("Sk.misceval.callsimAsync", Sk.misceval.callsimAsync);
  775. /**
  776. * @param {Object} func the thing to call
  777. * @param {...*} args stuff to pass it
  778. */
  779. Sk.misceval.callsimOrSuspend = function (func, args) {
  780. args = Array.prototype.slice.call(arguments, 1);
  781. return Sk.misceval.applyOrSuspend(func, undefined, undefined, undefined, args);
  782. };
  783. goog.exportSymbol("Sk.misceval.callsimOrSuspend", Sk.misceval.callsimOrSuspend);
  784. /**
  785. * Wrap Sk.misceval.applyOrSuspend, but throw an error if we suspend
  786. */
  787. Sk.misceval.apply = function (func, kwdict, varargseq, kws, args) {
  788. var r = Sk.misceval.applyOrSuspend(func, kwdict, varargseq, kws, args);
  789. if (r instanceof Sk.misceval.Suspension) {
  790. return Sk.misceval.retryOptionalSuspensionOrThrow(r);
  791. } else {
  792. return r;
  793. }
  794. };
  795. goog.exportSymbol("Sk.misceval.apply", Sk.misceval.apply);
  796. /**
  797. * Wraps anything that can return an Sk.misceval.Suspension, and returns a
  798. * JS Promise with the result. Also takes an object map of suspension handlers:
  799. * pass in {"suspType": function (susp) {} }, and your function will be called
  800. * with the Suspension object if susp.type=="suspType". The type "*" will match
  801. * all otherwise unhandled suspensions.
  802. *
  803. * A suspension handler should return a Promise yielding the return value of
  804. * r.resume() - ie, either the final return value of this call or another
  805. * Suspension. That is, the null suspension handler is:
  806. *
  807. * function handler(susp) {
  808. * return new Promise(function(resolve, reject) {
  809. * try {
  810. * resolve(susp.resume());
  811. * } catch(e) {
  812. * reject(e);
  813. * }
  814. * });
  815. * }
  816. *
  817. * Alternatively, a handler can return null to perform the default action for
  818. * that suspension type.
  819. *
  820. * (Note: do *not* call asyncToPromise() in a suspension handler; this will
  821. * create a new Promise object for each such suspension that occurs)
  822. *
  823. * asyncToPromise() returns a Promise that will be resolved with the final
  824. * return value, or rejected with an exception if one is thrown.
  825. *
  826. * @param{function()} suspendablefn returns either a result or a Suspension
  827. * @param{Object=} suspHandlers an object map of suspension handlers
  828. */
  829. Sk.misceval.asyncToPromise = function(suspendablefn, suspHandlers) {
  830. return new Promise(function(resolve, reject) {
  831. try {
  832. var r = suspendablefn();
  833. (function handleResponse (r) {
  834. try {
  835. // jsh*nt insists these be defined outside the loop
  836. var resume = function() {
  837. handleResponse(r.resume());
  838. };
  839. var resumeWithData = function resolved(x) {
  840. try {
  841. r.data["result"] = x;
  842. resume();
  843. } catch(e) {
  844. reject(e);
  845. }
  846. };
  847. var resumeWithError = function rejected(e) {
  848. try {
  849. r.data["error"] = e;
  850. resume();
  851. } catch(ex) {
  852. reject(ex);
  853. }
  854. };
  855. while (r instanceof Sk.misceval.Suspension) {
  856. var handler = suspHandlers &amp;&amp; (suspHandlers[r.data["type"]] || suspHandlers["*"]);
  857. if (handler) {
  858. var handlerPromise = handler(r);
  859. if (handlerPromise) {
  860. handlerPromise.then(handleResponse, reject);
  861. return;
  862. }
  863. }
  864. if (r.data["type"] == "Sk.promise") {
  865. r.data["promise"].then(resumeWithData, resumeWithError);
  866. return;
  867. } else if (r.data["type"] == "Sk.yield" &amp;&amp; typeof setTimeout === "function") {
  868. setTimeout(resume, 0);
  869. return;
  870. } else if (r.optional) {
  871. // Unhandled optional suspensions just get
  872. // resumed immediately, and we go around the loop again.
  873. r = r.resume();
  874. } else {
  875. // Unhandled, non-optional suspension.
  876. throw new Sk.builtin.SuspensionError("Unhandled non-optional suspension of type '"+r.data["type"]+"'");
  877. }
  878. }
  879. resolve(r);
  880. } catch(e) {
  881. reject(e);
  882. }
  883. })(r);
  884. } catch (e) {
  885. reject(e);
  886. }
  887. });
  888. };
  889. goog.exportSymbol("Sk.misceval.asyncToPromise", Sk.misceval.asyncToPromise);
  890. Sk.misceval.applyAsync = function (suspHandlers, func, kwdict, varargseq, kws, args) {
  891. return Sk.misceval.asyncToPromise(function() {
  892. return Sk.misceval.applyOrSuspend(func, kwdict, varargseq, kws, args);
  893. }, suspHandlers);
  894. };
  895. goog.exportSymbol("Sk.misceval.applyAsync", Sk.misceval.applyAsync);
  896. /**
  897. * Chain together a set of functions, each of which might return a value or
  898. * an Sk.misceval.Suspension. Each function is called with the return value of
  899. * the preceding function, but does not see any suspensions. If a function suspends,
  900. * Sk.misceval.chain() returns a suspension that will resume the chain once an actual
  901. * return value is available.
  902. *
  903. * The idea is to allow a Promise-like chaining of possibly-suspending steps without
  904. * repeating boilerplate suspend-and-resume code.
  905. *
  906. * For example, imagine we call Sk.misceval.chain(x, f).
  907. * - If x is a value, we return f(x).
  908. * - If x is a suspension, we suspend. We will suspend and resume until we get a
  909. * return value, and then we will return f(&lt;resumed-value).
  910. * This can be expanded to an arbitrary number of functions
  911. * (eg Sk.misceval.chain(x, f, g), which is equivalent to chain(chain(x, f), g).)
  912. *
  913. * @param {*} initialValue
  914. * @param {...function(*)} chainedFns
  915. */
  916. Sk.misceval.chain = function (initialValue, chainedFns) {
  917. var fs = arguments, i = 1;
  918. return (function nextStep(r) {
  919. while (i &lt; fs.length) {
  920. if (r instanceof Sk.misceval.Suspension) {
  921. return new Sk.misceval.Suspension(nextStep, r);
  922. }
  923. r = fs[i](r);
  924. i++;
  925. }
  926. return r;
  927. })(initialValue);
  928. };
  929. goog.exportSymbol("Sk.misceval.chain", Sk.misceval.chain);
  930. /**
  931. * same as Sk.misceval.call except args is an actual array, rather than
  932. * varargs.
  933. */
  934. Sk.misceval.applyOrSuspend = function (func, kwdict, varargseq, kws, args) {
  935. var fcall;
  936. var kwix;
  937. var numPosParams;
  938. var numNonOptParams;
  939. var it, i;
  940. if (func === null || func instanceof Sk.builtin.none) {
  941. throw new Sk.builtin.TypeError("'" + Sk.abstr.typeName(func) + "' object is not callable");
  942. } else if (typeof func === "function") {
  943. // todo; i believe the only time this happens is the wrapper
  944. // function around generators (that creates the iterator).
  945. // should just make that a real function object and get rid
  946. // of this case.
  947. // alternatively, put it to more use, and perhaps use
  948. // descriptors to create builtin.func's in other places.
  949. // This actually happens for all builtin functions (in
  950. // builtin.js, for example) as they are javascript functions,
  951. // not Sk.builtin.func objects.
  952. if (func.sk$klass) {
  953. // klass wrapper around __init__ requires special handling
  954. return func.apply(null, [kwdict, varargseq, kws, args, true]);
  955. }
  956. if (varargseq) {
  957. for (it = varargseq.tp$iter(), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) {
  958. args.push(i);
  959. }
  960. }
  961. if (kwdict) {
  962. goog.asserts.fail("kwdict not implemented;");
  963. }
  964. //goog.asserts.assert(((kws === undefined) || (kws.length === 0)));
  965. //print('kw args location: '+ kws + ' args ' + args.length)
  966. if (kws !== undefined &amp;&amp; kws.length > 0) {
  967. if (!func.co_varnames) {
  968. throw new Sk.builtin.ValueError("Keyword arguments are not supported by this function");
  969. }
  970. //number of positionally placed optional parameters
  971. numNonOptParams = func.co_numargs - func.co_varnames.length;
  972. numPosParams = args.length - numNonOptParams;
  973. //add defaults
  974. args = args.concat(func.$defaults.slice(numPosParams));
  975. for (i = 0; i &lt; kws.length; i = i + 2) {
  976. kwix = func.co_varnames.indexOf(kws[i]);
  977. if (kwix === -1) {
  978. throw new Sk.builtin.TypeError("'" + kws[i] + "' is an invalid keyword argument for this function");
  979. }
  980. if (kwix &lt; numPosParams) {
  981. throw new Sk.builtin.TypeError("Argument given by name ('" + kws[i] + "') and position (" + (kwix + numNonOptParams + 1) + ")");
  982. }
  983. args[kwix + numNonOptParams] = kws[i + 1];
  984. }
  985. }
  986. //append kw args to args, filling in the default value where none is provided.
  987. return func.apply(null, args);
  988. } else {
  989. fcall = func.tp$call;
  990. if (fcall !== undefined) {
  991. if (varargseq) {
  992. for (it = varargseq.tp$iter(), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) {
  993. args.push(i);
  994. }
  995. }
  996. if (kwdict) {
  997. goog.asserts.fail("kwdict not implemented;");
  998. }
  999. return fcall.call(func, args, kws, kwdict);
  1000. }
  1001. // todo; can we push this into a tp$call somewhere so there's
  1002. // not redundant checks everywhere for all of these __x__ ones?
  1003. fcall = func.__call__;
  1004. if (fcall !== undefined) {
  1005. // func is actually the object here because we got __call__
  1006. // from it. todo; should probably use descr_get here
  1007. args.unshift(func);
  1008. return Sk.misceval.apply(fcall, kws, args, kwdict, varargseq);
  1009. }
  1010. throw new Sk.builtin.TypeError("'" + Sk.abstr.typeName(func) + "' object is not callable");
  1011. }
  1012. };
  1013. goog.exportSymbol("Sk.misceval.applyOrSuspend", Sk.misceval.applyOrSuspend);
  1014. /**
  1015. * Constructs a class object given a code object representing the body
  1016. * of the class, the name of the class, and the list of bases.
  1017. *
  1018. * There are no "old-style" classes in Skulpt, so use the user-specified
  1019. * metaclass (todo;) if there is one, the type of the 0th base class if
  1020. * there's bases, or otherwise the 'type' type.
  1021. *
  1022. * The func code object is passed a (js) dict for its locals which it
  1023. * stores everything into.
  1024. *
  1025. * The metaclass is then called as metaclass(name, bases, locals) and
  1026. * should return a newly constructed class object.
  1027. *
  1028. */
  1029. Sk.misceval.buildClass = function (globals, func, name, bases) {
  1030. // todo; metaclass
  1031. var klass;
  1032. var meta = Sk.builtin.type;
  1033. var locals = {};
  1034. // init the dict for the class
  1035. func(globals, locals, []);
  1036. // ToDo: check if func contains the __meta__ attribute
  1037. // or if the bases contain __meta__
  1038. // new Syntax would be different
  1039. // file's __name__ is class's __module__
  1040. locals.__module__ = globals["__name__"];
  1041. var _name = new Sk.builtin.str(name);
  1042. var _bases = new Sk.builtin.tuple(bases);
  1043. var _locals = [];
  1044. var key;
  1045. // build array for python dict
  1046. for (key in locals) {
  1047. if (!locals.hasOwnProperty(key)) {
  1048. //The current property key not a direct property of p
  1049. continue;
  1050. }
  1051. _locals.push(new Sk.builtin.str(key)); // push key
  1052. _locals.push(locals[key]); // push associated value
  1053. }
  1054. _locals = new Sk.builtin.dict(_locals);
  1055. klass = Sk.misceval.callsim(meta, _name, _bases, _locals);
  1056. return klass;
  1057. };
  1058. goog.exportSymbol("Sk.misceval.buildClass", Sk.misceval.buildClass);
  1059. </code></pre>
  1060. </article>
  1061. </section>
  1062. </div>
  1063. <nav>
  1064. <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Sk.abstr.iter-seqIter.html">seqIter</a></li><li><a href="Sk.builtin.bool.html">bool</a></li><li><a href="Sk.builtin.float_.html">float_</a></li><li><a href="Sk.builtin.func.html">func</a></li><li><a href="Sk.builtin.int_.html">int_</a></li><li><a href="Sk.builtin.none.html">none</a></li><li><a href="Sk.builtin.NotImplemented.html">NotImplemented</a></li><li><a href="Sk.builtin.numtype.html">numtype</a></li><li><a href="Sk.builtin.object.html">object</a></li><li><a href="Sk.builtin.seqtype.html">seqtype</a></li><li><a href="Sk.misceval.Suspension.html">Suspension</a></li></ul><h3>Namespaces</h3><ul><li><a href="Sk.html">Sk</a></li><li><a href="Sk.abstr.html">abstr</a></li><li><a href="Sk.builtin.html">builtin</a></li><li><a href="Sk.ffi.html">ffi</a></li><li><a href="Sk.misceval.html">misceval</a></li></ul>
  1065. </nav>
  1066. <br class="clear">
  1067. <footer>
  1068. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0</a> on Thu Aug 13 2015 08:14:27 GMT-0500 (CDT)
  1069. </footer>
  1070. <script> prettyPrint(); </script>
  1071. <script src="scripts/linenumber.js"> </script>
  1072. </body>
  1073. </html>