UNPKG

sku-pg

Version:

Skulpt is a Javascript implementation of Python 2.x. Python that runs in your browser!

1,198 lines (1,073 loc) 41 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: misceval.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: misceval.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>/** * @namespace Sk.misceval * */ Sk.misceval = {}; /* Suspension object format: {resume: function() {...}, // the continuation - returns either another suspension or the return value data: &lt;copied down from innermost level>, optional: &lt;if true, can be resumed immediately (eg debug stops)>, child: &lt;Suspension, or null if we are the innermost level>, $blk: &lt;>, $loc: &lt;>, $gbl: &lt;>, $exc: &lt;>, $err: &lt;>, [$cell: &lt;>], } */ /** * * Hi kids lets make a suspension... * @constructor * @param{function(?)=} resume A function to be called on resume. child is resumed first and its return value is passed to this function. * @param{Object=} child A child suspension. 'optional' will be copied from here if supplied. * @param{Object=} data Data attached to this suspension. Will be copied from child if not supplied. */ Sk.misceval.Suspension = function Suspension(resume, child, data) { this.isSuspension = true; if (resume !== undefined &amp;&amp; child !== undefined) { this.resume = function() { return resume(child.resume()); }; } this.child = child; this.optional = child !== undefined &amp;&amp; child.optional; if (data === undefined &amp;&amp; child !== undefined) { this.data = child.data; } else { this.data = data; } }; goog.exportSymbol("Sk.misceval.Suspension", Sk.misceval.Suspension); /** * * Well this seems pretty obvious by the name what it should do.. * * @param{Sk.misceval.Suspension} susp * @param{string=} message */ Sk.misceval.retryOptionalSuspensionOrThrow = function (susp, message) { while (susp instanceof Sk.misceval.Suspension) { if (!susp.optional) { throw new Sk.builtin.SuspensionError(message || "Cannot call a function that blocks or suspends here"); } susp = susp.resume(); } return susp; }; goog.exportSymbol("Sk.misceval.retryOptionalSuspensionOrThrow", Sk.misceval.retryOptionalSuspensionOrThrow); /** * Check if the given object is valid to use as an index. Only ints, or if the object has an `__index__` method. * @param o * @returns {boolean} */ Sk.misceval.isIndex = function (o) { if (Sk.builtin.checkInt(o)) { return true; } if (Sk.abstr.lookupSpecial(o, "__index__")) { return true; } return false; }; goog.exportSymbol("Sk.misceval.isIndex", Sk.misceval.isIndex); Sk.misceval.asIndex = function (o) { var idxfn, ret; if (!Sk.misceval.isIndex(o)) { return undefined; } if (o === null) { return undefined; } if (o === true) { return 1; } if (o === false) { return 0; } if (typeof o === "number") { return o; } if (o.constructor === Sk.builtin.int_) { return o.v; } if (o.constructor === Sk.builtin.lng) { return o.tp$index(); } if (o.constructor === Sk.builtin.bool) { return Sk.builtin.asnum$(o); } idxfn = Sk.abstr.lookupSpecial(o, "__index__"); if (idxfn) { ret = Sk.misceval.callsim(idxfn, o); if (!Sk.builtin.checkInt(ret)) { throw new Sk.builtin.TypeError("__index__ returned non-(int,long) (type " + Sk.abstr.typeName(ret) + ")"); } return Sk.builtin.asnum$(ret); } goog.asserts.fail("todo asIndex;"); }; /** * return u[v:w] */ Sk.misceval.applySlice = function (u, v, w, canSuspend) { var ihigh; var ilow; if (u.sq$slice &amp;&amp; Sk.misceval.isIndex(v) &amp;&amp; Sk.misceval.isIndex(w)) { ilow = Sk.misceval.asIndex(v); if (ilow === undefined) { ilow = 0; } ihigh = Sk.misceval.asIndex(w); if (ihigh === undefined) { ihigh = 1e100; } return Sk.abstr.sequenceGetSlice(u, ilow, ihigh); } return Sk.abstr.objectGetItem(u, new Sk.builtin.slice(v, w, null), canSuspend); }; goog.exportSymbol("Sk.misceval.applySlice", Sk.misceval.applySlice); /** * u[v:w] = x */ Sk.misceval.assignSlice = function (u, v, w, x, canSuspend) { var slice; var ihigh; var ilow; if (u.sq$ass_slice &amp;&amp; Sk.misceval.isIndex(v) &amp;&amp; Sk.misceval.isIndex(w)) { ilow = Sk.misceval.asIndex(v) || 0; ihigh = Sk.misceval.asIndex(w) || 1e100; if (x === null) { Sk.abstr.sequenceDelSlice(u, ilow, ihigh); } else { Sk.abstr.sequenceSetSlice(u, ilow, ihigh, x); } } else { slice = new Sk.builtin.slice(v, w); if (x === null) { return Sk.abstr.objectDelItem(u, slice); } else { return Sk.abstr.objectSetItem(u, slice, x, canSuspend); } } }; goog.exportSymbol("Sk.misceval.assignSlice", Sk.misceval.assignSlice); /** * Used by min() and max() to get an array from arbitrary input. * Note that this does no validation, just coercion. */ Sk.misceval.arrayFromArguments = function (args) { // If args is not a single thing return as is var it, i; var res; var arg; if (args.length != 1) { return args; } arg = args[0]; if (arg instanceof Sk.builtin.set) { // this is a Sk.builtin.set arg = arg.tp$iter().$obj; } else if (arg instanceof Sk.builtin.dict) { // this is a Sk.builtin.list arg = Sk.builtin.dict.prototype["keys"].func_code(arg); } // shouldn't else if here as the above may output lists to arg. if (arg instanceof Sk.builtin.list || arg instanceof Sk.builtin.tuple) { return arg.v; } else if (Sk.builtin.checkIterable(arg)) { // handle arbitrary iterable (strings, generators, etc.) res = []; for (it = Sk.abstr.iter(arg), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) { res.push(i); } return res; } throw new Sk.builtin.TypeError("'" + Sk.abstr.typeName(arg) + "' object is not iterable"); }; goog.exportSymbol("Sk.misceval.arrayFromArguments", Sk.misceval.arrayFromArguments); /** * for reversed comparison: Gt -> Lt, etc. */ Sk.misceval.swappedOp_ = { "Eq" : "Eq", "NotEq": "NotEq", "Lt" : "GtE", "LtE" : "Gt", "Gt" : "LtE", "GtE" : "Lt", "Is" : "IsNot", "IsNot": "Is", "In_" : "NotIn", "NotIn": "In_" }; Sk.misceval.richCompareBool = function (v, w, op) { // v and w must be Python objects. will return Javascript true or false for internal use only // if you want to return a value from richCompareBool to Python you must wrap as Sk.builtin.bool first var wname, vname, ret, swapped_method, method, swapped_shortcut, shortcut, v_has_shortcut, w_has_shortcut, op2method, op2shortcut, vcmp, wcmp, w_seq_type, w_num_type, v_seq_type, v_num_type, sequence_types, numeric_types, w_type, v_type; goog.asserts.assert((v !== null) &amp;&amp; (v !== undefined), "passed null or undefined parameter to Sk.misceval.richCompareBool"); goog.asserts.assert((w !== null) &amp;&amp; (w !== undefined), "passed null or undefined parameter to Sk.misceval.richCompareBool"); v_type = new Sk.builtin.type(v); w_type = new Sk.builtin.type(w); // Python has specific rules when comparing two different builtin types // currently, this code will execute even if the objects are not builtin types // but will fall through and not return anything in this section if ((v_type !== w_type) &amp;&amp; (op === "GtE" || op === "Gt" || op === "LtE" || op === "Lt")) { // note: sets are omitted here because they can only be compared to other sets numeric_types = [Sk.builtin.float_.prototype.ob$type, Sk.builtin.int_.prototype.ob$type, Sk.builtin.lng.prototype.ob$type, Sk.builtin.bool.prototype.ob$type]; sequence_types = [Sk.builtin.dict.prototype.ob$type, Sk.builtin.enumerate.prototype.ob$type, Sk.builtin.list.prototype.ob$type, Sk.builtin.str.prototype.ob$type, Sk.builtin.tuple.prototype.ob$type]; v_num_type = numeric_types.indexOf(v_type); v_seq_type = sequence_types.indexOf(v_type); w_num_type = numeric_types.indexOf(w_type); w_seq_type = sequence_types.indexOf(w_type); // NoneTypes are considered less than any other type in Python // note: this only handles comparing NoneType with any non-NoneType. // Comparing NoneType with NoneType is handled further down. if (v_type === Sk.builtin.none.prototype.ob$type) { switch (op) { case "Lt": return true; case "LtE": return true; case "Gt": return false; case "GtE": return false; } } if (w_type === Sk.builtin.none.prototype.ob$type) { switch (op) { case "Lt": return false; case "LtE": return false; case "Gt": return true; case "GtE": return true; } } // numeric types are always considered smaller than sequence types in Python if (v_num_type !== -1 &amp;&amp; w_seq_type !== -1) { switch (op) { case "Lt": return true; case "LtE": return true; case "Gt": return false; case "GtE": return false; } } if (v_seq_type !== -1 &amp;&amp; w_num_type !== -1) { switch (op) { case "Lt": return false; case "LtE": return false; case "Gt": return true; case "GtE": return true; } } // in Python, different sequence types are ordered alphabetically // by name so that dict &lt; list &lt; str &lt; tuple if (v_seq_type !== -1 &amp;&amp; w_seq_type !== -1) { switch (op) { case "Lt": return v_seq_type &lt; w_seq_type; case "LtE": return v_seq_type &lt;= w_seq_type; case "Gt": return v_seq_type > w_seq_type; case "GtE": return v_seq_type >= w_seq_type; } } } // handle identity and membership comparisons if (op === "Is") { if (v instanceof Sk.builtin.int_ &amp;&amp; w instanceof Sk.builtin.int_) { return v.numberCompare(w) === 0; } else if (v instanceof Sk.builtin.float_ &amp;&amp; w instanceof Sk.builtin.float_) { return v.numberCompare(w) === 0; } else if (v instanceof Sk.builtin.lng &amp;&amp; w instanceof Sk.builtin.lng) { return v.longCompare(w) === 0; } return v === w; } if (op === "IsNot") { if (v instanceof Sk.builtin.int_ &amp;&amp; w instanceof Sk.builtin.int_) { return v.numberCompare(w) !== 0; } else if (v instanceof Sk.builtin.float_ &amp;&amp; w instanceof Sk.builtin.float_) { return v.numberCompare(w) !== 0; }else if (v instanceof Sk.builtin.lng &amp;&amp; w instanceof Sk.builtin.lng) { return v.longCompare(w) !== 0; } return v !== w; } if (op === "In") { return Sk.misceval.isTrue(Sk.abstr.sequenceContains(w, v)); } if (op === "NotIn") { return !Sk.misceval.isTrue(Sk.abstr.sequenceContains(w, v)); } // Call Javascript shortcut method if exists for either object op2shortcut = { "Eq" : "ob$eq", "NotEq": "ob$ne", "Gt" : "ob$gt", "GtE" : "ob$ge", "Lt" : "ob$lt", "LtE" : "ob$le" }; shortcut = op2shortcut[op]; v_has_shortcut = v.constructor.prototype.hasOwnProperty(shortcut); if (v_has_shortcut) { if ((ret = v[shortcut](w)) !== Sk.builtin.NotImplemented.NotImplemented$) { return Sk.misceval.isTrue(ret); } } swapped_shortcut = op2shortcut[Sk.misceval.swappedOp_[op]]; w_has_shortcut = w.constructor.prototype.hasOwnProperty(swapped_shortcut); if (w_has_shortcut) { if ((ret = w[swapped_shortcut](v)) !== Sk.builtin.NotImplemented.NotImplemented$) { return Sk.misceval.isTrue(ret); } } // use comparison methods if they are given for either object if (v.tp$richcompare &amp;&amp; (ret = v.tp$richcompare(w, op)) !== undefined) { if (ret != Sk.builtin.NotImplemented.NotImplemented$) { return Sk.misceval.isTrue(ret); } } if (w.tp$richcompare &amp;&amp; (ret = w.tp$richcompare(v, Sk.misceval.swappedOp_[op])) !== undefined) { if (ret != Sk.builtin.NotImplemented.NotImplemented$) { return Sk.misceval.isTrue(ret); } } // depending on the op, try left:op:right, and if not, then // right:reversed-top:left op2method = { "Eq" : "__eq__", "NotEq": "__ne__", "Gt" : "__gt__", "GtE" : "__ge__", "Lt" : "__lt__", "LtE" : "__le__" }; method = Sk.abstr.lookupSpecial(v, op2method[op]); if (method &amp;&amp; !v_has_shortcut) { ret = Sk.misceval.callsim(method, v, w); if (ret != Sk.builtin.NotImplemented.NotImplemented$) { return Sk.misceval.isTrue(ret); } } swapped_method = Sk.abstr.lookupSpecial(w, op2method[Sk.misceval.swappedOp_[op]]); if (swapped_method &amp;&amp; !w_has_shortcut) { ret = Sk.misceval.callsim(swapped_method, w, v); if (ret != Sk.builtin.NotImplemented.NotImplemented$) { return Sk.misceval.isTrue(ret); } } vcmp = Sk.abstr.lookupSpecial(v, "__cmp__"); if (vcmp) { try { ret = Sk.misceval.callsim(vcmp, v, w); if (Sk.builtin.checkNumber(ret)) { ret = Sk.builtin.asnum$(ret); if (op === "Eq") { return ret === 0; } else if (op === "NotEq") { return ret !== 0; } else if (op === "Lt") { return ret &lt; 0; } else if (op === "Gt") { return ret > 0; } else if (op === "LtE") { return ret &lt;= 0; } else if (op === "GtE") { return ret >= 0; } } if (ret !== Sk.builtin.NotImplemented.NotImplemented$) { throw new Sk.builtin.TypeError("comparison did not return an int"); } } catch (e) { throw new Sk.builtin.TypeError("comparison did not return an int"); } } wcmp = Sk.abstr.lookupSpecial(w, "__cmp__"); if (wcmp) { // note, flipped on return value and call try { ret = Sk.misceval.callsim(wcmp, w, v); if (Sk.builtin.checkNumber(ret)) { ret = Sk.builtin.asnum$(ret); if (op === "Eq") { return ret === 0; } else if (op === "NotEq") { return ret !== 0; } else if (op === "Lt") { return ret > 0; } else if (op === "Gt") { return ret &lt; 0; } else if (op === "LtE") { return ret >= 0; } else if (op === "GtE") { return ret &lt;= 0; } } if (ret !== Sk.builtin.NotImplemented.NotImplemented$) { throw new Sk.builtin.TypeError("comparison did not return an int"); } } catch (e) { throw new Sk.builtin.TypeError("comparison did not return an int"); } } // handle special cases for comparing None with None or Bool with Bool if (((v instanceof Sk.builtin.none) &amp;&amp; (w instanceof Sk.builtin.none)) || ((v instanceof Sk.builtin.bool) &amp;&amp; (w instanceof Sk.builtin.bool))) { // Javascript happens to return the same values when comparing null // with null or true/false with true/false as Python does when // comparing None with None or True/False with True/False if (op === "Eq") { return v.v === w.v; } if (op === "NotEq") { return v.v !== w.v; } if (op === "Gt") { return v.v > w.v; } if (op === "GtE") { return v.v >= w.v; } if (op === "Lt") { return v.v &lt; w.v; } if (op === "LtE") { return v.v &lt;= w.v; } } // handle equality comparisons for any remaining objects if (op === "Eq") { if ((v instanceof Sk.builtin.str) &amp;&amp; (w instanceof Sk.builtin.str)) { return v.v === w.v; } return v === w; } if (op === "NotEq") { if ((v instanceof Sk.builtin.str) &amp;&amp; (w instanceof Sk.builtin.str)) { return v.v !== w.v; } return v !== w; } vname = Sk.abstr.typeName(v); wname = Sk.abstr.typeName(w); throw new Sk.builtin.ValueError("don't know how to compare '" + vname + "' and '" + wname + "'"); }; goog.exportSymbol("Sk.misceval.richCompareBool", Sk.misceval.richCompareBool); Sk.misceval.objectRepr = function (v) { goog.asserts.assert(v !== undefined, "trying to repr undefined"); if ((v === null) || (v instanceof Sk.builtin.none)) { return new Sk.builtin.str("None"); } else if (v === true) { // todo; these should be consts return new Sk.builtin.str("True"); } else if (v === false) { return new Sk.builtin.str("False"); } else if (typeof v === "number") { return new Sk.builtin.str("" + v); } else if (!v["$r"]) { if (v.tp$name) { return new Sk.builtin.str("&lt;" + v.tp$name + " object>"); } else { return new Sk.builtin.str("&lt;unknown>"); } } else if (v.constructor === Sk.builtin.float_) { if (v.v === Infinity) { return new Sk.builtin.str("inf"); } else if (v.v === -Infinity) { return new Sk.builtin.str("-inf"); } else { return v["$r"](); } } else if (v.constructor === Sk.builtin.int_) { return v["$r"](); } else { return v["$r"](); } }; goog.exportSymbol("Sk.misceval.objectRepr", Sk.misceval.objectRepr); Sk.misceval.opAllowsEquality = function (op) { switch (op) { case "LtE": case "Eq": case "GtE": return true; } return false; }; goog.exportSymbol("Sk.misceval.opAllowsEquality", Sk.misceval.opAllowsEquality); Sk.misceval.isTrue = function (x) { var ret; if (x === true) { return true; } if (x === false) { return false; } if (x === null) { return false; } if (x.constructor === Sk.builtin.none) { return false; } if (x.constructor === Sk.builtin.NotImplemented) { return false; } if (x.constructor === Sk.builtin.bool) { return x.v; } if (typeof x === "number") { return x !== 0; } if (x instanceof Sk.builtin.lng) { return x.nb$nonzero(); } if (x.constructor === Sk.builtin.int_) { return x.v !== 0; } if (x.constructor === Sk.builtin.float_) { return x.v !== 0; } if (x["__nonzero__"]) { ret = Sk.misceval.callsim(x["__nonzero__"], x); if (!Sk.builtin.checkInt(ret)) { throw new Sk.builtin.TypeError("__nonzero__ should return an int"); } return Sk.builtin.asnum$(ret) !== 0; } if (x["__len__"]) { ret = Sk.misceval.callsim(x["__len__"], x); if (!Sk.builtin.checkInt(ret)) { throw new Sk.builtin.TypeError("__len__ should return an int"); } return Sk.builtin.asnum$(ret) !== 0; } if (x.mp$length) { return Sk.builtin.asnum$(x.mp$length()) !== 0; } if (x.sq$length) { return Sk.builtin.asnum$(x.sq$length()) !== 0; } return true; }; goog.exportSymbol("Sk.misceval.isTrue", Sk.misceval.isTrue); Sk.misceval.softspace_ = false; Sk.misceval.print_ = function (x) { // this was function print(x) not sure why... var isspace; var s; if (Sk.misceval.softspace_) { if (x !== "\n") { Sk.output(" "); } Sk.misceval.softspace_ = false; } s = new Sk.builtin.str(x); Sk.output(s.v); isspace = function (c) { return c === "\n" || c === "\t" || c === "\r"; }; if (s.v.length === 0 || !isspace(s.v[s.v.length - 1]) || s.v[s.v.length - 1] === " ") { Sk.misceval.softspace_ = true; } }; goog.exportSymbol("Sk.misceval.print_", Sk.misceval.print_); /** * @param {string} name * @param {Object=} other generally globals */ Sk.misceval.loadname = function (name, other) { var bi; var v = other[name]; if (v !== undefined) { return v; } bi = Sk.builtins[name]; if (bi !== undefined) { return bi; } name = name.replace("_$rw$", ""); name = name.replace("_$rn$", ""); throw new Sk.builtin.NameError("name '" + name + "' is not defined"); }; goog.exportSymbol("Sk.misceval.loadname", Sk.misceval.loadname); /** * * Notes on necessity for 'call()': * * Classes are callable in python to create an instance of the class. If * we're calling "C()" we cannot tell at the call site whether we're * calling a standard function, or instantiating a class. * * JS does not support user-level callables. So, we can't use the normal * prototype hierarchy to make the class inherit from a 'class' type * where the various tp$getattr, etc. methods would live. * * Instead, we must copy all the methods from the prototype of our class * type onto every instance of the class constructor function object. * That way, both "C()" and "C.tp$getattr(...)" can still work. This is * of course quite expensive. * * The alternative would be to indirect all calls (whether classes or * regular functions) through something like C.$call(...). In the case * of class construction, $call could then call the constructor after * munging arguments to pass them on. This would impose a penalty on * regular function calls unfortunately, as they would have to do the * same thing. * * Note that the same problem exists for function objects too (a "def" * creates a function object that also has properties). It just happens * that attributes on classes in python are much more useful and common * that the attributes on functions. * * Also note, that for full python compatibility we have to do the $call * method because any python object could have a __call__ method which * makes the python object callable too. So, unless we were to make * *all* objects simply (function(){...}) and use the dict to create * hierarchy, there would be no way to call that python user function. I * think I'm prepared to sacrifice __call__ support, or only support it * post-ECMA5 or something. * * Is using (function(){...}) as the only object type too crazy? * Probably. Better or worse than having two levels of function * invocation for every function call? * * For a class `C' with instance `inst' we have the following cases: * * 1. C.attr * * 2. C.staticmeth() * * 3. x = C.staticmeth; x() * * 4. inst = C() * * 5. inst.attr * * 6. inst.meth() * * 7. x = inst.meth; x() * * 8. inst(), where C defines a __call__ * * Because in general these are accomplished by a helper function * (tp$getattr/setattr/slice/ass_slice/etc.) it seems appropriate to add * a call that generally just calls through, but sometimes handles the * unusual cases. Once ECMA-5 is more broadly supported we can revisit * and hopefully optimize. * * @param {Object} func the thing to call * @param {Object=} kwdict **kwargs * @param {Object=} varargseq **args * @param {Object=} kws keyword args or undef * @param {...*} args stuff to pass it * * * TODO I think all the above is out of date. */ Sk.misceval.call = function (func, kwdict, varargseq, kws, args) { args = Array.prototype.slice.call(arguments, 4); // todo; possibly inline apply to avoid extra stack frame creation return Sk.misceval.apply(func, kwdict, varargseq, kws, args); }; goog.exportSymbol("Sk.misceval.call", Sk.misceval.call); /** * @param {?Object} suspensionHandlers * @param {Object} func the thing to call * @param {Object=} kwdict **kwargs * @param {Object=} varargseq **args * @param {Object=} kws keyword args or undef * @param {...*} args stuff to pass it * * * TODO I think all the above is out of date. */ Sk.misceval.callAsync = function (suspensionHandlers, func, kwdict, varargseq, kws, args) { args = Array.prototype.slice.call(arguments, 5); // todo; possibly inline apply to avoid extra stack frame creation return Sk.misceval.applyAsync(suspensionHandlers, func, kwdict, varargseq, kws, args); }; goog.exportSymbol("Sk.misceval.callAsync", Sk.misceval.callAsync); Sk.misceval.callOrSuspend = function (func, kwdict, varargseq, kws, args) { args = Array.prototype.slice.call(arguments, 4); // todo; possibly inline apply to avoid extra stack frame creation return Sk.misceval.applyOrSuspend(func, kwdict, varargseq, kws, args); }; goog.exportSymbol("Sk.misceval.callOrSuspend", Sk.misceval.callOrSuspend); /** * @param {Object} func the thing to call * @param {...*} args stuff to pass it */ Sk.misceval.callsim = function (func, args) { args = Array.prototype.slice.call(arguments, 1); return Sk.misceval.apply(func, undefined, undefined, undefined, args); }; goog.exportSymbol("Sk.misceval.callsim", Sk.misceval.callsim); /** * @param {?Object} suspensionHandlers any custom suspension handlers * @param {Object} func the thing to call * @param {...*} args stuff to pass it */ Sk.misceval.callsimAsync = function (suspensionHandlers, func, args) { args = Array.prototype.slice.call(arguments, 2); return Sk.misceval.applyAsync(suspensionHandlers, func, undefined, undefined, undefined, args); }; goog.exportSymbol("Sk.misceval.callsimAsync", Sk.misceval.callsimAsync); /** * @param {Object} func the thing to call * @param {...*} args stuff to pass it */ Sk.misceval.callsimOrSuspend = function (func, args) { args = Array.prototype.slice.call(arguments, 1); return Sk.misceval.applyOrSuspend(func, undefined, undefined, undefined, args); }; goog.exportSymbol("Sk.misceval.callsimOrSuspend", Sk.misceval.callsimOrSuspend); /** * Wrap Sk.misceval.applyOrSuspend, but throw an error if we suspend */ Sk.misceval.apply = function (func, kwdict, varargseq, kws, args) { var r = Sk.misceval.applyOrSuspend(func, kwdict, varargseq, kws, args); if (r instanceof Sk.misceval.Suspension) { return Sk.misceval.retryOptionalSuspensionOrThrow(r); } else { return r; } }; goog.exportSymbol("Sk.misceval.apply", Sk.misceval.apply); /** * Wraps anything that can return an Sk.misceval.Suspension, and returns a * JS Promise with the result. Also takes an object map of suspension handlers: * pass in {"suspType": function (susp) {} }, and your function will be called * with the Suspension object if susp.type=="suspType". The type "*" will match * all otherwise unhandled suspensions. * * A suspension handler should return a Promise yielding the return value of * r.resume() - ie, either the final return value of this call or another * Suspension. That is, the null suspension handler is: * * function handler(susp) { * return new Promise(function(resolve, reject) { * try { * resolve(susp.resume()); * } catch(e) { * reject(e); * } * }); * } * * Alternatively, a handler can return null to perform the default action for * that suspension type. * * (Note: do *not* call asyncToPromise() in a suspension handler; this will * create a new Promise object for each such suspension that occurs) * * asyncToPromise() returns a Promise that will be resolved with the final * return value, or rejected with an exception if one is thrown. * * @param{function()} suspendablefn returns either a result or a Suspension * @param{Object=} suspHandlers an object map of suspension handlers */ Sk.misceval.asyncToPromise = function(suspendablefn, suspHandlers) { return new Promise(function(resolve, reject) { try { var r = suspendablefn(); (function handleResponse (r) { try { // jsh*nt insists these be defined outside the loop var resume = function() { handleResponse(r.resume()); }; var resumeWithData = function resolved(x) { try { r.data["result"] = x; resume(); } catch(e) { reject(e); } }; var resumeWithError = function rejected(e) { try { r.data["error"] = e; resume(); } catch(ex) { reject(ex); } }; while (r instanceof Sk.misceval.Suspension) { var handler = suspHandlers &amp;&amp; (suspHandlers[r.data["type"]] || suspHandlers["*"]); if (handler) { var handlerPromise = handler(r); if (handlerPromise) { handlerPromise.then(handleResponse, reject); return; } } if (r.data["type"] == "Sk.promise") { r.data["promise"].then(resumeWithData, resumeWithError); return; } else if (r.data["type"] == "Sk.yield" &amp;&amp; typeof setTimeout === "function") { setTimeout(resume, 0); return; } else if (r.optional) { // Unhandled optional suspensions just get // resumed immediately, and we go around the loop again. r = r.resume(); } else { // Unhandled, non-optional suspension. throw new Sk.builtin.SuspensionError("Unhandled non-optional suspension of type '"+r.data["type"]+"'"); } } resolve(r); } catch(e) { reject(e); } })(r); } catch (e) { reject(e); } }); }; goog.exportSymbol("Sk.misceval.asyncToPromise", Sk.misceval.asyncToPromise); Sk.misceval.applyAsync = function (suspHandlers, func, kwdict, varargseq, kws, args) { return Sk.misceval.asyncToPromise(function() { return Sk.misceval.applyOrSuspend(func, kwdict, varargseq, kws, args); }, suspHandlers); }; goog.exportSymbol("Sk.misceval.applyAsync", Sk.misceval.applyAsync); /** * Chain together a set of functions, each of which might return a value or * an Sk.misceval.Suspension. Each function is called with the return value of * the preceding function, but does not see any suspensions. If a function suspends, * Sk.misceval.chain() returns a suspension that will resume the chain once an actual * return value is available. * * The idea is to allow a Promise-like chaining of possibly-suspending steps without * repeating boilerplate suspend-and-resume code. * * For example, imagine we call Sk.misceval.chain(x, f). * - If x is a value, we return f(x). * - If x is a suspension, we suspend. We will suspend and resume until we get a * return value, and then we will return f(&lt;resumed-value). * This can be expanded to an arbitrary number of functions * (eg Sk.misceval.chain(x, f, g), which is equivalent to chain(chain(x, f), g).) * * @param {*} initialValue * @param {...function(*)} chainedFns */ Sk.misceval.chain = function (initialValue, chainedFns) { var fs = arguments, i = 1; return (function nextStep(r) { while (i &lt; fs.length) { if (r instanceof Sk.misceval.Suspension) { return new Sk.misceval.Suspension(nextStep, r); } r = fs[i](r); i++; } return r; })(initialValue); }; goog.exportSymbol("Sk.misceval.chain", Sk.misceval.chain); /** * same as Sk.misceval.call except args is an actual array, rather than * varargs. */ Sk.misceval.applyOrSuspend = function (func, kwdict, varargseq, kws, args) { var fcall; var kwix; var numPosParams; var numNonOptParams; var it, i; if (func === null || func instanceof Sk.builtin.none) { throw new Sk.builtin.TypeError("'" + Sk.abstr.typeName(func) + "' object is not callable"); } else if (typeof func === "function") { // todo; i believe the only time this happens is the wrapper // function around generators (that creates the iterator). // should just make that a real function object and get rid // of this case. // alternatively, put it to more use, and perhaps use // descriptors to create builtin.func's in other places. // This actually happens for all builtin functions (in // builtin.js, for example) as they are javascript functions, // not Sk.builtin.func objects. if (func.sk$klass) { // klass wrapper around __init__ requires special handling return func.apply(null, [kwdict, varargseq, kws, args, true]); } if (varargseq) { for (it = varargseq.tp$iter(), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) { args.push(i); } } if (kwdict) { goog.asserts.fail("kwdict not implemented;"); } //goog.asserts.assert(((kws === undefined) || (kws.length === 0))); //print('kw args location: '+ kws + ' args ' + args.length) if (kws !== undefined &amp;&amp; kws.length > 0) { if (!func.co_varnames) { throw new Sk.builtin.ValueError("Keyword arguments are not supported by this function"); } //number of positionally placed optional parameters numNonOptParams = func.co_numargs - func.co_varnames.length; numPosParams = args.length - numNonOptParams; //add defaults args = args.concat(func.$defaults.slice(numPosParams)); for (i = 0; i &lt; kws.length; i = i + 2) { kwix = func.co_varnames.indexOf(kws[i]); if (kwix === -1) { throw new Sk.builtin.TypeError("'" + kws[i] + "' is an invalid keyword argument for this function"); } if (kwix &lt; numPosParams) { throw new Sk.builtin.TypeError("Argument given by name ('" + kws[i] + "') and position (" + (kwix + numNonOptParams + 1) + ")"); } args[kwix + numNonOptParams] = kws[i + 1]; } } //append kw args to args, filling in the default value where none is provided. return func.apply(null, args); } else { fcall = func.tp$call; if (fcall !== undefined) { if (varargseq) { for (it = varargseq.tp$iter(), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) { args.push(i); } } if (kwdict) { goog.asserts.fail("kwdict not implemented;"); } return fcall.call(func, args, kws, kwdict); } // todo; can we push this into a tp$call somewhere so there's // not redundant checks everywhere for all of these __x__ ones? fcall = func.__call__; if (fcall !== undefined) { // func is actually the object here because we got __call__ // from it. todo; should probably use descr_get here args.unshift(func); return Sk.misceval.apply(fcall, kws, args, kwdict, varargseq); } throw new Sk.builtin.TypeError("'" + Sk.abstr.typeName(func) + "' object is not callable"); } }; goog.exportSymbol("Sk.misceval.applyOrSuspend", Sk.misceval.applyOrSuspend); /** * Constructs a class object given a code object representing the body * of the class, the name of the class, and the list of bases. * * There are no "old-style" classes in Skulpt, so use the user-specified * metaclass (todo;) if there is one, the type of the 0th base class if * there's bases, or otherwise the 'type' type. * * The func code object is passed a (js) dict for its locals which it * stores everything into. * * The metaclass is then called as metaclass(name, bases, locals) and * should return a newly constructed class object. * */ Sk.misceval.buildClass = function (globals, func, name, bases) { // todo; metaclass var klass; var meta = Sk.builtin.type; var locals = {}; // init the dict for the class func(globals, locals, []); // ToDo: check if func contains the __meta__ attribute // or if the bases contain __meta__ // new Syntax would be different // file's __name__ is class's __module__ locals.__module__ = globals["__name__"]; var _name = new Sk.builtin.str(name); var _bases = new Sk.builtin.tuple(bases); var _locals = []; var key; // build array for python dict for (key in locals) { if (!locals.hasOwnProperty(key)) { //The current property key not a direct property of p continue; } _locals.push(new Sk.builtin.str(key)); // push key _locals.push(locals[key]); // push associated value } _locals = new Sk.builtin.dict(_locals); klass = Sk.misceval.callsim(meta, _name, _bases, _locals); return klass; }; goog.exportSymbol("Sk.misceval.buildClass", Sk.misceval.buildClass); </code></pre> </article> </section> </div> <nav> <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> </nav> <br class="clear"> <footer> 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) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>