Skip to content

Commit 802b7ba

Browse files
Merge branch 'TurboWarp:develop' into develop
2 parents 610aba2 + 11eec66 commit 802b7ba

16 files changed

+598
-42
lines changed

.github/workflows/deploy.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Deploy playground
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [develop]
7+
8+
concurrency:
9+
group: "deploy"
10+
cancel-in-progress: true
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
- name: Install Node.js
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: 20
21+
cache: npm
22+
- name: Install dependencies
23+
run: npm ci
24+
- name: Build playground
25+
run: npm run build
26+
- name: Build docs
27+
run: npm run docs
28+
# We expect to see syntax errors from the old jsdoc cli not understanding some of our syntax
29+
# It will still generate what it can, so it's safe to ignore the error
30+
continue-on-error: true
31+
- name: Upload artifact
32+
uses: actions/upload-pages-artifact@v3
33+
with:
34+
path: ./playground/
35+
36+
deploy:
37+
environment:
38+
name: github-pages
39+
url: ${{ steps.deployment.outputs.page_url }}
40+
permissions:
41+
pages: write
42+
id-token: write
43+
runs-on: ubuntu-latest
44+
needs: build
45+
steps:
46+
- name: Deploy to GitHub Pages
47+
id: deployment
48+
uses: actions/deploy-pages@v4

.github/workflows/node.js.yml

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
name: Node.js CI
1+
name: CI
22

33
on:
44
push:
55
pull_request:
66

77
jobs:
88
build:
9-
109
runs-on: ubuntu-latest
11-
1210
steps:
13-
- uses: actions/checkout@v4
14-
- name: Install Node.js
15-
uses: actions/setup-node@v4
16-
with:
17-
node-version: 20.x
18-
- run: npm ci
19-
- run: npm run lint
20-
- run: npm run build
21-
- run: npm run test
11+
- uses: actions/checkout@v4
12+
- name: Install Node.js
13+
uses: actions/setup-node@v4
14+
with:
15+
node-version: 20
16+
cache: npm
17+
- run: npm ci
18+
- run: npm run lint
19+
- run: npm run build
20+
- run: npm run test

LICENSE

Lines changed: 368 additions & 8 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,27 @@ For more technical information, read the code in src/compiler.
2424

2525
This section was too out of date to be useful. We hope to re-add it as some point.
2626

27+
## License
28+
29+
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
30+
31+
This program is based on [scratchfoundation/scratch-vm](https://github.com/scratchfoundation/scratch-vm), which is under this license:
32+
33+
```
34+
Copyright (c) 2016, Massachusetts Institute of Technology
35+
All rights reserved.
36+
37+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
38+
39+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
40+
41+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
42+
43+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
44+
45+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46+
```
47+
2748
<!--
2849
2950
## scratch-vm

package-lock.json

Lines changed: 16 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "2.1.46",
44
"description": "Virtual Machine for Scratch 3.0",
55
"author": "Massachusetts Institute of Technology",
6-
"license": "BSD-3-Clause",
6+
"license": "MPL-2.0",
77
"homepage": "https://github.com/scratchfoundation/scratch-vm#readme",
88
"repository": {
99
"type": "git",
@@ -12,9 +12,9 @@
1212
"main": "./src/index.js",
1313
"browser": "./src/index.js",
1414
"scripts": {
15-
"build": "npm run docs && webpack --progress --colors --bail",
15+
"build": "webpack --progress --colors --bail",
1616
"coverage": "tap ./test/{unit,integration}/*.js --coverage --coverage-report=lcov",
17-
"docs": "exit 0 || jsdoc -c .jsdoc.json",
17+
"docs": "jsdoc -c .jsdoc.json",
1818
"i18n:src": "mkdirp translations/core && format-message extract --out-file translations/core/en.json src/extensions/**/index.js",
1919
"i18n:push": "tx-push-src scratch-editor extensions translations/core/en.json",
2020
"lint": "eslint .",
@@ -35,7 +35,7 @@
3535
},
3636
"dependencies": {
3737
"@turbowarp/json": "^0.1.2",
38-
"@turbowarp/nanolog": "^0.1.0",
38+
"@turbowarp/nanolog": "^0.2.0",
3939
"@vernier/godirect": "1.5.0",
4040
"arraybuffer-loader": "^1.0.6",
4141
"atob": "2.1.2",

src/engine/thread.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,12 +316,22 @@ class Thread {
316316
let blockID = this.peekStack();
317317
while (blockID !== null) {
318318
const block = this.target.blocks.getBlock(blockID);
319-
if (
320-
(typeof block !== 'undefined' && block.opcode === 'procedures_call') ||
321-
this.peekStackFrame().waitingReporter
322-
) {
319+
320+
// Reporter form of procedures_call
321+
if (this.peekStackFrame().waitingReporter) {
323322
break;
324323
}
324+
325+
// Command form of procedures_call
326+
if (typeof block !== 'undefined' && block.opcode === 'procedures_call') {
327+
// By definition, if we get here, the procedure is done, so skip ahead so
328+
// the arguments won't be re-evaluated and then discarded as frozen state
329+
// about which arguments have been evaluated is lost.
330+
// This fixes https://github.com/TurboWarp/scratch-vm/issues/201
331+
this.goToNextBlock();
332+
break;
333+
}
334+
325335
this.popStack();
326336
blockID = this.peekStack();
327337
}

src/extension-support/tw-unsandboxed-extension-runner.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ const setupUnsandboxedExtensionAPI = vm => new Promise(resolve => {
131131

132132
global.Scratch = Scratch;
133133
global.ScratchExtensions = createScratchX(Scratch);
134+
135+
vm.emit('CREATE_UNSANDBOXED_EXTENSION_API', Scratch);
134136
});
135137

136138
/**

src/extensions/scratch3_wedo2/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,6 @@ class WeDo2Motor {
269269
* Turn this motor on indefinitely.
270270
*/
271271
turnOn () {
272-
if (this._power === 0) return;
273-
274272
const cmd = this._parent.generateOutputCommand(
275273
this._index + 1,
276274
WeDo2Command.MOTOR_POWER,

src/util/base64-util.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,8 @@ class Base64Util {
2424
* @return {string} - the base64 encoded string.
2525
*/
2626
static uint8ArrayToBase64 (array) {
27-
if (Array.isArray(array)) {
28-
array = new Uint8Array(array);
29-
}
3027
let binary = '';
31-
const len = array.byteLength;
28+
const len = array.length;
3229
for (let i = 0; i < len; i++) {
3330
binary += String.fromCharCode(array[i]);
3431
}
Binary file not shown.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// TW Snapshot
2+
// Input SHA-256: fd981742e0e4299bad5a89349635d3a7d0467d8163ae77ba4bafe43c97849bae
3+
4+
// Sprite1 script
5+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
6+
const b0 = runtime.getOpcodeFunction("looks_say");
7+
return function* genXYZ () {
8+
yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "d", null);
9+
thread.procedures["Zfoo %s"]("");
10+
yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null);
11+
retire(); return;
12+
}; })
13+
14+
// Sprite1 foo %s
15+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
16+
return function funXYZ_foo_ (p0) {
17+
return "";
18+
return "";
19+
}; })
20+
21+
// Sprite1 no op
22+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
23+
return function funXYZ_no_op () {
24+
return "";
25+
}; })
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// TW Snapshot
2+
// Input SHA-256: fd981742e0e4299bad5a89349635d3a7d0467d8163ae77ba4bafe43c97849bae
3+
4+
// Sprite1 script
5+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
6+
const b0 = runtime.getOpcodeFunction("looks_say");
7+
return function* genXYZ () {
8+
yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "d", null);
9+
thread.procedures["Zfoo %s"]("");
10+
yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null);
11+
retire(); return;
12+
}; })
13+
14+
// Sprite1 foo %s
15+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
16+
return function funXYZ_foo_ (p0) {
17+
return "";
18+
return "";
19+
}; })
20+
21+
// Sprite1 no op
22+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
23+
return function funXYZ_no_op () {
24+
return "";
25+
}; })

test/unit/engine_thread.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ test('stopThisScript', t => {
223223
th.pushStack('arbitraryString');
224224
th.pushStack('secondString');
225225
th.stopThisScript();
226-
t.strictEquals(th.peekStack(), 'secondString');
226+
t.strictEquals(th.peekStack(), null);
227227

228228
t.end();
229229
});

test/unit/tw_stop_this_script.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
const {test} = require('tap');
2+
const Thread = require('../../src/engine/thread');
3+
const Runtime = require('../../src/engine/runtime');
4+
const Target = require('../../src/engine/target');
5+
6+
test('stopThisScript procedures_call reporter form', t => {
7+
const rt = new Runtime();
8+
const target = new Target(rt, null);
9+
10+
target.blocks.createBlock({
11+
id: 'reporterCall',
12+
opcode: 'procedures_call',
13+
inputs: {},
14+
fields: {},
15+
mutation: {
16+
return: '1'
17+
},
18+
shadow: false,
19+
topLevel: true,
20+
parent: null,
21+
next: 'afterReporterCall'
22+
});
23+
target.blocks.createBlock({
24+
id: 'afterReporterCall',
25+
opcode: 'motion_ifonedgebounce',
26+
inputs: {},
27+
fields: {},
28+
mutation: null,
29+
shadow: false,
30+
topLevel: false,
31+
parent: null,
32+
next: null
33+
});
34+
35+
const thread = new Thread('reporterCall');
36+
thread.target = target;
37+
38+
// pretend to run reporterCall
39+
thread.pushStack('reporterCall');
40+
thread.peekStackFrame().waitingReporter = true;
41+
42+
// pretend to run scripts inside of the procedure
43+
thread.pushStack('fakeBlock');
44+
45+
// stopping or returning should always return to reporterCall, not the block after
46+
thread.stopThisScript();
47+
t.same(thread.stack, [
48+
'reporterCall'
49+
]);
50+
51+
t.end();
52+
});

test/unit/tw_unsandboxed_extensions.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,3 +417,13 @@ test('canEmbed', async t => {
417417

418418
t.end();
419419
});
420+
421+
test('CREATE_UNSANDBOXED_EXTENSION_API', t => {
422+
const vm = new VirtualMachine();
423+
vm.on('CREATE_UNSANDBOXED_EXTENSION_API', api => {
424+
api.extraStuff = 'aaaa';
425+
});
426+
UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm);
427+
t.equal(global.Scratch.extraStuff, 'aaaa');
428+
t.end();
429+
});

0 commit comments

Comments
 (0)