123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197 |
- <!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: <copied down from innermost level>,
- optional: <if true, can be resumed immediately (eg debug stops)>,
- child: <Suspension, or null if we are the innermost level>,
- $blk: <>, $loc: <>, $gbl: <>, $exc: <>, $err: <>, [$cell: <>],
- }
- */
- /**
- *
- * 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 && child !== undefined) {
- this.resume = function() { return resume(child.resume()); };
- }
- this.child = child;
- this.optional = child !== undefined && child.optional;
- if (data === undefined && 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 && Sk.misceval.isIndex(v) && 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 && Sk.misceval.isIndex(v) && 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) && (v !== undefined), "passed null or undefined parameter to Sk.misceval.richCompareBool");
- goog.asserts.assert((w !== null) && (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) &&
- (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 && 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 && 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 < list < str < tuple
- if (v_seq_type !== -1 && w_seq_type !== -1) {
- switch (op) {
- case "Lt":
- return v_seq_type < w_seq_type;
- case "LtE":
- return v_seq_type <= 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_ && w instanceof Sk.builtin.int_) {
- return v.numberCompare(w) === 0;
- } else if (v instanceof Sk.builtin.float_ && w instanceof Sk.builtin.float_) {
- return v.numberCompare(w) === 0;
- } else if (v instanceof Sk.builtin.lng && w instanceof Sk.builtin.lng) {
- return v.longCompare(w) === 0;
- }
- return v === w;
- }
- if (op === "IsNot") {
- if (v instanceof Sk.builtin.int_ && w instanceof Sk.builtin.int_) {
- return v.numberCompare(w) !== 0;
- } else if (v instanceof Sk.builtin.float_ && w instanceof Sk.builtin.float_) {
- return v.numberCompare(w) !== 0;
- }else if (v instanceof Sk.builtin.lng && 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 && (ret = v.tp$richcompare(w, op)) !== undefined) {
- if (ret != Sk.builtin.NotImplemented.NotImplemented$) {
- return Sk.misceval.isTrue(ret);
- }
- }
- if (w.tp$richcompare && (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 && !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 && !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 < 0;
- } else if (op === "Gt") {
- return ret > 0;
- } else if (op === "LtE") {
- return ret <= 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 < 0;
- } else if (op === "LtE") {
- return ret >= 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");
- }
- }
- // handle special cases for comparing None with None or Bool with Bool
- if (((v instanceof Sk.builtin.none) && (w instanceof Sk.builtin.none)) ||
- ((v instanceof Sk.builtin.bool) && (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 < w.v;
- }
- if (op === "LtE") {
- return v.v <= w.v;
- }
- }
- // handle equality comparisons for any remaining objects
- if (op === "Eq") {
- if ((v instanceof Sk.builtin.str) && (w instanceof Sk.builtin.str)) {
- return v.v === w.v;
- }
- return v === w;
- }
- if (op === "NotEq") {
- if ((v instanceof Sk.builtin.str) && (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("<" + v.tp$name + " object>");
- } else {
- return new Sk.builtin.str("<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 && (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" && 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(<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 < 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 && 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 < 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 < 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>
|