diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index b1b8ded5..ca3d7f31 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -1229,17 +1229,19 @@ class ScriptTreeGenerator { const variable = block.fields[fieldName]; const id = variable.id; - if (Object.prototype.hasOwnProperty.call(this.variableCache, id)) { + if (id && Object.prototype.hasOwnProperty.call(this.variableCache, id)) { return this.variableCache[id]; } const data = this._descendVariable(id, variable.value, type); - this.variableCache[id] = data; + // If variable ID was null, this might do some unnecessary updates, but that is a rare + // edge case and it won't have any adverse effects anyways. + this.variableCache[data.id] = data; return data; } /** - * @param {string} id The ID of the variable. + * @param {string|null} id The ID of the variable. * @param {string} name The name of the variable. * @param {''|'list'} type The variable type. * @private diff --git a/test/fixtures/execute/tw-block-with-null-for-variable-id.sb3 b/test/fixtures/execute/tw-block-with-null-for-variable-id.sb3 new file mode 100644 index 00000000..68b151ee Binary files /dev/null and b/test/fixtures/execute/tw-block-with-null-for-variable-id.sb3 differ diff --git a/test/snapshot/__snapshots__/tw-block-with-null-for-variable-id.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-block-with-null-for-variable-id.sb3.tw-snapshot new file mode 100644 index 00000000..17631a6d --- /dev/null +++ b/test/snapshot/__snapshots__/tw-block-with-null-for-variable-id.sb3.tw-snapshot @@ -0,0 +1,39 @@ +// TW Snapshot +// Input SHA-256: 99bb22ac4fb2542ce3c21fa7d2025f03d15392a33850585a4d12f4ec558663ac + +// 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"]; +const b2 = stage.variables[")|GMR5fz;%F_H,c0wGVM"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "c", null); +b1.value = 1; +b2.value = 2; +yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "check 1" })); +yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "check 2" })); +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "k", 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"]; +const b1 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +if (((+b0.value || 0) === 1)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 1",}, b1, false, false, "m", null); +} +retire(); return; +}; }) + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables[")|GMR5fz;%F_H,c0wGVM"]; +const b1 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +if (((+b0.value || 0) === 2)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 2",}, b1, false, false, "q", null); +} +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-block-with-null-for-variable-id.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-block-with-null-for-variable-id.sb3.tw-snapshot new file mode 100644 index 00000000..17631a6d --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-block-with-null-for-variable-id.sb3.tw-snapshot @@ -0,0 +1,39 @@ +// TW Snapshot +// Input SHA-256: 99bb22ac4fb2542ce3c21fa7d2025f03d15392a33850585a4d12f4ec558663ac + +// 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"]; +const b2 = stage.variables[")|GMR5fz;%F_H,c0wGVM"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "c", null); +b1.value = 1; +b2.value = 2; +yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "check 1" })); +yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "check 2" })); +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "k", 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"]; +const b1 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +if (((+b0.value || 0) === 1)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 1",}, b1, false, false, "m", null); +} +retire(); return; +}; }) + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables[")|GMR5fz;%F_H,c0wGVM"]; +const b1 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +if (((+b0.value || 0) === 2)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 2",}, b1, false, false, "q", null); +} +retire(); return; +}; })