From 46b9766b71366028d1235f5a01695ac8d35a17b5 Mon Sep 17 00:00:00 2001 From: FurryR Date: Wed, 17 Jan 2024 18:50:21 +0800 Subject: [PATCH 1/3] Fix compiler's waitPromise implementation `waitPromise()` now finally allows PromiseLike --- src/compiler/jsexecute.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/compiler/jsexecute.js b/src/compiler/jsexecute.js index ec7d683404e..0ab448d4a10 100644 --- a/src/compiler/jsexecute.js +++ b/src/compiler/jsexecute.js @@ -109,6 +109,11 @@ 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; @@ -119,9 +124,6 @@ const waitPromise = function*(promise) { 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; From 72cdbc26b3dadbc9609456de7325f05d6c6c3e32 Mon Sep 17 00:00:00 2001 From: FurryR Date: Wed, 17 Jan 2024 19:22:57 +0800 Subject: [PATCH 2/3] Avoid using `promise.catch` in waitPromise `promise.catch` is not included in PromiseLike --- src/compiler/jsexecute.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/jsexecute.js b/src/compiler/jsexecute.js index 0ab448d4a10..247b3e2c606 100644 --- a/src/compiler/jsexecute.js +++ b/src/compiler/jsexecute.js @@ -118,8 +118,7 @@ const waitPromise = function*(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); }); From b3e621c61bfeb9eff25b77948f7a16ad7c731651 Mon Sep 17 00:00:00 2001 From: Muffin Date: Sun, 21 Jan 2024 13:42:41 -0600 Subject: [PATCH 3/3] Add test for promise-like blocks --- .../tw-block-returning-promise-like.sb3 | Bin 0 -> 2309 bytes .../tw_block_returning_promise_like.js | 65 ++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 test/fixtures/tw-block-returning-promise-like.sb3 create mode 100644 test/integration/tw_block_returning_promise_like.js diff --git a/test/fixtures/tw-block-returning-promise-like.sb3 b/test/fixtures/tw-block-returning-promise-like.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..d7c232ca21ab440b01d3d9cf9b8df4702dfa886b GIT binary patch literal 2309 zcma);c{CJy8^=eeFpWLaB~*4{XoexzUY4@tKg z!eqNsDaIN?*VbV0T3+}4=ib{n?>YB*&U1d}{LcA4=Y0S8e$Hcy;N;>30074Us63cc zR>1M-LQVjnn-2g09{%1A#Q9=S!K%JNIR83_aNJi-;DOSy6NWC*^jq(I7`rtaJ7AFa z9crn#rpP5zgas*C=I}6M+h$FFak05(JFS`8+)_LdKH>F(zfNcbWmPZk z`l|W7eX8r&xm+jCSSn}1FM6-M{i`h(cld5NB{N?KL>WdOu~V2A3gN!Mp(plf=8Tc( zn5VzPkA7S|jx z4XlWR=A5jhb3AHyyag?%IZ4^@K%NfeUnKZ+H9d|91>xT)ELMp5yjj-d)s6W8Q_6Fh z#cY*#seGqJ?_2h#NV~Y}bV%1xyK#xeHE(+5GP$FWLg>f+Vs-5gGAqixwKzTfwID4$ z1G9EzS`_=rN7dj!kwmutsXr*tbswT%jIx z=c`9ufE#`^4%nCeg|-kDvCdN5H2mDc`}(OJUufiB{WZ!RXQfjgb+72%+f5Gsob-VV zW@^cK-v-M{v*oEW+B3%L5?zK*fXGR8>mI}EiM&GGLMzlTVD~+M7Vv$W$44hmDV1ck z5laf)TKO=sAy@Qr2E$C~bbew@7k+7RHwF2JqYNg!OsY-j=w)w>;w-KDjvAlH>4tqT_nyomU1k1+<&0;$N2$bAkJ&>t-nOQ~n{fP59X-c(%bgaQj&V@0#TCu@fw>+ZqKh&7g3tMcg%7+l#@`Vdoqxta>g^ ze3-*Qn8d0v>X9`H{PlXgXe`XXs+RFFH+b#(nMYMcu~u{j+%!Jh+b7OUaV>aG4@gp? z+ufp?mh==qD>#U)Cf|JBT+SE0*$H-KO>^c-O5z$rrmTtFM@_Z%x%9NB%LqIkmSRh6 z1Of0*Q*CVN1;`9$ffPgt=%xezwIa7Hm=aDJ_i zk~5MQgb?^;RFhu#aJ-0$xLOaiamTSv86n_Tycl`+{MKI zVNVVNNOb+i4k=USEmYE|ZSZekM|<~z9nTu4_2-YL+JtmLs2Pcj?PpQ~Zw@j9);(9S zGa~^8t4wIklE7yv>rF^hutJHtvE=@)^n!RsX!0HPEF-3e6c0T}Fp?RQ?`X`ZJm(=2(3H`ttp*k>vzJhbZ zrT1wSHzSNw`-ZG#o`h_&2ME7D+}F}N7;0>9_GGu-t!JE~uo(CD8FBJcP9%k@!S~4ALCDK7h=L#t+{1$ zP5tDmfM%kKt=L>p_wrSwj5%)8V$DR85cfYWM3qz=dyaU-R7}|!HXExL|{e| zuezm(3iK)^lIE^0=7B+elCSfYS?Nw$5i2U^)XuTvji)}!I-_X+!(!Std5Bi}MszEp zm8J8aiVI!78M9i>3U?Ea?!=coRlZ&e6#uPM^N8Sh{>aO-9rrfCD<;Dl$mUN<(ppe1Tsw$ar`)T66JIQ%QDbrbA{@)09G% z2Gv|i_I~k!n97&X%M@>$PW`fQ3GXjS#g5!t?;QyZlhw1xU{ry1rS@|=9{*v_` oX87L#>F13<=l`#b1zZ5YzoCIGg8S&7D$c_mKYRrbNdf@;7f7-a1^@s6 literal 0 HcmV?d00001 diff --git a/test/integration/tw_block_returning_promise_like.js b/test/integration/tw_block_returning_promise_like.js new file mode 100644 index 00000000000..a0e95e8c3e7 --- /dev/null +++ b/test/integration/tw_block_returning_promise_like.js @@ -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(); + }); + }); +}