Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

suspension aware __bool__ #15

Open
wants to merge 3 commits into
base: anvil-branch/master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions src/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,12 @@ Compiler.prototype.outputInterruptTest = function () { // Added by RNL
return output;
};

Compiler.prototype._jumpfalse = function (test, block) {
var cond = this._gr("jfalse", "(", test, "===false||!Sk.misceval.isTrue(", test, "))");
out("if(", cond, "){/*test failed */$blk=", block, ";continue;}");
Compiler.prototype._jumpfalse = function (test, block, canSuspend) {
out("$ret=Sk.misceval.isTrue(", test, (canSuspend ? ",true" : "")+ ");");
if (canSuspend) {
this._checkSuspension(null, "$ret !== true && $ret !== false");
}
out("if(!$ret){/*test failed */$blk=", block, ";continue;}");
};

Compiler.prototype._jumpundef = function (test, block) {
Expand All @@ -264,8 +267,9 @@ Compiler.prototype._jump = function (block) {
/**
* @param {Object=} e Object with keys 'lineno' and 'col_offset'
*/
Compiler.prototype._checkSuspension = function(e) {
Compiler.prototype._checkSuspension = function(e, suspCheck) {
var retblk;
suspCheck = suspCheck ? suspCheck + " && " : "";
if (this.u.canSuspend) {

retblk = this.newBlock("function return or resume suspension");
Expand All @@ -274,13 +278,13 @@ Compiler.prototype._checkSuspension = function(e) {

e = e || {lineno: "$currLineNo", col_offset: "$currColNo"};

out ("if ($ret && $ret.$isSuspension) { return $saveSuspension($ret,'"+this.filename+"',"+e.lineno+","+e.col_offset+"); }");
out ("if (" + suspCheck + "$ret !== undefined && $ret !== null && $ret.$isSuspension) { return $saveSuspension($ret,'"+this.filename+"',"+e.lineno+","+e.col_offset+"); }");

this.u.doesSuspend = true;
this.u.tempsToSave = this.u.tempsToSave.concat(this.u.localtemps);

} else {
out ("if ($ret && $ret.$isSuspension) { $ret = Sk.misceval.retryOptionalSuspensionOrThrow($ret); }");
out ("if (" + suspCheck + "$ret !== undefined && $ret !== null && $ret.$isSuspension) { $ret = Sk.misceval.retryOptionalSuspensionOrThrow($ret); }");
}
};
Compiler.prototype.cunpackstarstoarray = function(elts, permitEndOnly) {
Expand Down Expand Up @@ -510,7 +514,7 @@ Compiler.prototype.ccompgen = function (type, tmpname, generators, genIndex, val
n = l.ifs ? l.ifs.length : 0;
for (i = 0; i < n; ++i) {
ifres = this.vexpr(l.ifs[i]);
this._jumpfalse(ifres, start);
this._jumpfalse(ifres, start, true);
}

if (++genIndex < generators.length) {
Expand Down Expand Up @@ -570,10 +574,12 @@ Compiler.prototype.ccompare = function (e) {

for (i = 0; i < n; ++i) {
rhs = this.vexpr(e.comparators[i]);
out("$ret = Sk.builtin.bool(Sk.misceval.richCompareBool(", cur, ",", rhs, ",'", e.ops[i].prototype._astname, "', true));");
out("$ret = Sk.misceval.richCompareBool(", cur, ",", rhs, ",'", e.ops[i].prototype._astname, "', true);");
this._checkSuspension(e);
out(fres, "=$ret;");
this._jumpfalse("$ret", done);
out(fres, "=Sk.builtin.bool($ret);");
if (i < n - 1) {
this._jumpfalse("$ret", done, false);
}
cur = rhs;
}
this._jump(done);
Expand Down Expand Up @@ -1268,14 +1274,14 @@ Compiler.prototype.cif = function (s) {
test = this.vexpr(s.test);

if (s.orelse && s.orelse.length > 0) {
this._jumpfalse(test, next);
this._jumpfalse(test, next, true);
this.vseqstmt(s.body);
this._jump(end);

this.setBlock(next);
this.vseqstmt(s.orelse);
} else {
this._jumpfalse(test, end);
this._jumpfalse(test, end, true);
this.vseqstmt(s.body);
}
this._jump(end);
Expand Down Expand Up @@ -1304,7 +1310,7 @@ Compiler.prototype.cwhile = function (s) {
body = this.newBlock("while body");

this.annotateSource(s);
this._jumpfalse(this.vexpr(s.test), orelse ? orelse : next);
this._jumpfalse(this.vexpr(s.test), orelse ? orelse : next, true);
this._jump(body);

this.pushBreakBlock(next);
Expand Down Expand Up @@ -2199,7 +2205,7 @@ Compiler.prototype.cifexp = function (e) {
var ret = this._gr("res", "null");

var test = this.vexpr(e.test);
this._jumpfalse(test, next);
this._jumpfalse(test, next, true);

out(ret, "=", this.vexpr(e.body), ";");
this._jump(end);
Expand Down
6 changes: 3 additions & 3 deletions src/misceval.js
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ Sk.exportSymbol("Sk.misceval.opAllowsEquality", Sk.misceval.opAllowsEquality);
* @returns {boolean}
* @param {*} x
*/
Sk.misceval.isTrue = function (x) {
Sk.misceval.isTrue = function (x, canSuspend) {
if (x === true || x === Sk.builtin.bool.true$) {
return true;
}
Expand All @@ -626,11 +626,11 @@ Sk.misceval.isTrue = function (x) {
return false;
}
if (x.nb$bool) {
return x.nb$bool(); // the slot wrapper takes care of converting to js Boolean
return x.nb$bool(canSuspend); // the slot wrapper takes care of converting to js Boolean
}
if (x.sq$length) {
// the slot wrapper takes care of the error message and converting to js int
return x.sq$length() !== 0;
return Sk.misceval.chain(x.sq$length(canSuspend), (r) => r !== 0);
}
return Boolean(x);
};
Expand Down
53 changes: 18 additions & 35 deletions src/slotdefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,25 +135,28 @@ function slotFuncNoArgs(dunderFunc) {
*/
function slotFuncNoArgsWithCheck(dunderName, checkFunc, checkMsg, f) {
return function (dunderFunc) {
return function () {
return function slotfunc(canSuspend) {
const func = dunderFunc.tp$descr_get ? dunderFunc.tp$descr_get(this) : dunderFunc;
let res = Sk.misceval.callsimArray(func, []);
if (!checkFunc(res)) {
throw new Sk.builtin.TypeError(dunderName + " should return " + checkMsg + " (returned " + Sk.abstr.typeName(res) + ")");
}
// f is might be a function that changes the result to a js object like for nb$bool which returns a Boolean
if (f !== undefined) {
return f(res);
}
return res;
const ret = Sk.misceval.chain(Sk.misceval.callsimOrSuspendArray(func, []), (res) => {
if (checkFunc && !checkFunc(res)) {
throw new Sk.builtin.TypeError(dunderName + " should return " + checkMsg + " (returned " + Sk.abstr.typeName(res) + ")");
}
// f might be a function that changes the result to a js object like for nb$bool which returns a Boolean
if (f !== undefined) {
return f(res);
}
return res;
});
return canSuspend ? ret : Sk.misceval.retryOptionalSuspensionOrThrow(ret);
};
};
}

function slotFuncOneArg(dunderFunc) {
return function (value) {
return function (value, canSuspend) {
const func = dunderFunc.tp$descr_get ? dunderFunc.tp$descr_get(this) : dunderFunc;
return Sk.misceval.callsimArray(func, [value]);
const ret = Sk.misceval.callsimOrSuspendArray(func, [value]);
return canSuspend ? ret : Sk.misceval.retryOptionalSuspensionOrThrow(ret);
};
}

Expand Down Expand Up @@ -846,21 +849,7 @@ slots.__next__ = {
slots.__len__ = {
$name: "__len__",
$slot_name: "sq$length",
$slot_func: function (dunderFunc) {
return function sq$length(canSuspend) {
let res;
const func = dunderFunc.tp$descr_get ? dunderFunc.tp$descr_get(this) : dunderFunc;
if (canSuspend) {
res = Sk.misceval.callsimOrSuspendArray(func, []);
return Sk.misceval.chain(res, (r) => {
return Sk.misceval.asIndexOrThrow(r);
});
} else {
res = Sk.misceval.callsimArray(func, []);
return Sk.misceval.asIndexOrThrow(res);
}
};
},
$slot_func: slotFuncNoArgsWithCheck(null, null, null, (r) => Sk.misceval.asIndexOrThrow(r)), // asIndexOrThrow does the checks and conversion
$wrapper: wrapperCallBack(wrapperCallNoArgs, (res) => new Sk.builtin.int_(res)),
$flags: { NoArgs: true },
$textsig: "($self, /)",
Expand All @@ -886,7 +875,7 @@ slots.__contains__ = {
const func = dunderFunc.tp$descr_get ? dunderFunc.tp$descr_get(this) : dunderFunc;
let res = Sk.misceval.callsimOrSuspendArray(func, [key]);
res = Sk.misceval.chain(res, (r) => Sk.misceval.isTrue(r));
if (res.$isSuspension) {
if (res !== true && res !== false && res.$isSuspension) {
return canSuspend ? res : Sk.misceval.retryOptionalSuspensionOrThrow(res);
}
return res;
Expand All @@ -912,13 +901,7 @@ slots.__contains__ = {
slots.__getitem__ = {
$name: "__getitem__",
$slot_name: "mp$subscript",
$slot_func: function (dunderFunc) {
return function mp$subscript(key, canSuspend) {
const func = dunderFunc.tp$descr_get ? dunderFunc.tp$descr_get(this) : dunderFunc;
const ret = Sk.misceval.callsimOrSuspendArray(func, [key]);
return canSuspend ? ret : Sk.misceval.retryOptionalSuspensionOrThrow(ret);
};
},
$slot_func: slotFuncOneArg,
$wrapper: wrapperCallOneArg,
$textsig: "($self, key, /)",
$flags: { OneArg: true },
Expand Down