Skip to content

Commit 198221e

Browse files
committed
fix switch cases being lost when more than 2 or inputs
1 parent 1d40c3e commit 198221e

2 files changed

Lines changed: 104 additions & 4 deletions

File tree

src/serialization/sb3.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -809,10 +809,14 @@ const collapseSwitches = function (blocks, variables) {
809809
return [condId];
810810
}
811811
if (b.opcode === 'operator_or') {
812-
const left = flattenEquals(getInputBlockId(b, 'OPERAND1'), leftKey);
813-
const right = flattenEquals(getInputBlockId(b, 'OPERAND2'), leftKey);
814-
if (!left || !right) return null;
815-
return left.concat(right);
812+
const count = getOperatorItemCount(b);
813+
const result = [];
814+
for (let i = 1; i <= count; i++) {
815+
const part = flattenEquals(getInputBlockId(b, `OPERAND${i}`), leftKey);
816+
if (!part) return null;
817+
for (const eqId of part) result.push(eqId);
818+
}
819+
return result;
816820
}
817821
return null;
818822
};

test/unit/serialization_switch_expand.js

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,3 +498,99 @@ test('expandSwitches lowers nested switches innermost-first', t => {
498498
t.notOk(opcodes.includes('control_case'), 'no cases left');
499499
t.end();
500500
});
501+
502+
test('collapseSwitches folds a variadic operator_or into every case', t => {
503+
const eqBlock = (id, value, parent) => ({
504+
id,
505+
opcode: 'operator_equals',
506+
next: null,
507+
parent,
508+
inputs: {
509+
OPERAND1: {name: 'OPERAND1', block: `${id}var`, shadow: null},
510+
OPERAND2: {name: 'OPERAND2', block: `${id}val`, shadow: `${id}val`}
511+
},
512+
fields: {},
513+
shadow: false,
514+
topLevel: false
515+
});
516+
const varReporter = (id, parent) => ({
517+
id,
518+
opcode: 'data_variable',
519+
next: null,
520+
parent,
521+
inputs: {},
522+
fields: {VARIABLE: {name: 'VARIABLE', value: 'switch value', id: 'svid'}},
523+
shadow: false,
524+
topLevel: false
525+
});
526+
527+
const values = ['5', '4', '2', '3'];
528+
const orInputs = {};
529+
const blocks = {
530+
top: {
531+
id: 'top',
532+
opcode: 'event_whenflagclicked',
533+
next: 'if',
534+
parent: null,
535+
inputs: {},
536+
fields: {},
537+
shadow: false,
538+
topLevel: true,
539+
x: 0,
540+
y: 0
541+
},
542+
if: {
543+
id: 'if',
544+
opcode: 'control_if_else',
545+
next: null,
546+
parent: 'top',
547+
inputs: {
548+
CONDITION: {name: 'CONDITION', block: 'or', shadow: null},
549+
SUBSTACK: {name: 'SUBSTACK', block: 'body', shadow: null},
550+
SUBSTACK2: {name: 'SUBSTACK2', block: 'defbody', shadow: null}
551+
},
552+
fields: {},
553+
shadow: false,
554+
topLevel: false
555+
},
556+
body: stackBlock('body', 'looks_show', 'if', null),
557+
defbody: stackBlock('defbody', 'looks_hide', 'if', null)
558+
};
559+
values.forEach((value, i) => {
560+
const eqId = `eq${i}`;
561+
orInputs[`OPERAND${i + 1}`] = {name: `OPERAND${i + 1}`, block: eqId, shadow: null};
562+
blocks[eqId] = eqBlock(eqId, value, 'or');
563+
blocks[`${eqId}var`] = varReporter(`${eqId}var`, eqId);
564+
blocks[`${eqId}val`] = textShadow(`${eqId}val`, value, eqId);
565+
});
566+
blocks.or = {
567+
id: 'or',
568+
opcode: 'operator_or',
569+
next: null,
570+
parent: 'if',
571+
inputs: orInputs,
572+
fields: {},
573+
shadow: false,
574+
topLevel: false,
575+
mutation: {tagName: 'mutation', children: [], itemcount: '4'}
576+
};
577+
578+
const collapsed = sb3.collapseSwitches(blocks, {});
579+
const switchId = Object.keys(collapsed).find(id => collapsed[id].opcode === 'control_switch');
580+
t.ok(switchId, 'switch created');
581+
582+
const caseValues = [];
583+
let cur = collapsed[switchId].inputs.SUBSTACK.block;
584+
while (cur) {
585+
const block = collapsed[cur];
586+
if (block.opcode === 'control_case' || block.opcode === 'control_case_fallthrough') {
587+
const valInput = block.inputs.VALUE;
588+
const valBlock = collapsed[valInput.block || valInput.shadow];
589+
caseValues.push(valBlock.fields.TEXT.value);
590+
}
591+
cur = block.next;
592+
}
593+
t.same(caseValues, ['5', '4', '2', '3'], 'all four operands became cases');
594+
t.notOk(Object.values(collapsed).some(b => b.opcode === 'operator_or'), 'variadic or consumed');
595+
t.end();
596+
});

0 commit comments

Comments
 (0)