diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index f20a47ea4f1..416f1c3e060 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -1,6 +1,7 @@ // @ts-check const {StackOpcode, InputOpcode, InputType} = require('./enums.js'); +const log = require('../util/log'); // These imports are used by jsdoc comments but eslint doesn't know that /* eslint-disable no-unused-vars */ @@ -16,7 +17,7 @@ const { class TypeState { constructor () { /** @type {Object.}*/ - this.variables = {}; + this.variables = Object.create(null); } /** @@ -30,7 +31,7 @@ class TypeState { break; } } - this.variables = {}; + this.variables = Object.create(null); return modified; } @@ -93,7 +94,7 @@ class TypeState { after (other) { return this.mutate(other, varId => { const otherType = other.variables[varId]; - if (otherType !== 0) return otherType; + if (otherType) return otherType; return this.variables[varId] ?? InputType.ANY; }); } @@ -541,18 +542,19 @@ class IROptimizer { state = state.clone(); } - modified = this.analyzeInputs(inputs, state) || modified; - switch (stackBlock.opcode) { case StackOpcode.VAR_SET: + modified = this.analyzeInputs(inputs, state) || modified; modified = state.setVariableType(inputs.variable, inputs.value.type) || modified; break; case StackOpcode.CONTROL_WHILE: case StackOpcode.CONTROL_FOR: case StackOpcode.CONTROL_REPEAT: + modified = this.analyzeInputs(inputs, state) || modified; modified = this.analyzeLoopedStack(inputs.do, state, stackBlock) || modified; break; case StackOpcode.CONTROL_IF_ELSE: { + modified = this.analyzeInputs(inputs, state) || modified; const trueState = state.clone(); modified = this.analyzeStack(inputs.whenTrue, trueState) || modified; modified = this.analyzeStack(inputs.whenFalse, state) || modified; @@ -560,10 +562,17 @@ class IROptimizer { break; } case StackOpcode.CONTROL_STOP_SCRIPT: { + modified = this.analyzeInputs(inputs, state) || modified; this.addPossibleExitState(state); break; } + case StackOpcode.CONTROL_WAIT_UNTIL: { + modified = state.clear() || modified; + modified = this.analyzeInputs(inputs, state) || modified; + break; + } case StackOpcode.PROCEDURE_CALL: { + modified = this.analyzeInputs(inputs, state) || modified; modified = this.analyzeInputs(inputs.inputs, state) || modified; const script = this.ir.procedures[inputs.variant]; @@ -575,6 +584,7 @@ class IROptimizer { break; } case StackOpcode.COMPATIBILITY_LAYER: { + modified = this.analyzeInputs(inputs, state) || modified; this.analyzeInputs(inputs.inputs, state); for (const substackName in inputs.substacks) { const newState = state.clone(); @@ -583,6 +593,9 @@ class IROptimizer { } break; } + default: + modified = this.analyzeInputs(inputs, state) || modified; + break; } return modified; @@ -635,7 +648,7 @@ class IROptimizer { do { // If we are stuck in an apparent infinite loop, give up and assume the worst. if (iterations > 10000) { - console.error('analyzeLoopedStack stuck in likely infinite loop; quitting', block, state); + log.error('analyzeLoopedStack stuck in likely infinite loop; quitting', block, state); modified = state.clear(); block.entryState = state.clone(); block.exitState = state.clone(); @@ -646,8 +659,8 @@ class IROptimizer { const newState = state.clone(); modified = this.analyzeStack(stack, newState) || modified; - modified = this.analyzeInputs(block.inputs, newState) || modified; modified = (keepLooping = state.or(newState)) || modified; + modified = this.analyzeInputs(block.inputs, state) || modified; } while (keepLooping); block.entryState = state.clone(); return modified; diff --git a/test/fixtures/execute/tw-loop-condition-optimization-gh-276.sb3 b/test/fixtures/execute/tw-loop-condition-optimization-gh-276.sb3 new file mode 100644 index 00000000000..48099303ce1 Binary files /dev/null and b/test/fixtures/execute/tw-loop-condition-optimization-gh-276.sb3 differ diff --git a/test/fixtures/execute/tw-non-warp-loop-condition-analysis.sb3 b/test/fixtures/execute/tw-non-warp-loop-condition-analysis.sb3 new file mode 100644 index 00000000000..59c1cfcf66c Binary files /dev/null and b/test/fixtures/execute/tw-non-warp-loop-condition-analysis.sb3 differ diff --git a/test/fixtures/execute/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3 b/test/fixtures/execute/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3 new file mode 100644 index 00000000000..ce978f1954e Binary files /dev/null and b/test/fixtures/execute/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3 differ diff --git a/test/fixtures/execute/tw-state-analysis-understands-stop-this-script.sb3 b/test/fixtures/execute/tw-state-analysis-understands-stop-this-script.sb3 new file mode 100644 index 00000000000..735f45d77ca Binary files /dev/null and b/test/fixtures/execute/tw-state-analysis-understands-stop-this-script.sb3 differ diff --git a/test/fixtures/execute/tw-wait-until-condition-gh-277.sb3 b/test/fixtures/execute/tw-wait-until-condition-gh-277.sb3 new file mode 100644 index 00000000000..a170d42f737 Binary files /dev/null and b/test/fixtures/execute/tw-wait-until-condition-gh-277.sb3 differ diff --git a/test/fixtures/execute/tw-warp-loop-condition-analysis.sb3 b/test/fixtures/execute/tw-warp-loop-condition-analysis.sb3 new file mode 100644 index 00000000000..126857522d8 Binary files /dev/null and b/test/fixtures/execute/tw-warp-loop-condition-analysis.sb3 differ diff --git a/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot index d2efe972b71..224f800f45e 100644 --- a/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot @@ -67,10 +67,10 @@ b0.value = (b1.value[(((((+p1 || 0) + (+p0 || 0)) || 0) / 2) | 0) - 1] ?? ""); b2.value = p0; b3.value = p1; while (true) { -while (compareLessThan((b1.value[(b2.value | 0) - 1] ?? ""), b0.value)) { +while (compareLessThan(listGet(b1.value, b2.value), b0.value)) { b2.value = ((+b2.value || 0) + 1); } -while (compareGreaterThan((b1.value[(b3.value | 0) - 1] ?? ""), b0.value)) { +while (compareGreaterThan(listGet(b1.value, b3.value), b0.value)) { b3.value = ((+b3.value || 0) + -1); } if (compareGreaterThan(b2.value, b3.value)) { diff --git a/test/snapshot/__snapshots__/tw-loop-condition-optimization-gh-276.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-loop-condition-optimization-gh-276.sb3.tw-snapshot new file mode 100644 index 00000000000..20e23cc6056 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-loop-condition-optimization-gh-276.sb3.tw-snapshot @@ -0,0 +1,28 @@ +// TW Snapshot +// Input SHA-256: 3c81a01417b9a927457132a5f89b63e54b2499714376246739535b51dbce2d45 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "g", null); +thread.procedures["Wtest %s"]("random"); +if ((("" + b1.value).toLowerCase() === "random".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "p", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null); +retire(); return; +}; }) + +// Sprite1 Wtest %s +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = stage.variables["t)]?yi[*8XU73qhMqOa8"]; +return function funXYZ_test_ (p0) { +b0.value = p0; +while (!(("" + listGet(b1.value, b0.value)).toLowerCase() === "something".toLowerCase())) { +b0.value = ((+b0.value || 0) + 1); +} +return ""; +}; }) diff --git a/test/snapshot/__snapshots__/tw-non-warp-loop-condition-analysis.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-non-warp-loop-condition-analysis.sb3.tw-snapshot new file mode 100644 index 00000000000..018d12fbdc0 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-non-warp-loop-condition-analysis.sb3.tw-snapshot @@ -0,0 +1,29 @@ +// TW Snapshot +// Input SHA-256: be149d21cc69628647000cc698ebd60949252730a0ea7b19f71cc85fe927b294 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables["%ehs:~!Y0l-5=!mnd-B?"]; +const b2 = stage.variables["=3aHfv[mKa)v,Wfpy:y?"]; +const b3 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); +b1.value = []; +b1.value.push((1 + 2)); +b1._monitorUpToDate = false; +b1.value.push("eof"); +b1._monitorUpToDate = false; +b2.value = 0; +b3.value = "bwah"; +while (!(("" + b3.value).toLowerCase() === "eof".toLowerCase())) { +b2.value = ((+b2.value || 0) + 1); +b3.value = (b1.value[(b2.value | 0) - 1] ?? ""); +yield; +} +if (((+b2.value || 0) === 2)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "q", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot index b7824ee767a..6b2bc2a9f60 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot @@ -10,17 +10,17 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 18",}, b0, false, false, "G", null); b1.value = 0; b2.value = (yield* thread.procedures["Znon warp recursion should yield %s"](8)); -if (((+b1.value || 0) === 4)) { +if ((b1.value === 4)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp recursion yields",}, b0, false, false, "ao", null); } b1.value = 0; b2.value = thread.procedures["Wwarp recursion should not yield %s"](8); -if (compareEqual(b1.value, 0)) { +if ((b1.value === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass warp recursion does not yield",}, b0, false, false, "ar", null); } b1.value = 0; b2.value = (yield* thread.procedures["Zfib %s"](7)); -if (((+b1.value || 0) === 20)) { +if ((b1.value === 20)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp fib yielded",}, b0, false, false, "au", null); } yield* thread.procedures["Zrecursing yields between each %s"]("initial"); diff --git a/test/snapshot/__snapshots__/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3.tw-snapshot new file mode 100644 index 00000000000..3e809112dd6 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3.tw-snapshot @@ -0,0 +1,21 @@ +// TW Snapshot +// Input SHA-256: 91090a2de3ee7db914230fa0aa354e89d6b1781b5a730a71986b018b5f217f18 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "f", null); +b1.value = "5"; +runtime.ext_scratch3_looks._setCostume(target, "costume1"); +if (((target.currentCostume + 1) === 1)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass initial costume",}, b0, false, false, "p", null); +} +runtime.ext_scratch3_looks._setCostume(target, b1.value); +if (((target.currentCostume + 1) === 3)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass costume \"5\"",}, b0, false, false, "m", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/tw-state-analysis-understands-stop-this-script.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-state-analysis-understands-stop-this-script.sb3.tw-snapshot new file mode 100644 index 00000000000..7530899818e --- /dev/null +++ b/test/snapshot/__snapshots__/tw-state-analysis-understands-stop-this-script.sb3.tw-snapshot @@ -0,0 +1,30 @@ +// TW Snapshot +// Input SHA-256: 7f99a41ef716935ae486087d8adf955cbd853c893bc94e58e4cc1c46ad1a7883 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables["KMKx1gRubgLz,!L]^TBS"]; +const b2 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "g", null); +thread.procedures["Wtest"](); +if ((("" + listGet(b1.value, b2.value)).toLowerCase() === "thing".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "m", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null); +retire(); return; +}; }) + +// Sprite1 Wtest +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["yz}9Y:gLL0ZWEs}l)s+Q"]; +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function funXYZ_test () { +if ((("" + b0.value).toLowerCase() === "true".toLowerCase())) { +b1.value = "last"; +return ""; +} +b1.value = (1 + 2); +return ""; +}; }) diff --git a/test/snapshot/__snapshots__/tw-wait-until-condition-gh-277.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-wait-until-condition-gh-277.sb3.tw-snapshot new file mode 100644 index 00000000000..4312367087b --- /dev/null +++ b/test/snapshot/__snapshots__/tw-wait-until-condition-gh-277.sb3.tw-snapshot @@ -0,0 +1,34 @@ +// TW Snapshot +// Input SHA-256: 2422e407892596fbf410e032196131f9bae718563fd80b1ff32cf972859c034b + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "e", null); +startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); +b1.value = "bwah"; +while (!(("" + b1.value).toLowerCase() === "bleh".toLowerCase())) { +yield; +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "h", null); +retire(); return; +}; }) + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +b0.value = (1 + 2); +thread.timer = timer(); +var a0 = Math.max(0, 1000 * 0); +runtime.requestRedraw(); +yield; +while (thread.timer.timeElapsed() < a0) { +yield; +} +thread.timer = null; +b0.value = "bleh"; +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/tw-warp-loop-condition-analysis.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-warp-loop-condition-analysis.sb3.tw-snapshot new file mode 100644 index 00000000000..7a4aaa9cae2 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-warp-loop-condition-analysis.sb3.tw-snapshot @@ -0,0 +1,39 @@ +// TW Snapshot +// Input SHA-256: 95d4c128e84ee992b48ed20653ba70b0f6c2d404c4f7088fa654676cd6b7c53c + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables[";~q(!vt3c.Jrz2M]ZMy]"]; +const b2 = stage.variables[",23fjp~KN1aMG|;66K@Z"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "j", null); +b1.value = []; +b1.value.push((1 + 2)); +b1._monitorUpToDate = false; +b1.value.push((3 + 4)); +b1._monitorUpToDate = false; +b1.value.push("final"); +b1._monitorUpToDate = false; +thread.procedures["Wtest"](); +if ((b2.value === 4)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "u", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "t", null); +retire(); return; +}; }) + +// Sprite1 Wtest +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = stage.variables[",23fjp~KN1aMG|;66K@Z"]; +const b2 = stage.variables[";~q(!vt3c.Jrz2M]ZMy]"]; +return function funXYZ_test () { +b0.value = ""; +b1.value = 1; +while (!(("" + b0.value).toLowerCase() === "final".toLowerCase())) { +b0.value = (b2.value[b1.value - 1] ?? ""); +b1.value = (b1.value + 1); +} +return ""; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-loop-condition-optimization-gh-276.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-loop-condition-optimization-gh-276.sb3.tw-snapshot new file mode 100644 index 00000000000..5cef84247bc --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-loop-condition-optimization-gh-276.sb3.tw-snapshot @@ -0,0 +1,29 @@ +// TW Snapshot +// Input SHA-256: 3c81a01417b9a927457132a5f89b63e54b2499714376246739535b51dbce2d45 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "g", null); +yield* thread.procedures["Wtest %s"]("random"); +if ((("" + b1.value).toLowerCase() === "random".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "p", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null); +retire(); return; +}; }) + +// Sprite1 Wtest %s +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = stage.variables["t)]?yi[*8XU73qhMqOa8"]; +return function* genXYZ_test_ (p0) { +b0.value = p0; +while (!(("" + listGet(b1.value, b0.value)).toLowerCase() === "something".toLowerCase())) { +b0.value = ((+b0.value || 0) + 1); +if (isStuck()) yield; +} +return ""; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-non-warp-loop-condition-analysis.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-non-warp-loop-condition-analysis.sb3.tw-snapshot new file mode 100644 index 00000000000..018d12fbdc0 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-non-warp-loop-condition-analysis.sb3.tw-snapshot @@ -0,0 +1,29 @@ +// TW Snapshot +// Input SHA-256: be149d21cc69628647000cc698ebd60949252730a0ea7b19f71cc85fe927b294 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables["%ehs:~!Y0l-5=!mnd-B?"]; +const b2 = stage.variables["=3aHfv[mKa)v,Wfpy:y?"]; +const b3 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); +b1.value = []; +b1.value.push((1 + 2)); +b1._monitorUpToDate = false; +b1.value.push("eof"); +b1._monitorUpToDate = false; +b2.value = 0; +b3.value = "bwah"; +while (!(("" + b3.value).toLowerCase() === "eof".toLowerCase())) { +b2.value = ((+b2.value || 0) + 1); +b3.value = (b1.value[(b2.value | 0) - 1] ?? ""); +yield; +} +if (((+b2.value || 0) === 2)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "q", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-recursion.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-recursion.sb3.tw-snapshot index b7824ee767a..6b2bc2a9f60 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-recursion.sb3.tw-snapshot @@ -10,17 +10,17 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 18",}, b0, false, false, "G", null); b1.value = 0; b2.value = (yield* thread.procedures["Znon warp recursion should yield %s"](8)); -if (((+b1.value || 0) === 4)) { +if ((b1.value === 4)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp recursion yields",}, b0, false, false, "ao", null); } b1.value = 0; b2.value = thread.procedures["Wwarp recursion should not yield %s"](8); -if (compareEqual(b1.value, 0)) { +if ((b1.value === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass warp recursion does not yield",}, b0, false, false, "ar", null); } b1.value = 0; b2.value = (yield* thread.procedures["Zfib %s"](7)); -if (((+b1.value || 0) === 20)) { +if ((b1.value === 20)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp fib yielded",}, b0, false, false, "au", null); } yield* thread.procedures["Zrecursing yields between each %s"]("initial"); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3.tw-snapshot new file mode 100644 index 00000000000..3e809112dd6 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3.tw-snapshot @@ -0,0 +1,21 @@ +// TW Snapshot +// Input SHA-256: 91090a2de3ee7db914230fa0aa354e89d6b1781b5a730a71986b018b5f217f18 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "f", null); +b1.value = "5"; +runtime.ext_scratch3_looks._setCostume(target, "costume1"); +if (((target.currentCostume + 1) === 1)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass initial costume",}, b0, false, false, "p", null); +} +runtime.ext_scratch3_looks._setCostume(target, b1.value); +if (((target.currentCostume + 1) === 3)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass costume \"5\"",}, b0, false, false, "m", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-state-analysis-understands-stop-this-script.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-state-analysis-understands-stop-this-script.sb3.tw-snapshot new file mode 100644 index 00000000000..7530899818e --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-state-analysis-understands-stop-this-script.sb3.tw-snapshot @@ -0,0 +1,30 @@ +// TW Snapshot +// Input SHA-256: 7f99a41ef716935ae486087d8adf955cbd853c893bc94e58e4cc1c46ad1a7883 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables["KMKx1gRubgLz,!L]^TBS"]; +const b2 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "g", null); +thread.procedures["Wtest"](); +if ((("" + listGet(b1.value, b2.value)).toLowerCase() === "thing".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "m", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null); +retire(); return; +}; }) + +// Sprite1 Wtest +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["yz}9Y:gLL0ZWEs}l)s+Q"]; +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function funXYZ_test () { +if ((("" + b0.value).toLowerCase() === "true".toLowerCase())) { +b1.value = "last"; +return ""; +} +b1.value = (1 + 2); +return ""; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-wait-until-condition-gh-277.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-wait-until-condition-gh-277.sb3.tw-snapshot new file mode 100644 index 00000000000..4312367087b --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-wait-until-condition-gh-277.sb3.tw-snapshot @@ -0,0 +1,34 @@ +// TW Snapshot +// Input SHA-256: 2422e407892596fbf410e032196131f9bae718563fd80b1ff32cf972859c034b + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "e", null); +startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); +b1.value = "bwah"; +while (!(("" + b1.value).toLowerCase() === "bleh".toLowerCase())) { +yield; +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "h", null); +retire(); return; +}; }) + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +b0.value = (1 + 2); +thread.timer = timer(); +var a0 = Math.max(0, 1000 * 0); +runtime.requestRedraw(); +yield; +while (thread.timer.timeElapsed() < a0) { +yield; +} +thread.timer = null; +b0.value = "bleh"; +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-warp-loop-condition-analysis.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-warp-loop-condition-analysis.sb3.tw-snapshot new file mode 100644 index 00000000000..e5b718730e8 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-warp-loop-condition-analysis.sb3.tw-snapshot @@ -0,0 +1,40 @@ +// TW Snapshot +// Input SHA-256: 95d4c128e84ee992b48ed20653ba70b0f6c2d404c4f7088fa654676cd6b7c53c + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +const b1 = stage.variables[";~q(!vt3c.Jrz2M]ZMy]"]; +const b2 = stage.variables[",23fjp~KN1aMG|;66K@Z"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "j", null); +b1.value = []; +b1.value.push((1 + 2)); +b1._monitorUpToDate = false; +b1.value.push((3 + 4)); +b1._monitorUpToDate = false; +b1.value.push("final"); +b1._monitorUpToDate = false; +yield* thread.procedures["Wtest"](); +if (((+b2.value || 0) === 4)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "u", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "t", null); +retire(); return; +}; }) + +// Sprite1 Wtest +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = stage.variables[",23fjp~KN1aMG|;66K@Z"]; +const b2 = stage.variables[";~q(!vt3c.Jrz2M]ZMy]"]; +return function* genXYZ_test () { +b0.value = ""; +b1.value = 1; +while (!(("" + b0.value).toLowerCase() === "final".toLowerCase())) { +b0.value = listGet(b2.value, b1.value); +b1.value = ((+b1.value || 0) + 1); +if (isStuck()) yield; +} +return ""; +}; })