Skip to content

Commit

Permalink
Merge pull request #185 from FurryR/develop
Browse files Browse the repository at this point in the history
Fix compiler's waitPromise implementation
  • Loading branch information
GarboMuffin authored Jan 21, 2024
2 parents 03cd07f + b3e621c commit 08eb399
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 5 deletions.
11 changes: 6 additions & 5 deletions src/compiler/jsexecute.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,20 @@ const waitPromise = function*(promise) {
const thread = globalState.thread;
let returnValue;
// enter STATUS_PROMISE_WAIT and yield
// this will stop script execution until the promise handlers reset the thread status
// because promise handlers might execute immediately, configure thread.status here
thread.status = 1; // STATUS_PROMISE_WAIT
promise
.then(value => {
returnValue = value;
thread.status = 0; // STATUS_RUNNING
})
.catch(error => {
}, error => {
thread.status = 0; // STATUS_RUNNING
globalState.log.warn('Promise rejected in compiled script:', error);
});
// enter STATUS_PROMISE_WAIT and yield
// this will stop script execution until the promise handlers reset the thread status
thread.status = 1; // STATUS_PROMISE_WAIT
yield;
return returnValue;
Expand Down
Binary file added test/fixtures/tw-block-returning-promise-like.sb3
Binary file not shown.
65 changes: 65 additions & 0 deletions test/integration/tw_block_returning_promise_like.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const {test} = require('tap');
const fs = require('fs');
const path = require('path');
const VirtualMachine = require('../../src/virtual-machine');
const Scratch = require('../../src/extension-support/tw-extension-api-common');

// based on https://github.com/TurboWarp/scratch-vm/issues/184

class TestExtension {
getInfo () {
return {
id: 'testextension',
name: 'test',
blocks: [
{
opcode: 'test',
blockType: Scratch.BlockType.COMMAND,
text: 'test block'
}
]
};
}
test () {
// returns a PromiseLike that calls handler immediately.
const promise = {
then (callbackFn) {
callbackFn();
return promise;
}
// intentionally omit catch() as that is not part of PromiseLike
};
return promise;
}
}

const fixture = fs.readFileSync(path.join(__dirname, '../fixtures/tw-block-returning-promise-like.sb3'));

for (const compilerEnabled of [false, true]) {
test(`handles blocks that return a promise-like object - ${compilerEnabled ? 'compiled' : 'interpreted'}`, t => {
const vm = new VirtualMachine();
vm.extensionManager.addBuiltinExtension('testextension', TestExtension);

vm.setCompilerOptions({
enabled: compilerEnabled
});
t.equal(vm.runtime.compilerOptions.enabled, compilerEnabled, 'sanity check');

vm.loadProject(fixture).then(() => {
let ended = 0;
vm.runtime.on('SAY', (target, type, text) => {
if (text === 'end') {
ended++;
} else {
t.fail('said something unknown');
}
});

vm.greenFlag();
vm.runtime._step();

t.equal(ended, 1, 'script ran once immediately');
t.end();
});
});
}

0 comments on commit 08eb399

Please sign in to comment.