Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion src/compiler/intermediate.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,46 @@ class IntermediateInput {
}
}


/**
* @param {InputType} type
* @returns {string}
*/
const stringifyType = type => {
let formatFlags = [];

for (const enumValue in InputType) {
const testFormat = InputType[enumValue];

if ((testFormat & type) === testFormat) {
for (const existingFormat of formatFlags) {
if ((testFormat & InputType[existingFormat]) === testFormat) {
continue;
}
}

formatFlags = formatFlags.filter(value => (InputType[value] & testFormat) !== InputType[value]);
formatFlags.push(enumValue);
}
}

let str = null;

for (const formatFlag of formatFlags) {
if (str === null) {
str = formatFlag;
} else {
str = `${str} | ${formatFlag}`;
}
}

if (str === null) {
return 'INVALID';
}

return str;
};

/**
* A 'stack' of blocks, like the contents of a script or the inside
* of a C block.
Expand Down Expand Up @@ -350,5 +390,6 @@ module.exports = {
IntermediateInput,
IntermediateStack,
IntermediateScript,
IntermediateRepresentation
IntermediateRepresentation,
stringifyType
};
8 changes: 4 additions & 4 deletions src/compiler/irgen.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,14 +299,14 @@ class ScriptTreeGenerator {
}
return new IntermediateInput(InputOpcode.LOOKS_COSTUME_NAME, InputType.STRING);
case 'looks_size':
return new IntermediateInput(InputOpcode.LOOKS_SIZE_GET, InputType.NUMBER_POS_REAL);
return new IntermediateInput(InputOpcode.LOOKS_SIZE_GET, InputType.NUMBER_POS);

case 'motion_direction':
return new IntermediateInput(InputOpcode.MOTION_DIRECTION_GET, InputType.NUMBER_REAL);
case 'motion_xposition':
return new IntermediateInput(InputOpcode.MOTION_X_GET, InputType.NUMBER_REAL);
return new IntermediateInput(InputOpcode.MOTION_X_GET, InputType.NUMBER);
case 'motion_yposition':
return new IntermediateInput(InputOpcode.MOTION_Y_GET, InputType.NUMBER_REAL);
return new IntermediateInput(InputOpcode.MOTION_Y_GET, InputType.NUMBER);

case 'operator_add':
return new IntermediateInput(InputOpcode.OP_ADD, InputType.NUMBER_OR_NAN, {
Expand Down Expand Up @@ -494,7 +494,7 @@ class ScriptTreeGenerator {
case 'sensing_dayssince2000':
return new IntermediateInput(InputOpcode.SENSING_TIME_DAYS_SINCE_2000, InputType.NUMBER);
case 'sensing_distanceto':
return new IntermediateInput(InputOpcode.SENSING_DISTANCE, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO, {
return new IntermediateInput(InputOpcode.SENSING_DISTANCE, InputType.NUMBER_POS | InputType.NUMBER_ZERO, {
target: this.descendInputOfBlock(block, 'DISTANCETOMENU').toType(InputType.STRING)
});
case 'sensing_keypressed':
Expand Down
36 changes: 19 additions & 17 deletions src/compiler/iroptimizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,8 @@ class IROptimizer {
let resultType = 0;

const canBeNaN = function () {
// REAL / 0 = NaN
if ((leftType & InputType.NUMBER_REAL) && (rightType & InputType.NUMBER_ZERO)) return true;
// (-)0 / (-)0 = NaN
if ((leftType & InputType.NUMBER_ANY_ZERO) && (rightType & InputType.NUMBER_ANY_ZERO)) return true;
// (-)Infinity / (-)Infinity = NaN
if ((leftType & InputType.NUMBER_INF) && (rightType & InputType.NUMBER_INF)) return true;
// (-)0 / NaN = NaN
Expand All @@ -395,24 +395,26 @@ class IROptimizer {
if (canBePos()) resultType |= InputType.NUMBER_POS;

const canBeNegInfinity = function () {
// -Infinity / 0 = -Infinity
if ((leftType & InputType.NUMBER_NEG_INF) && (rightType & InputType.NUMBER_ZERO)) return true;
// Infinity / -0 = -Infinity
if ((leftType & InputType.NUMBER_POS_INF) && (rightType & InputType.NUMBER_NEG_ZERO)) return true;
// NEG_REAL / NaN = -Infinity
if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_NAN)) return true;
// NEG_REAL / NUMBER_OR_NAN ~= -Infinity
if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_OR_NAN)) return true;
// NEG / 0 = -Infinity
if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_ZERO)) return true;
// POS / -0 = -Infinity
if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_NEG_ZERO)) return true;
// NEG_REAL / POS_REAL ~= -Infinity
if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_POS_REAL)) return true;
// POS_REAL / NEG_REAL ~= -Infinity
if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_NEG_REAL)) return true;
};
if (canBeNegInfinity()) resultType |= InputType.NUMBER_NEG_INF;

const canBeInfinity = function () {
// Infinity / 0 = Infinity
if ((leftType & InputType.NUMBER_POS_INF) && (rightType & InputType.NUMBER_ZERO)) return true;
// -Infinity / -0 = Infinity
if ((leftType & InputType.NUMBER_NEG_INF) && (rightType & InputType.NUMBER_NEG_ZERO)) return true;
// POS_REAL / NUMBER_OR_NAN ~= Infinity
if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_OR_NAN)) return true;
// POS / 0 = Infinity
if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_ZERO)) return true;
// NEG / -0 = Infinity
if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_NEG_ZERO)) return true;
// POS_REAL / POS_REAL ~= Infinity
if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_POS_REAL)) return true;
// NEG_REAL / NEG_REAL ~= Infinity
if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_NEG_REAL)) return true;
};
if (canBeInfinity()) resultType |= InputType.NUMBER_POS_INF;

Expand Down Expand Up @@ -644,8 +646,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;
Expand Down
6 changes: 3 additions & 3 deletions test/integration/tw_operator_type_matrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const VM = require('../../src/virtual-machine');
const {BlockType, ArgumentType} = require('../../src/extension-support/tw-extension-api-common');
const {IRGenerator} = require('../../src/compiler/irgen');
const {IROptimizer} = require('../../src/compiler/iroptimizer');
const {IntermediateInput} = require('../../src/compiler/intermediate');
const {IntermediateInput, stringifyType} = require('../../src/compiler/intermediate');
const nanolog = require('@turbowarp/nanolog');

const VALUES = [
Expand Down Expand Up @@ -113,7 +113,7 @@ test('operator type matrix', async t => {
1,
[
4,
`${inputs[i]}`
`${Object.is(inputs[i], -0) ? '-0' : inputs[i]}`
]
];
}
Expand Down Expand Up @@ -180,7 +180,7 @@ test('operator type matrix', async t => {
t.ok(
irOperator.isSometimesType(expectedType),
`${operator.opcode}${JSON.stringify(operator.fields)}[${inputs.map(str)}] ` +
`outputted value ${str(reportedValue)} is of the expected type ${irOperator.type}.`
`outputted value ${str(reportedValue)} is of the expected type ${stringifyType(irOperator.type)}.`
);
};

Expand Down
6 changes: 3 additions & 3 deletions test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ao",
if (((((Math.log(-1) / Math.LN10) || 0) * 1) === 0)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aq", null);
}
if (((((Math.round(Math.sin((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) {
if (((((Math.round(Math.sin((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "as", null);
}
if (((((Math.round(Math.cos((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) {
if (((((Math.round(Math.cos((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "au", null);
}
if ((((tan(((1 / 0) || 0)) || 0) * 1) === 0)) {
if ((((tan((1 / 0)) || 0) * 1) === 0)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aw", null);
}
if ((((runtime.ext_scratch3_operators._random((-1 / 0), (1 / 0)) || 0) * 1) === 0)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ target.setDirection(95);
if ((target.direction === 95)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass 1",}, b0, false, false, "o", null);
}
target.setDirection(((1 / 0) || 0));
target.setDirection((1 / 0));
if ((target.direction === 95)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass 2",}, b0, false, false, "r", null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(listGet(b1.value, b2.value), b0.value)) {
while (compareLessThan((b1.value[(b2.value | 0) - 1] ?? ""), b0.value)) {
b2.value = ((+b2.value || 0) + 1);
}
while (compareGreaterThan(listGet(b1.value, b3.value), b0.value)) {
while (compareGreaterThan((b1.value[(b3.value | 0) - 1] ?? ""), b0.value)) {
b3.value = ((+b3.value || 0) + -1);
}
if (compareGreaterThan(b2.value, b3.value)) {
Expand Down
6 changes: 3 additions & 3 deletions test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ao",
if (((((Math.log(-1) / Math.LN10) || 0) * 1) === 0)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aq", null);
}
if (((((Math.round(Math.sin((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) {
if (((((Math.round(Math.sin((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "as", null);
}
if (((((Math.round(Math.cos((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) {
if (((((Math.round(Math.cos((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "au", null);
}
if ((((tan(((1 / 0) || 0)) || 0) * 1) === 0)) {
if ((((tan((1 / 0)) || 0) * 1) === 0)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aw", null);
}
if ((((runtime.ext_scratch3_operators._random((-1 / 0), (1 / 0)) || 0) * 1) === 0)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ target.setDirection(95);
if ((target.direction === 95)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass 1",}, b0, false, false, "o", null);
}
target.setDirection(((1 / 0) || 0));
target.setDirection((1 / 0));
if ((target.direction === 95)) {
yield* executeInCompatibilityLayer({"MESSAGE":"pass 2",}, b0, false, false, "r", null);
}
Expand Down