From fffb72b09d549bb37bbbc64ef7508a4a2eafa13d Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:10:14 +1000 Subject: [PATCH 001/106] Upgraded Type Analysis --- src/compiler/compat-block-utility.js | 7 +- src/compiler/compat-blocks.js | 2 + src/compiler/compile.js | 12 +- src/compiler/enums.js | 295 ++++ src/compiler/environment.js | 1 + src/compiler/intermediate.js | 253 ++- src/compiler/irgen.js | 1465 +++++++---------- src/compiler/iroptimizer.js | 703 ++++++++ src/compiler/jsexecute.js | 13 +- src/compiler/jsgen.js | 1312 ++++++--------- src/compiler/variable-pool.js | 2 + .../order-library-reverse.sb3.tw-snapshot | 4 +- .../order-library.sb3.tw-snapshot | 4 +- .../__snapshots__/tw-NaN.sb3.tw-snapshot | 24 +- ...-does-not-use-rounded-size.sb3.tw-snapshot | 2 +- ...tw-color-input-returns-hex.sb3.tw-snapshot | 2 +- ...w-comparison-matrix-inline.sb3.tw-snapshot | 186 +-- ...-comparison-matrix-runtime.sb3.tw-snapshot | 14 +- .../tw-custom-report-repeat.sb3.tw-snapshot | 2 +- ...-boolean-number-comparison.sb3.tw-snapshot | 4 +- ...-name-desync-name-fallback.sb3.tw-snapshot | 4 +- ...-zero-seconds-in-warp-mode.sb3.tw-snapshot | 6 +- ...s-not-reevaluate-arguments.sb3.tw-snapshot | 4 +- .../__snapshots__/tw-list-any.sb3.tw-snapshot | 2 +- ...w-one-divide-negative-zero.sb3.tw-snapshot | 2 +- ...nce-of-procedure-387608267.sb3.tw-snapshot | 2 +- ...e-arguments-with-same-name.sb3.tw-snapshot | 4 +- ...able-input-types-430811055.sb3.tw-snapshot | 4 +- ...cedure-return-non-existant.sb3.tw-snapshot | 4 +- ...cedure-return-non-existent.sb3.tw-snapshot | 2 +- ...procedure-return-recursion.sb3.tw-snapshot | 32 +- ...tw-procedure-return-simple.sb3.tw-snapshot | 20 +- ...edure-return-stops-scripts.sb3.tw-snapshot | 8 +- .../tw-procedure-return-warp.sb3.tw-snapshot | 6 +- ...procedure-argument-casting.sb3.tw-snapshot | 2 +- .../tw-sensing-of.sb3.tw-snapshot | 4 +- .../tw-tab-equals-zero.sb3.tw-snapshot | 2 +- .../__snapshots__/tw-tangent.sb3.tw-snapshot | 14 +- .../tw-unsafe-equals.sb3.tw-snapshot | 26 +- ...t-until-timer-greater-than.sb3.tw-snapshot | 6 +- ...mbie-cube-escape-284516654.sb3.tw-snapshot | 4 +- .../order-library-reverse.sb3.tw-snapshot | 4 +- .../warp-timer/order-library.sb3.tw-snapshot | 4 +- .../warp-timer/tw-NaN.sb3.tw-snapshot | 24 +- ...-does-not-use-rounded-size.sb3.tw-snapshot | 2 +- ...tw-color-input-returns-hex.sb3.tw-snapshot | 2 +- ...w-comparison-matrix-inline.sb3.tw-snapshot | 186 +-- ...-comparison-matrix-runtime.sb3.tw-snapshot | 14 +- .../tw-custom-report-repeat.sb3.tw-snapshot | 2 +- ...-boolean-number-comparison.sb3.tw-snapshot | 4 +- ...-name-desync-name-fallback.sb3.tw-snapshot | 4 +- ...-zero-seconds-in-warp-mode.sb3.tw-snapshot | 6 +- ...s-not-reevaluate-arguments.sb3.tw-snapshot | 4 +- .../warp-timer/tw-list-any.sb3.tw-snapshot | 2 +- ...w-one-divide-negative-zero.sb3.tw-snapshot | 2 +- ...nce-of-procedure-387608267.sb3.tw-snapshot | 2 +- ...e-arguments-with-same-name.sb3.tw-snapshot | 4 +- ...able-input-types-430811055.sb3.tw-snapshot | 4 +- ...cedure-return-non-existant.sb3.tw-snapshot | 4 +- ...cedure-return-non-existent.sb3.tw-snapshot | 2 +- ...procedure-return-recursion.sb3.tw-snapshot | 32 +- ...tw-procedure-return-simple.sb3.tw-snapshot | 20 +- ...edure-return-stops-scripts.sb3.tw-snapshot | 6 +- .../tw-procedure-return-warp.sb3.tw-snapshot | 6 +- ...procedure-argument-casting.sb3.tw-snapshot | 2 +- .../warp-timer/tw-sensing-of.sb3.tw-snapshot | 4 +- .../tw-tab-equals-zero.sb3.tw-snapshot | 2 +- .../warp-timer/tw-tangent.sb3.tw-snapshot | 14 +- .../tw-unsafe-equals.sb3.tw-snapshot | 26 +- ...t-until-timer-greater-than.sb3.tw-snapshot | 6 +- ...mbie-cube-escape-284516654.sb3.tw-snapshot | 4 +- 71 files changed, 2800 insertions(+), 2063 deletions(-) create mode 100644 src/compiler/enums.js create mode 100644 src/compiler/iroptimizer.js diff --git a/src/compiler/compat-block-utility.js b/src/compiler/compat-block-utility.js index 6fedba1d9d2..b662867dc07 100644 --- a/src/compiler/compat-block-utility.js +++ b/src/compiler/compat-block-utility.js @@ -1,13 +1,16 @@ +// @ts-check + const BlockUtility = require('../engine/block-utility'); class CompatibilityLayerBlockUtility extends BlockUtility { constructor () { super(); + this._stackFrame = {}; this._startedBranch = null; } get stackFrame () { - return this.thread.compatibilityStackFrame; + return this._stackFrame; } startBranch (branchNumber, isLoop) { @@ -32,9 +35,9 @@ class CompatibilityLayerBlockUtility extends BlockUtility { init (thread, fakeBlockId, stackFrame) { this.thread = thread; this.sequencer = thread.target.runtime.sequencer; + this._stackFrame = stackFrame; this._startedBranch = null; thread.stack[0] = fakeBlockId; - thread.compatibilityStackFrame = stackFrame; } } diff --git a/src/compiler/compat-blocks.js b/src/compiler/compat-blocks.js index 1c9d8f5ae9a..ba9d5b88bb8 100644 --- a/src/compiler/compat-blocks.js +++ b/src/compiler/compat-blocks.js @@ -1,3 +1,5 @@ +// @ts-check + /** * @fileoverview List of blocks to be supported in the compiler compatibility layer. * This is only for native blocks. Extensions should not be listed here. diff --git a/src/compiler/compile.js b/src/compiler/compile.js index b5edb81352b..4a5c5029636 100644 --- a/src/compiler/compile.js +++ b/src/compiler/compile.js @@ -1,14 +1,20 @@ -const {IRGenerator} = require('./irgen'); +// @ts-check + +const IRGenerator = require('./irgen'); +const {IROptimizer} = require('./iroptimizer'); const JSGenerator = require('./jsgen'); -const compile = thread => { +const compile = (/** @type {import("../engine/thread")} */ thread) => { const irGenerator = new IRGenerator(thread); const ir = irGenerator.generate(); + const irOptimizer = new IROptimizer(ir); + irOptimizer.optimize(); + const procedures = {}; const target = thread.target; - const compileScript = script => { + const compileScript = (/** @type {import("./intermediate").IntermediateScript} */ script) => { if (script.cachedCompileResult) { return script.cachedCompileResult; } diff --git a/src/compiler/enums.js b/src/compiler/enums.js new file mode 100644 index 00000000000..c1a4e90fc24 --- /dev/null +++ b/src/compiler/enums.js @@ -0,0 +1,295 @@ +// @ts-check + +/** + * @fileoverview Common enums shared amongst parts of the compiler. + */ + + +/** + * Enum for the type of the value that is returned by reporter blocks and stored in constants. + * + * At compile time, often we don't know exactly type a value will be but we can tell it must be one of a + * set of types. For this reason, the number value of each type represents a possibility space, where set + * bits indicate that their corropoding type *could* be encountered at runtime. + * For example, a type of InputType.NUMBER | InputType.STRING means the value will be either a number or + * a string at runtime, the compiler can't tell which, but we do know that it's not a boolean or NaN as + * those bits are not set. + * + * @readonly + * @enum {number} + */ +const InputType = { + /** The value Infinity */ + NUMBER_POS_INF: 0x001, + /** Any natural number */ + NUMBER_POS_INT: 0x002, + /** Any positive fractional number, excluding integers. */ + NUMBER_POS_FRACT: 0x004, + /** Any positive number excluding 0 and Infinity. Equal to NUMBER_POS_INT | NUMBER_POS_FRACT */ + NUMBER_POS_REAL: 0x006, + /** The value 0 */ + NUMBER_ZERO: 0x008, + /** The value -0 */ + NUMBER_NEG_ZERO: 0x010, + /** Any negitive integer excluding -0 */ + NUMBER_NEG_INT: 0x020, + /** Any negitive fractional number, excluding integers. */ + NUMBER_NEG_FRACT: 0x040, + /** Any negitive number excluding -0 and -Infinity. Equal to NUMBER_NEG_INT | NUMBER_NEG_FRACT */ + NUMBER_NEG_REAL: 0x060, + /** The value -Infinity */ + NUMBER_NEG_INF: 0x080, + + /** The value NaN */ + NUMBER_NAN: 0x100, + + /** Either 0 or -0. Equal to NUMBER_ZERO | NUMBER_NEG_ZERO */ + NUMBER_ANY_ZERO: 0x018, + /** Either Infinity or -Infinity. Equal to NUMBER_POS_INF | NUMBER_NEG_INF */ + NUMBER_INF: 0x081, + /** Any positive number, excluding 0. Equal to NUMBER_POS_REAL | NUMBER_POS_INF */ + NUMBER_POS: 0x007, + /** Any negitive number, excluding -0. Equal to NUMBER_NEG_REAL | NUMBER_NEG_INF */ + NUMBER_NEG: 0x0E0, + /** Any whole number. Equal to NUMBER_POS_INT | NUMBER_ZERO */ + NUMBER_WHOLE: 0x00A, + /** Any integer. Equal to NUMBER_POS_INT | NUMBER_ANY_ZERO | NUMBER_NEG_INT */ + NUMBER_INT: 0x03A, + /** Any number that works as an array index. Equal to NUMBER_INT | NUMBER_INF | NUMBER_NAN */ + NUMBER_INDEX: 0x1BB, + /** Any fractional non-integer numbers. Equal to NUMBER_POS_FRACT | NUMBER_NEG_FRACT */ + NUMBER_FRACT: 0x44, + /** Any real number. Equal to NUMBER_POS_REAL | NUMBER_ANY_ZERO | NUMBER_NEG_REAL */ + NUMBER_REAL: 0x07E, + + /** Any number, excluding NaN. Equal to NUMBER_REAL | NUMBER_INF */ + NUMBER: 0x0FF, + /** Any number, including NaN. Equal to NUMBER | NUMBER_NAN */ + NUMBER_OR_NAN: 0x1FF, + /** Anything that can be interperated as a number. Equal to NUMBER | STRING_NUM | BOOLEAN */ + NUMBER_INTERPRETABLE: 0x12FF, + + /** Any string which as a non-NaN neumeric interpretation, excluding ''. */ + STRING_NUM: 0x200, + /** Any string which has no non-NaN neumeric interpretation, including ''. */ + STRING_NAN: 0x400, + /** Either of the strings 'true' or 'false'. */ + STRING_BOOLEAN: 0x800, + + /** Any string. Equal to STRING_NUM | STRING_NAN | STRING_BOOLEAN */ + STRING: 0xE00, + + /** Any boolean. */ + BOOLEAN: 0x1000, + /** Any input that can be interperated as a boolean. Equal to BOOLEAN | STRING_BOOLEAN */ + BOOLEAN_INTERPRETABLE: 0x1800, + + /** Any type. Equal to NUMBER_OR_NAN | STRING | BOOLEAN */ + ANY: 0x1FFF +}; + +/** + * Enum for the opcodes of the stackable blocks used in the IR AST. + * @readonly + * @enum {string} + */ +const StackOpcode = { + NOP: 'noop', + + ADDON_CALL: 'addons.call', + DEBUGGER: 'tw.debugger', + VISUAL_REPORT: 'visualReport', + COMPATIBILITY_LAYER: 'compat', + + HAT_EDGE: 'hat.edge', + HAT_PREDICATE: 'hat.predicate', + + CONTROL_IF_ELSE: 'control.if', + CONTROL_CLONE_CREATE: 'control.createClone', + CONTROL_CLONE_DELETE: 'control.deleteClone', + CONTROL_WHILE: 'control.while', + CONTROL_FOR: 'control.for', + CONTROL_REPEAT: 'control.repeat', + CONTROL_STOP_ALL: 'control.stopAll', + CONTROL_STOP_OTHERS: 'control.stopOthers', + CONTROL_STOP_SCRIPT: 'control.stopScript', + CONTROL_WAIT: 'control.wait', + CONTROL_WAIT_UNTIL: 'control.waitUntil', + CONTROL_CLEAR_COUNTER: 'control.counterClear', + CONTORL_INCR_COUNTER: 'control.counterIncr', + + LIST_ADD: 'list.add', + LIST_INSERT: 'list.instert', + LIST_REPLACE: 'list.replace', + LIST_DELETE_ALL: 'list.deleteAll', + LIST_DELETE: 'list.delete', + LIST_SHOW: 'list.show', + LIST_HIDE: 'list.hide', + + VAR_SET: 'var.set', + VAR_SHOW: 'var.show', + VAR_HIDE: 'var.hide', + + EVENT_BROADCAST: 'event.broadcast', + EVENT_BROADCAST_AND_WAIT: 'event.broadcastAndWait', + + LOOKS_EFFECT_SET: 'looks.setEffect', + LOOKS_EFFECT_CHANGE: 'looks.changeEffect', + LOOKS_EFFECT_CLEAR: 'looks.clearEffects', + LOOKS_SIZE_CHANGE: 'looks.changeSize', + LOOKS_SIZE_SET: 'looks.setSize', + LOOKS_LAYER_FORWARD: 'looks.forwardLayers', + LOOKS_LAYER_BACKWARD: 'looks.backwardLayers', + LOOKS_LAYER_FRONT: 'looks.goToFront', + LOOKS_LAYER_BACK: 'looks.goToBack', + LOOKS_HIDE: 'looks.hide', + LOOKS_SHOW: 'looks.show', + LOOKS_BACKDROP_NEXT: 'looks.nextBackdrop', + LOOKS_BACKDROP_SET: 'looks.switchBackdrop', + LOOKS_COSTUME_NEXT: 'looks.nextCostume', + LOOKS_COSTUME_SET: 'looks.switchCostume', + + MOTION_X_SET: 'motion.setX', + MOTION_X_CHANGE: 'motion.changeX', + MOTION_Y_SET: 'motion.setY', + MOTION_Y_CHANGE: 'motion.changeY', + MOTION_XY_SET: 'motion.setXY', + MOTION_IF_ON_EDGE_BOUNCE: 'motion.ifOnEdgeBounce', + MOTION_STEP: 'motion.step', + MOTION_ROTATION_STYLE_SET: 'motion.setRotationStyle', + MOTION_DIRECTION_SET: 'motion.setDirection', + + PEN_UP: 'pen.up', + PEN_DOWN: 'pen.down', + PEN_CLEAR: 'pen.clear', + PEN_COLOR_PARAM_SET: 'pen.setParam', + PEN_COLOR_PARAM_CHANGE: 'pen.changeParam', + PEN_COLOR_HUE_CHANGE_LEGACY: 'pen.legacyChangeHue', + PEN_COLOR_HUE_SET_LEGACY: 'pen_setPenHueToNumber', + PEN_COLOR_SHADE_CHANGE_LEGACY: 'pen.legacyChangeShade', + PEN_COLOR_SHADE_SET_LEGACY: 'pen.legacySetShade', + PEN_COLOR_SET: 'pen.setColor', + PEN_SIZE_SET: 'pen.setSize', + PEN_SIZE_CHANGE: 'pen.changeSize', + PEN_STAMP: 'pen.stamp', + + SENSING_TIMER_RESET: 'timer.reset', + + PROCEDURE_RETURN: 'procedures.return', + PROCEDURE_CALL: 'procedures.call' +}; + +/** + * Enum for the opcodes of the reporter blocks used in the IR AST. + * @readonly + * @enum {string} + */ +const InputOpcode = { + NOP: 'noop', + + ADDON_CALL: 'addons.call', + CONSTANT: 'constant', + + CAST_NUMBER: 'cast.toNumber', + CAST_NUMBER_INDEX: 'cast.toInteger', + CAST_NUMBER_OR_NAN: 'cast.toNumberOrNaN', + CAST_STRING: 'cast.toString', + CAST_BOOLEAN: 'cast.toBoolean', + + COMPATIBILITY_LAYER: 'compat', + + LOOKS_BACKDROP_NUMBER: 'looks.backdropNumber', + LOOKS_BACKDROP_NAME: 'looks.backdropName', + LOOKS_COSTUME_NUMBER: 'looks.costumeNumber', + LOOKS_COSTUME_NAME: 'looks.costumeName', + LOOKS_SIZE_GET: 'looks.size', + + VAR_GET: 'var.get', + + LIST_GET: 'list.get', + LIST_LENGTH: 'list.length', + LIST_CONTAINS: 'list.contains', + LIST_INDEX_OF: 'list.indexOf', + LIST_CONTENTS: 'list.contents', + + MOTION_X_GET: 'motion.x', + MOTION_Y_GET: 'motion.y', + MOTION_DIRECTION_GET: 'motion.direction', + + OP_ADD: 'op.add', + OP_AND: 'op.and', + OP_CONTAINS: 'op.contains', + OP_DIVIDE: 'op.divide', + OP_EQUALS: 'op.equals', + OP_GREATER: 'op.greater', + OP_LESS: 'op.less', + OP_JOIN: 'op.join', + OP_LENGTH: 'op.length', + OP_LETTER_OF: 'op.letterOf', + OP_ABS: 'op.abs', + OP_FLOOR: 'op.floor', + OP_CEILING: 'op.ceiling', + OP_SQRT: 'op.sqrt', + OP_SIN: 'op.sin', + OP_COS: 'op.cos', + OP_TAN: 'op.tan', + OP_ASIN: 'op.asin', + OP_ACOS: 'op.acos', + OP_ATAN: 'op.atan', + OP_LOG_E: 'op.ln', + OP_LOG_10: 'op.log', + OP_POW_E: 'op.e^', + OP_POW_10: 'op.10^', + OP_MOD: 'op.mod', + OP_MULTIPLY: 'op.multiply', + OP_NOT: 'op.not', + OP_OR: 'op.or', + OP_RANDOM: 'op.random', + OP_ROUND: 'op.round', + OP_SUBTRACT: 'op.subtract', + + SENSING_ANSWER: 'sensing.answer', + SENSING_COLOR_TOUCHING_COLOR: 'sensing.colorTouchingColor', + SENSING_TIME_YEAR: 'sensing.year', + SENSING_TIME_MONTH: 'sensing.month', + SENSING_TIME_DATE: 'sensing.date', + SENSING_TIME_WEEKDAY: 'sensing.dayofweek', + SENSING_TIME_HOUR: 'sensing.hour', + SENSING_TIME_MINUTE: 'sensing.minute', + SENSING_TIME_SECOND: 'sensing.second', + SENSING_TIME_DAYS_SINCE_2000: 'sensing.daysSince2000', + SENSING_DISTANCE: 'sensing.distance', + SENSING_KEY_DOWN: 'keyboard.pressed', + SENSING_MOUSE_DOWN: 'mouse.down', + SENSING_MOUSE_X: 'mouse.x', + SENSING_MOUSE_Y: 'mouse.y', + SENSING_OF: 'sensing.of', + SENSING_OF_BACKDROP_NAME: 'sensing.of.backdropName', + SENSING_OF_BACKDROP_NUMBER: 'sensing.of.backdropNumber', + SENSING_OF_COSTUME_NAME: 'sensing.of.costumeName', + SENSING_OF_COSTUME_NUMBER: 'sensing.of.costumeNumber', + SENSING_OF_VOLUME: 'sensing.of.volume', + SENSING_OF_POS_X: 'sensing.of.x', + SENSING_OF_POS_Y: 'sensing.of.y', + SENSING_OF_DIRECTION: 'sensing.of.direction', + SENSING_OF_SIZE: 'sensing.of.size', + SENSING_OF_VAR: 'sensing.of.var', + SENSING_TIMER_GET: 'timer.get', + SENSING_TOUCHING_COLOR: 'sensing.touchingColor', + SENSING_TOUCHING_OBJECT: 'sensing.touching', + SENSING_USERNAME: 'sensing.username', + + PROCEDURE_CALL: 'procedures.call', + PROCEDURE_ARG_STRING_NUMBER: 'args.stringNumber', + PROCEDURE_ARG_BOOLEAN: 'args.boolean', + + CONTROL_COUNTER: 'control.counter', + + TW_KEY_LAST_PRESSED: 'tw.lastKeyPressed' +}; + +module.exports = { + StackOpcode, + InputOpcode, + InputType +}; diff --git a/src/compiler/environment.js b/src/compiler/environment.js index 75b300a64fe..a7b49c3155b 100644 --- a/src/compiler/environment.js +++ b/src/compiler/environment.js @@ -1,3 +1,4 @@ +// @ts-check /* eslint-disable no-eval */ /** diff --git a/src/compiler/intermediate.js b/src/compiler/intermediate.js index 9882cefc62d..dc5f4ea36d4 100644 --- a/src/compiler/intermediate.js +++ b/src/compiler/intermediate.js @@ -1,7 +1,220 @@ +// @ts-check + +const Cast = require('../util/cast'); +const {InputOpcode, InputType} = require('./enums.js'); +const log = require('../util/log'); + /** * @fileoverview Common intermediates shared amongst parts of the compiler. */ +/** + * Describes a 'stackable' block (eg. show) + */ +class IntermediateStackBlock { + /** + * @param {import("./enums").StackOpcode} opcode + * @param {Object} inputs + * @param {boolean} yields + */ + constructor (opcode, inputs = {}, yields = false) { + /** + * The type of the stackable block. + * @type {import("./enums").StackOpcode} + */ + this.opcode = opcode; + + /** + * The inputs of this block. + * @type {Object} + */ + this.inputs = inputs; + + /** + * Does this block cause a yield + * @type {boolean} + */ + this.yields = yields; + + /** + * Should state changes made by this stack block be ignored? Used for testing. + * @type {boolean} + */ + this.ignoreState = false; + + /** + * @type {import("./iroptimizer").TypeState?} + */ + this.entryState = null; + + /** + * @type {import("./iroptimizer").TypeState?} + */ + this.exitState = null; + } +} + +/** + * Describes an input to a block. + * This could be a constant, variable or math operation. + */ +class IntermediateInput { + + static getNumberInputType (number) { + if (typeof number !== 'number') throw new Error('Expected a number.'); + if (number === Infinity) return InputType.NUMBER_POS_INF; + if (number === -Infinity) return InputType.NUMBER_NEG_INF; + if (number < 0) return Number.isInteger(number) ? InputType.NUMBER_NEG_INT : InputType.NUMBER_NEG_FRACT; + if (number > 0) return Number.isInteger(number) ? InputType.NUMBER_POS_INT : InputType.NUMBER_POS_FRACT; + if (Number.isNaN(number)) return InputType.NUMBER_NAN; + if (Object.is(number, -0)) return InputType.NUMBER_NEG_ZERO; + return InputType.NUMBER_ZERO; + } + + /** + * @param {InputOpcode} opcode + * @param {InputType} type + * @param {Object} inputs + * @param {boolean} yields + */ + constructor (opcode, type, inputs = {}, yields = false) { + /** + * @type {InputOpcode} + */ + this.opcode = opcode; + + /** + * @type {InputType} + */ + this.type = type; + + /** + * @type {Object} + */ + this.inputs = inputs; + + /** + * @type {boolean} + */ + this.yields = yields; + } + + /** + * Is this input a constant whos value equals value. + * @param {*} value The value + * @returns {boolean} + */ + isConstant (value) { + if (this.opcode !== InputOpcode.CONSTANT) return false; + let equal = this.inputs.value === value; + if (!equal && typeof value === 'number') equal = (+this.inputs.value) === value; + return equal; + } + + /** + * Is the type of this input guaranteed to always be the type at runtime. + * @param {InputType} type + * @returns {boolean} + */ + isAlwaysType (type) { + return (this.type & type) === this.type; + } + + /** + * Is it possible for this input to be the type at runtime. + * @param {InputType} type + * @returns + */ + isSometimesType (type) { + return (this.type & type) !== 0; + } + + /** + * Converts this input to a target type. + * If this input is a constant the conversion is performed now, at compile time. + * If the input changes, the conversion is performed at runtime. + * @param {InputType} targetType + * @returns {IntermediateInput} An input with the new type. + */ + toType (targetType) { + let castOpcode; + switch (targetType) { + case InputType.BOOLEAN: + castOpcode = InputOpcode.CAST_BOOLEAN; + break; + case InputType.NUMBER: + castOpcode = InputOpcode.CAST_NUMBER; + break; + case InputType.NUMBER_INDEX: + castOpcode = InputOpcode.CAST_NUMBER_INDEX; + break; + case InputType.NUMBER_OR_NAN: + castOpcode = InputOpcode.CAST_NUMBER_OR_NAN; + break; + case InputType.STRING: + castOpcode = InputOpcode.CAST_STRING; + break; + default: + log.warn(`Cannot cast to type: ${targetType}`, this); + throw new Error(`Cannot cast to type: ${targetType}`); + } + + if (this.isAlwaysType(targetType)) return this; + + if (this.opcode === InputOpcode.CONSTANT) { + // If we are a constant, we can do the cast here at compile time + switch (castOpcode) { + case InputOpcode.CAST_BOOLEAN: + this.inputs.value = Cast.toBoolean(this.inputs.value); + this.type = InputType.BOOLEAN; + break; + case InputOpcode.CAST_NUMBER: + case InputOpcode.CAST_NUMBER_INDEX: + case InputOpcode.CAST_NUMBER_OR_NAN: + if (this.isAlwaysType(InputType.BOOLEAN_INTERPRETABLE)) { + this.type = InputType.NUMBER; + this.inputs.value = +Cast.toBoolean(this.inputs.value); + } + var numberValue = +this.inputs.value; + if (numberValue) { + this.inputs.value = numberValue; + } else { + // numberValue is one of 0, -0, or NaN + if (Object.is(numberValue, -0)) this.inputs.value = -0; + else this.inputs.value = 0; // Convert NaN to 0 + } + if (castOpcode === InputOpcode.CAST_NUMBER_INDEX) { + // Round numberValue to an integer + numberValue |= 0; + } + this.type = IntermediateInput.getNumberInputType(this.inputs.value); + break; + case InputOpcode.CAST_STRING: + this.inputs.value += ''; + this.type = InputType.STRING; + break; + } + return this; + } + + return new IntermediateInput(castOpcode, targetType, {target: this}); + } +} + +/** + * A 'stack' of blocks, like the contents of a script or the inside + * of a C block. + */ +class IntermediateStack { + /** + * @param {IntermediateStackBlock[]} [blocks] + */ + constructor (blocks) { + /** @type {IntermediateStackBlock[]} */ + this.blocks = blocks ?? []; + } +} + /** * An IntermediateScript describes a single script. * Scripts do not necessarily have hats. @@ -10,13 +223,13 @@ class IntermediateScript { constructor () { /** * The ID of the top block of this script. - * @type {string} + * @type {string?} */ this.topBlockId = null; /** * List of nodes that make up this script. - * @type {Array|null} + * @type {IntermediateStack?} */ this.stack = null; @@ -26,12 +239,6 @@ class IntermediateScript { */ this.isProcedure = false; - /** - * This procedure's variant, if any. - * @type {string} - */ - this.procedureVariant = ''; - /** * This procedure's code, if any. * @type {string} @@ -76,11 +283,18 @@ class IntermediateScript { */ this.cachedCompileResult = null; + /** + * Cached result of analysing this script. + * @type {import("./iroptimizer").TypeState|null} + */ + this.cachedAnalysisEndState = null; + /** * Whether the top block of this script is an executable hat. * @type {boolean} */ this.executableHat = false; + } } @@ -88,22 +302,39 @@ class IntermediateScript { * An IntermediateRepresentation contains scripts. */ class IntermediateRepresentation { - constructor () { + /** + * + * @param {IntermediateScript} entry + * @param {Object.} procedures + */ + constructor (entry, procedures) { /** * The entry point of this IR. * @type {IntermediateScript} */ - this.entry = null; + this.entry = entry; /** * Maps procedure variants to their intermediate script. * @type {Object.} */ - this.procedures = {}; + this.procedures = procedures; + } + + /** + * Gets the first procedure with the given proccode. + * @param {string} proccode + * @returns {IntermediateScript | undefined} + */ + getProcedure (proccode) { + return Object.values(this.procedures).find(procedure => procedure.procedureCode === proccode); } } module.exports = { + IntermediateStackBlock, + IntermediateInput, + IntermediateStack, IntermediateScript, IntermediateRepresentation }; diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 39707ef5c6c..91a576db301 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -1,10 +1,13 @@ +// @ts-check + const Cast = require('../util/cast'); const StringUtil = require('../util/string-util'); const BlockType = require('../extension-support/block-type'); const Variable = require('../engine/variable'); const log = require('../util/log'); -const {IntermediateScript, IntermediateRepresentation} = require('./intermediate'); +const {IntermediateStackBlock, IntermediateInput, IntermediateStack, IntermediateScript, IntermediateRepresentation} = require('./intermediate'); const compatBlocks = require('./compat-blocks'); +const {StackOpcode, InputOpcode, InputType} = require('./enums.js'); /** * @fileoverview Generate intermediate representations from Scratch blocks. @@ -13,11 +16,6 @@ const compatBlocks = require('./compat-blocks'); const SCALAR_TYPE = ''; const LIST_TYPE = 'list'; -/** - * @typedef {Object.} Node - * @property {string} kind - */ - /** * Create a variable codegen object. * @param {'target'|'stage'} scope The scope of this variable -- which object owns it. @@ -82,12 +80,24 @@ class ScriptTreeGenerator { this.variableCache = {}; this.usesTimer = false; + + this.namesOfCostumesAndSounds = new Set(); + for (const target of this.runtime.targets) { + if (target.isOriginal) { + const sprite = target.sprite; + for (const costume of sprite.costumes) { + this.namesOfCostumesAndSounds.add(costume.name); + } + for (const sound of sprite.sounds) { + this.namesOfCostumesAndSounds.add(sound.name); + } + } + } } setProcedureVariant (procedureVariant) { const procedureCode = parseProcedureCode(procedureVariant); - this.script.procedureVariant = procedureVariant; this.script.procedureCode = procedureCode; this.script.isProcedure = true; this.script.yields = false; @@ -126,63 +136,76 @@ class ScriptTreeGenerator { return blockInfo; } + createConstantInput (constant, preserveStrings = false) { + if (constant == null) throw new Error('IR: Constant cannot have a null value.'); + + constant += ''; + const numConstant = +constant; + const preserve = preserveStrings && this.namesOfCostumesAndSounds.has(constant); + + if (!Number.isNaN(numConstant) && (constant.trim() !== '' || constant.includes('\t'))) { + if (!preserve && numConstant.toString() === constant) { + return new IntermediateInput(InputOpcode.CONSTANT, IntermediateInput.getNumberInputType(numConstant), {value: numConstant}); + } + return new IntermediateInput(InputOpcode.CONSTANT, InputType.STRING_NUM, {value: constant}); + } + + if (!preserve) { + if (constant === 'true') { + return new IntermediateInput(InputOpcode.CONSTANT, InputType.STRING_BOOLEAN, {value: constant}); + } else if (constant === 'false') { + return new IntermediateInput(InputOpcode.CONSTANT, InputType.STRING_BOOLEAN, {value: constant}); + } + } + + return new IntermediateInput(InputOpcode.CONSTANT, InputType.STRING_NAN, {value: constant}); + } + /** * Descend into a child input of a block. (eg. the input STRING of "length of ( )") * @param {*} parentBlock The parent Scratch block that contains the input. * @param {string} inputName The name of the input to descend into. + * @param {boolean} preserveStrings Should this input keep the names of costumes and sounds at strings. * @private - * @returns {Node} Compiled input node for this input. + * @returns {IntermediateInput} Compiled input node for this input. */ - descendInputOfBlock (parentBlock, inputName) { + descendInputOfBlock (parentBlock, inputName, preserveStrings = false) { const input = parentBlock.inputs[inputName]; if (!input) { log.warn(`IR: ${parentBlock.opcode}: missing input ${inputName}`, parentBlock); - return { - kind: 'constant', - value: 0 - }; + return this.createConstantInput(0); } const inputId = input.block; const block = this.getBlockById(inputId); if (!block) { log.warn(`IR: ${parentBlock.opcode}: could not find input ${inputName} with ID ${inputId}`); - return { - kind: 'constant', - value: 0 - }; + return this.createConstantInput(0); } - return this.descendInput(block); + const intermediate = this.descendInput(block, preserveStrings); + this.script.yields = this.script.yields || intermediate.yields; + return intermediate; } /** * Descend into an input. (eg. "length of ( )") * @param {*} block The parent Scratch block input. + * @param {boolean} preserveStrings Should this input keep the names of costumes and sounds at strings. * @private - * @returns {Node} Compiled input node for this input. + * @returns {IntermediateInput} Compiled input node for this input. */ - descendInput (block) { + descendInput (block, preserveStrings = false) { switch (block.opcode) { case 'colour_picker': - return { - kind: 'constant', - value: block.fields.COLOUR.value - }; + return this.createConstantInput(block.fields.COLOUR.value, true); case 'math_angle': case 'math_integer': case 'math_number': case 'math_positive_number': case 'math_whole_number': - return { - kind: 'constant', - value: block.fields.NUM.value - }; + return this.createConstantInput(block.fields.NUM.value, preserveStrings); case 'text': - return { - kind: 'constant', - value: block.fields.TEXT.value - }; - + return this.createConstantInput(block.fields.TEXT.value, preserveStrings); case 'argument_reporter_string_number': { const name = block.fields.VALUE.value; // lastIndexOf because multiple parameters with the same name will use the value of the last definition @@ -190,21 +213,13 @@ class ScriptTreeGenerator { if (index === -1) { // Legacy support if (name.toLowerCase() === 'last key pressed') { - return { - kind: 'tw.lastKeyPressed' - }; + return new IntermediateInput(InputOpcode.TW_KEY_LAST_PRESSED, InputType.STRING); } } if (index === -1) { - return { - kind: 'constant', - value: 0 - }; + return this.createConstantInput(0); } - return { - kind: 'args.stringNumber', - index: index - }; + return new IntermediateInput(InputOpcode.PROCEDURE_ARG_STRING_NUMBER, InputType.ANY, {index}); } case 'argument_reporter_boolean': { // see argument_reporter_string_number above @@ -212,460 +227,343 @@ class ScriptTreeGenerator { const index = this.script.arguments.lastIndexOf(name); if (index === -1) { if (name.toLowerCase() === 'is compiled?' || name.toLowerCase() === 'is turbowarp?') { - return { - kind: 'constant', - value: true - }; + return this.createConstantInput(true).toType(InputType.BOOLEAN); } - return { - kind: 'constant', - value: 0 - }; + return this.createConstantInput(0); } - return { - kind: 'args.boolean', - index: index - }; + return new IntermediateInput(InputOpcode.PROCEDURE_ARG_BOOLEAN, InputType.BOOLEAN, {index}); } - case 'control_get_counter': - return { - kind: 'counter.get' - }; - case 'data_variable': - return { - kind: 'var.get', + return new IntermediateInput(InputOpcode.VAR_GET, InputType.ANY, { variable: this.descendVariable(block, 'VARIABLE', SCALAR_TYPE) - }; + }); case 'data_itemoflist': - return { - kind: 'list.get', + return new IntermediateInput(InputOpcode.LIST_GET, InputType.ANY, { list: this.descendVariable(block, 'LIST', LIST_TYPE), index: this.descendInputOfBlock(block, 'INDEX') - }; + }); case 'data_lengthoflist': - return { - kind: 'list.length', + return new IntermediateInput(InputOpcode.LIST_LENGTH, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO, { list: this.descendVariable(block, 'LIST', LIST_TYPE) - }; + }); case 'data_listcontainsitem': - return { - kind: 'list.contains', + return new IntermediateInput(InputOpcode.LIST_CONTAINS, InputType.BOOLEAN, { list: this.descendVariable(block, 'LIST', LIST_TYPE), item: this.descendInputOfBlock(block, 'ITEM') - }; + }); case 'data_itemnumoflist': - return { - kind: 'list.indexOf', + return new IntermediateInput(InputOpcode.LIST_INDEX_OF, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO, { list: this.descendVariable(block, 'LIST', LIST_TYPE), item: this.descendInputOfBlock(block, 'ITEM') - }; + }); case 'data_listcontents': - return { - kind: 'list.contents', + return new IntermediateInput(InputOpcode.LIST_CONTENTS, InputType.STRING, { list: this.descendVariable(block, 'LIST', LIST_TYPE) - }; + }); case 'event_broadcast_menu': { const broadcastOption = block.fields.BROADCAST_OPTION; const broadcastVariable = this.target.lookupBroadcastMsg(broadcastOption.id, broadcastOption.value); // TODO: empty string probably isn't the correct fallback const broadcastName = broadcastVariable ? broadcastVariable.name : ''; - return { - kind: 'constant', - value: broadcastName - }; + return this.createConstantInput(broadcastName); } case 'looks_backdropnumbername': if (block.fields.NUMBER_NAME.value === 'number') { - return { - kind: 'looks.backdropNumber' - }; + return new IntermediateInput(InputOpcode.LOOKS_BACKDROP_NUMBER, InputType.NUMBER_POS_REAL); } - return { - kind: 'looks.backdropName' - }; + return new IntermediateInput(InputOpcode.LOOKS_BACKDROP_NAME, InputType.STRING); case 'looks_costumenumbername': if (block.fields.NUMBER_NAME.value === 'number') { - return { - kind: 'looks.costumeNumber' - }; + return new IntermediateInput(InputOpcode.LOOKS_COSTUME_NUMBER, InputType.NUMBER_POS_REAL); } - return { - kind: 'looks.costumeName' - }; + return new IntermediateInput(InputOpcode.LOOKS_COSTUME_NAME, InputType.STRING); case 'looks_size': - return { - kind: 'looks.size' - }; + return new IntermediateInput(InputOpcode.LOOKS_SIZE_GET, InputType.NUMBER_POS_REAL); case 'motion_direction': - return { - kind: 'motion.direction' - }; + return new IntermediateInput(InputOpcode.MOTION_DIRECTION_GET, InputType.NUMBER_REAL); case 'motion_xposition': - return { - kind: 'motion.x' - }; + return new IntermediateInput(InputOpcode.MOTION_X_GET, InputType.NUMBER_REAL); case 'motion_yposition': - return { - kind: 'motion.y' - }; + return new IntermediateInput(InputOpcode.MOTION_Y_GET, InputType.NUMBER_REAL); case 'operator_add': - return { - kind: 'op.add', - left: this.descendInputOfBlock(block, 'NUM1'), - right: this.descendInputOfBlock(block, 'NUM2') - }; + return new IntermediateInput(InputOpcode.OP_ADD, InputType.NUMBER_OR_NAN, { + left: this.descendInputOfBlock(block, 'NUM1').toType(InputType.NUMBER), + right: this.descendInputOfBlock(block, 'NUM2').toType(InputType.NUMBER) + }); case 'operator_and': - return { - kind: 'op.and', - left: this.descendInputOfBlock(block, 'OPERAND1'), - right: this.descendInputOfBlock(block, 'OPERAND2') - }; + return new IntermediateInput(InputOpcode.OP_AND, InputType.BOOLEAN, { + left: this.descendInputOfBlock(block, 'OPERAND1').toType(InputType.BOOLEAN), + right: this.descendInputOfBlock(block, 'OPERAND2').toType(InputType.BOOLEAN) + }); case 'operator_contains': - return { - kind: 'op.contains', - string: this.descendInputOfBlock(block, 'STRING1'), - contains: this.descendInputOfBlock(block, 'STRING2') - }; + return new IntermediateInput(InputOpcode.OP_CONTAINS, InputType.BOOLEAN, { + string: this.descendInputOfBlock(block, 'STRING1').toType(InputType.STRING), + contains: this.descendInputOfBlock(block, 'STRING2').toType(InputType.STRING) + }); case 'operator_divide': - return { - kind: 'op.divide', - left: this.descendInputOfBlock(block, 'NUM1'), - right: this.descendInputOfBlock(block, 'NUM2') - }; + return new IntermediateInput(InputOpcode.OP_DIVIDE, InputType.NUMBER_OR_NAN, { + left: this.descendInputOfBlock(block, 'NUM1').toType(InputType.NUMBER), + right: this.descendInputOfBlock(block, 'NUM2').toType(InputType.NUMBER) + }); case 'operator_equals': - return { - kind: 'op.equals', + return new IntermediateInput(InputOpcode.OP_EQUALS, InputType.BOOLEAN, { left: this.descendInputOfBlock(block, 'OPERAND1'), right: this.descendInputOfBlock(block, 'OPERAND2') - }; + }); case 'operator_gt': - return { - kind: 'op.greater', + return new IntermediateInput(InputOpcode.OP_GREATER, InputType.BOOLEAN, { left: this.descendInputOfBlock(block, 'OPERAND1'), right: this.descendInputOfBlock(block, 'OPERAND2') - }; + }); case 'operator_join': - return { - kind: 'op.join', - left: this.descendInputOfBlock(block, 'STRING1'), - right: this.descendInputOfBlock(block, 'STRING2') - }; + return new IntermediateInput(InputOpcode.OP_JOIN, InputType.STRING, { + left: this.descendInputOfBlock(block, 'STRING1').toType(InputType.STRING), + right: this.descendInputOfBlock(block, 'STRING2').toType(InputType.STRING) + }); case 'operator_length': - return { - kind: 'op.length', - string: this.descendInputOfBlock(block, 'STRING') - }; + return new IntermediateInput(InputOpcode.OP_LENGTH, InputType.NUMBER_REAL, { + string: this.descendInputOfBlock(block, 'STRING').toType(InputType.STRING) + }); case 'operator_letter_of': - return { - kind: 'op.letterOf', - letter: this.descendInputOfBlock(block, 'LETTER'), - string: this.descendInputOfBlock(block, 'STRING') - }; + return new IntermediateInput(InputOpcode.OP_LETTER_OF, InputType.STRING, { + letter: this.descendInputOfBlock(block, 'LETTER').toType(InputType.NUMBER_INDEX), + string: this.descendInputOfBlock(block, 'STRING').toType(InputType.STRING) + }); case 'operator_lt': - return { - kind: 'op.less', + return new IntermediateInput(InputOpcode.OP_LESS, InputType.BOOLEAN, { left: this.descendInputOfBlock(block, 'OPERAND1'), right: this.descendInputOfBlock(block, 'OPERAND2') - }; + }); case 'operator_mathop': { - const value = this.descendInputOfBlock(block, 'NUM'); + const value = this.descendInputOfBlock(block, 'NUM').toType(InputType.NUMBER); const operator = block.fields.OPERATOR.value.toLowerCase(); switch (operator) { - case 'abs': return { - kind: 'op.abs', - value - }; - case 'floor': return { - kind: 'op.floor', - value - }; - case 'ceiling': return { - kind: 'op.ceiling', - value - }; - case 'sqrt': return { - kind: 'op.sqrt', - value - }; - case 'sin': return { - kind: 'op.sin', - value - }; - case 'cos': return { - kind: 'op.cos', - value - }; - case 'tan': return { - kind: 'op.tan', - value - }; - case 'asin': return { - kind: 'op.asin', - value - }; - case 'acos': return { - kind: 'op.acos', - value - }; - case 'atan': return { - kind: 'op.atan', - value - }; - case 'ln': return { - kind: 'op.ln', - value - }; - case 'log': return { - kind: 'op.log', - value - }; - case 'e ^': return { - kind: 'op.e^', - value - }; - case '10 ^': return { - kind: 'op.10^', - value - }; - default: return { - kind: 'constant', - value: 0 - }; + case 'abs': return new IntermediateInput(InputOpcode.OP_ABS, InputType.NUMBER_POS | InputType.NUMBER_ZERO, {value}); + case 'floor': return new IntermediateInput(InputOpcode.OP_FLOOR, InputType.NUMBER, {value}); + case 'ceiling': return new IntermediateInput(InputOpcode.OP_CEILING, InputType.NUMBER, {value}); + case 'sqrt': return new IntermediateInput(InputOpcode.OP_SQRT, InputType.NUMBER_OR_NAN, {value}); + case 'sin': return new IntermediateInput(InputOpcode.OP_SIN, InputType.NUMBER_OR_NAN, {value}); + case 'cos': return new IntermediateInput(InputOpcode.OP_COS, InputType.NUMBER_OR_NAN, {value}); + case 'tan': return new IntermediateInput(InputOpcode.OP_TAN, InputType.NUMBER_OR_NAN, {value}); + case 'asin': return new IntermediateInput(InputOpcode.OP_ASIN, InputType.NUMBER_OR_NAN, {value}); + case 'acos': return new IntermediateInput(InputOpcode.OP_ACOS, InputType.NUMBER_OR_NAN, {value}); + case 'atan': return new IntermediateInput(InputOpcode.OP_ATAN, InputType.NUMBER, {value}); + case 'ln': return new IntermediateInput(InputOpcode.OP_LOG_E, InputType.NUMBER_OR_NAN, {value}); + case 'log': return new IntermediateInput(InputOpcode.OP_LOG_10, InputType.NUMBER_OR_NAN, {value}); + case 'e ^': return new IntermediateInput(InputOpcode.OP_POW_E, InputType.NUMBER, {value}); + case '10 ^': return new IntermediateInput(InputOpcode.OP_POW_10, InputType.NUMBER, {value}); + default: this.createConstantInput(0); } } case 'operator_mod': - return { - kind: 'op.mod', - left: this.descendInputOfBlock(block, 'NUM1'), - right: this.descendInputOfBlock(block, 'NUM2') - }; + return new IntermediateInput(InputOpcode.OP_MOD, InputType.NUMBER_OR_NAN, { + left: this.descendInputOfBlock(block, 'NUM1').toType(InputType.NUMBER), + right: this.descendInputOfBlock(block, 'NUM2').toType(InputType.NUMBER) + }); case 'operator_multiply': - return { - kind: 'op.multiply', - left: this.descendInputOfBlock(block, 'NUM1'), - right: this.descendInputOfBlock(block, 'NUM2') - }; + return new IntermediateInput(InputOpcode.OP_MULTIPLY, InputType.NUMBER_OR_NAN, { + left: this.descendInputOfBlock(block, 'NUM1').toType(InputType.NUMBER), + right: this.descendInputOfBlock(block, 'NUM2').toType(InputType.NUMBER) + }); case 'operator_not': - return { - kind: 'op.not', - operand: this.descendInputOfBlock(block, 'OPERAND') - }; + return new IntermediateInput(InputOpcode.OP_NOT, InputType.BOOLEAN, { + operand: this.descendInputOfBlock(block, 'OPERAND').toType(InputType.BOOLEAN) + }); case 'operator_or': - return { - kind: 'op.or', - left: this.descendInputOfBlock(block, 'OPERAND1'), - right: this.descendInputOfBlock(block, 'OPERAND2') - }; + return new IntermediateInput(InputOpcode.OP_OR, InputType.BOOLEAN, { + left: this.descendInputOfBlock(block, 'OPERAND1').toType(InputType.BOOLEAN), + right: this.descendInputOfBlock(block, 'OPERAND2').toType(InputType.BOOLEAN) + }); case 'operator_random': { const from = this.descendInputOfBlock(block, 'FROM'); const to = this.descendInputOfBlock(block, 'TO'); // If both values are known at compile time, we can do some optimizations. // TODO: move optimizations to jsgen? - if (from.kind === 'constant' && to.kind === 'constant') { - const sFrom = from.value; - const sTo = to.value; + if (from.opcode === InputOpcode.CONSTANT && to.opcode === InputOpcode.CONSTANT) { + const sFrom = from.inputs.value; + const sTo = to.inputs.value; const nFrom = Cast.toNumber(sFrom); const nTo = Cast.toNumber(sTo); // If both numbers are the same, random is unnecessary. // todo: this probably never happens so consider removing if (nFrom === nTo) { - return { - kind: 'constant', - value: nFrom - }; + return this.createConstantInput(nFrom); } // If both are ints, hint this to the compiler if (Cast.isInt(sFrom) && Cast.isInt(sTo)) { - return { - kind: 'op.random', - low: nFrom <= nTo ? from : to, - high: nFrom <= nTo ? to : from, + // Both inputs are ints, so we know neither are NaN + return new IntermediateInput(InputOpcode.OP_RANDOM, InputType.NUMBER, { + low: (nFrom <= nTo ? from : to).toType(InputType.NUMBER), + high: (nFrom <= nTo ? to : from).toType(InputType.NUMBER), useInts: true, useFloats: false - }; + }); } // Otherwise hint that these are floats - return { - kind: 'op.random', - low: nFrom <= nTo ? from : to, - high: nFrom <= nTo ? to : from, + return new IntermediateInput(InputOpcode.OP_RANDOM, InputType.NUMBER_OR_NAN, { + low: (nFrom <= nTo ? from : to).toType(InputType.NUMBER), + high: (nFrom <= nTo ? to : from).toType(InputType.NUMBER), useInts: false, useFloats: true - }; - } else if (from.kind === 'constant') { + }); + } else if (from.opcode === InputOpcode.CONSTANT) { // If only one value is known at compile-time, we can still attempt some optimizations. - if (!Cast.isInt(Cast.toNumber(from.value))) { - return { - kind: 'op.random', - low: from, - high: to, + if (!Cast.isInt(Cast.toNumber(from.inputs.value))) { + return new IntermediateInput(InputOpcode.OP_RANDOM, InputType.NUMBER_OR_NAN, { + low: from.toType(InputType.NUMBER), + high: to.toType(InputType.NUMBER), useInts: false, useFloats: true - }; + }); } - } else if (to.kind === 'constant') { - if (!Cast.isInt(Cast.toNumber(to.value))) { - return { - kind: 'op.random', - low: from, - high: to, + } else if (to.opcode === InputOpcode.CONSTANT) { + if (!Cast.isInt(Cast.toNumber(from.inputs.value))) { + return new IntermediateInput(InputOpcode.OP_RANDOM, InputType.NUMBER_OR_NAN, { + low: from.toType(InputType.NUMBER), + high: to.toType(InputType.NUMBER), useInts: false, useFloats: true - }; + }); } } // No optimizations possible - return { - kind: 'op.random', + return new IntermediateInput(InputOpcode.OP_RANDOM, InputType.NUMBER_OR_NAN, { low: from, high: to, useInts: false, useFloats: false - }; + }); } case 'operator_round': - return { - kind: 'op.round', - value: this.descendInputOfBlock(block, 'NUM') - }; + return new IntermediateInput(InputOpcode.OP_ROUND, InputType.NUMBER, { + value: this.descendInputOfBlock(block, 'NUM').toType(InputType.NUMBER) + }); case 'operator_subtract': - return { - kind: 'op.subtract', - left: this.descendInputOfBlock(block, 'NUM1'), - right: this.descendInputOfBlock(block, 'NUM2') - }; + return new IntermediateInput(InputOpcode.OP_SUBTRACT, InputType.NUMBER_OR_NAN, { + left: this.descendInputOfBlock(block, 'NUM1').toType(InputType.NUMBER), + right: this.descendInputOfBlock(block, 'NUM2').toType(InputType.NUMBER) + }); - case 'procedures_call': - return this.descendProcedure(block); + case 'procedures_call': { + const procedureInfo = this.getProcedureInfo(block); + return new IntermediateInput(procedureInfo.opcode, InputType.ANY, procedureInfo.inputs, procedureInfo.yields); + } case 'sensing_answer': - return { - kind: 'sensing.answer' - }; + return new IntermediateInput(InputOpcode.SENSING_ANSWER, InputType.STRING); + case 'sensing_coloristouchingcolor': - return { - kind: 'sensing.colorTouchingColor', + return new IntermediateInput(InputOpcode.SENSING_COLOR_TOUCHING_COLOR, InputType.BOOLEAN, { target: this.descendInputOfBlock(block, 'COLOR2'), mask: this.descendInputOfBlock(block, 'COLOR') - }; + }); case 'sensing_current': switch (block.fields.CURRENTMENU.value.toLowerCase()) { - case 'year': - return { - kind: 'sensing.year' - }; - case 'month': - return { - kind: 'sensing.month' - }; - case 'date': - return { - kind: 'sensing.date' - }; - case 'dayofweek': - return { - kind: 'sensing.dayofweek' - }; - case 'hour': - return { - kind: 'sensing.hour' - }; - case 'minute': - return { - kind: 'sensing.minute' - }; - case 'second': - return { - kind: 'sensing.second' - }; + case 'year': return new IntermediateInput(InputOpcode.SENSING_TIME_YEAR, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); + case 'month': return new IntermediateInput(InputOpcode.SENSING_TIME_MONTH, InputType.NUMBER_POS_REAL); + case 'date': return new IntermediateInput(InputOpcode.SENSING_TIME_DATE, InputType.NUMBER_POS_REAL); + case 'dayofweek': return new IntermediateInput(InputOpcode.SENSING_TIME_WEEKDAY, InputType.NUMBER_POS_REAL); + case 'hour': return new IntermediateInput(InputOpcode.SENSING_TIME_HOUR, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); + case 'minute': return new IntermediateInput(InputOpcode.SENSING_TIME_MINUTE, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); + case 'second': return new IntermediateInput(InputOpcode.SENSING_TIME_SECOND, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); + default: return this.createConstantInput(0); } - return { - kind: 'constant', - value: 0 - }; case 'sensing_dayssince2000': - return { - kind: 'sensing.daysSince2000' - }; + return new IntermediateInput(InputOpcode.SENSING_TIME_DAYS_SINCE_2000, InputType.NUMBER); case 'sensing_distanceto': - return { - kind: 'sensing.distance', - target: this.descendInputOfBlock(block, 'DISTANCETOMENU') - }; + return new IntermediateInput(InputOpcode.SENSING_DISTANCE, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO, { + target: this.descendInputOfBlock(block, 'DISTANCETOMENU').toType(InputType.STRING) + }); case 'sensing_keypressed': - return { - kind: 'keyboard.pressed', - key: this.descendInputOfBlock(block, 'KEY_OPTION') - }; + return new IntermediateInput(InputOpcode.SENSING_KEY_DOWN, InputType.BOOLEAN, { + key: this.descendInputOfBlock(block, 'KEY_OPTION', true) + }); case 'sensing_mousedown': - return { - kind: 'mouse.down' - }; + return new IntermediateInput(InputOpcode.SENSING_MOUSE_DOWN, InputType.BOOLEAN); case 'sensing_mousex': - return { - kind: 'mouse.x' - }; + return new IntermediateInput(InputOpcode.SENSING_MOUSE_X, InputType.NUMBER); case 'sensing_mousey': - return { - kind: 'mouse.y' - }; + return new IntermediateInput(InputOpcode.SENSING_MOUSE_Y, InputType.NUMBER); case 'sensing_of': - return { - kind: 'sensing.of', - property: block.fields.PROPERTY.value, - object: this.descendInputOfBlock(block, 'OBJECT') - }; + const property = block.fields.PROPERTY.value; + const object = this.descendInputOfBlock(block, 'OBJECT').toType(InputType.STRING); + + if (object.opcode !== InputOpcode.CONSTANT) { + return new IntermediateInput(InputOpcode.SENSING_OF, InputType.ANY, {object, property}); + } + + if (property === 'volume') { + return new IntermediateInput(InputOpcode.SENSING_OF_VOLUME, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO, {object, property}); + } + + if (object.isConstant('_stage_')) { + switch (property) { + case 'background #': // fallthrough for scratch 1.0 compatibility + case 'backdrop #': + return new IntermediateInput(InputOpcode.SENSING_OF_BACKDROP_NUMBER, InputType.NUMBER_POS_REAL); + case 'backdrop name': + return new IntermediateInput(InputOpcode.SENSING_OF_BACKDROP_NAME, InputType.STRING); + } + } else { + switch (property) { + case 'x position': + return new IntermediateInput(InputOpcode.SENSING_OF_POS_X, InputType.NUMBER_REAL, {object}); + case 'y position': + return new IntermediateInput(InputOpcode.SENSING_OF_POS_Y, InputType.NUMBER_REAL, {object}); + case 'direction': + return new IntermediateInput(InputOpcode.SENSING_OF_DIRECTION, InputType.NUMBER_REAL, {object}); + case 'costume #': + return new IntermediateInput(InputOpcode.SENSING_OF_COSTUME_NUMBER, InputType.NUMBER_POS_REAL, {object}); + case 'costume name': + return new IntermediateInput(InputOpcode.SENSING_OF_COSTUME_NAME, InputType.STRING, {object}); + case 'size': + return new IntermediateInput(InputOpcode.SENSING_OF_SIZE, InputType.NUMBER_POS_REAL, {object}); + } + } + + return new IntermediateInput(InputOpcode.SENSING_OF_VAR, InputType.ANY, {object, property}); case 'sensing_timer': this.usesTimer = true; - return { - kind: 'timer.get' - }; + return new IntermediateInput(InputOpcode.SENSING_TIMER_GET, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); case 'sensing_touchingcolor': - return { - kind: 'sensing.touchingColor', - color: this.descendInputOfBlock(block, 'COLOR') - }; + return new IntermediateInput(InputOpcode.SENSING_TOUCHING_COLOR, InputType.BOOLEAN, { + color: this.descendInputOfBlock(block, 'COLOR').toType(InputType.NUMBER) + }); case 'sensing_touchingobject': - return { - kind: 'sensing.touching', + return new IntermediateInput(InputOpcode.SENSING_TOUCHING_OBJECT, InputType.BOOLEAN, { object: this.descendInputOfBlock(block, 'TOUCHINGOBJECTMENU') - }; + }); case 'sensing_username': - return { - kind: 'sensing.username' - }; + return new IntermediateInput(InputOpcode.SENSING_USERNAME, InputType.STRING); case 'sound_sounds_menu': // This menu is special compared to other menus -- it actually has an opcode function. - return { - kind: 'constant', - value: block.fields.SOUND_MENU.value - }; + return this.createConstantInput(block.fields.SOUND_MENU.value); + + case 'control_get_counter': + return new IntermediateInput(InputOpcode.CONTROL_COUNTER, InputType.NUMBER_POS_INT | InputType.NUMBER_ZERO); case 'tw_getLastKeyPressed': - return { - kind: 'tw.lastKeyPressed' - }; + return new IntermediateInput(InputOpcode.TW_KEY_LAST_PRESSED, InputType.STRING); default: { const opcodeFunction = this.runtime.getOpcodeFunction(block.opcode); if (opcodeFunction) { // It might be a non-compiled primitive from a standard category if (compatBlocks.inputs.includes(block.opcode)) { - return this.descendCompatLayer(block); + return this.descendCompatLayerInput(block); } // It might be an extension block. const blockInfo = this.getBlockInfo(block.opcode); if (blockInfo) { const type = blockInfo.info.blockType; if (type === BlockType.REPORTER || type === BlockType.BOOLEAN) { - return this.descendCompatLayer(block); + return this.descendCompatLayerInput(block); } } } @@ -674,10 +572,7 @@ class ScriptTreeGenerator { const inputs = Object.keys(block.inputs); const fields = Object.keys(block.fields); if (inputs.length === 0 && fields.length === 1) { - return { - kind: 'constant', - value: block.fields[fields[0]].value - }; + return this.createConstantInput(block.fields[fields[0]].value); } log.warn(`IR: Unknown input: ${block.opcode}`, block); @@ -690,477 +585,356 @@ class ScriptTreeGenerator { * Descend into a stacked block. (eg. "move ( ) steps") * @param {*} block The Scratch block to parse. * @private - * @returns {Node} Compiled node for this block. + * @returns {IntermediateStackBlock} Compiled node for this block. */ descendStackedBlock (block) { switch (block.opcode) { case 'control_all_at_once': // In Scratch 3, this block behaves like "if 1 = 1" - return { - kind: 'control.if', - condition: { - kind: 'constant', - value: true - }, + return new IntermediateStackBlock(StackOpcode.CONTROL_IF_ELSE, { + condition: this.createConstantInput(true).toType(InputType.BOOLEAN), whenTrue: this.descendSubstack(block, 'SUBSTACK'), - whenFalse: [] - }; - case 'control_clear_counter': - return { - kind: 'counter.clear' - }; + whenFalse: new IntermediateStack() + }); case 'control_create_clone_of': - return { - kind: 'control.createClone', - target: this.descendInputOfBlock(block, 'CLONE_OPTION') - }; + return new IntermediateStackBlock(StackOpcode.CONTROL_CLONE_CREATE, { + target: this.descendInputOfBlock(block, 'CLONE_OPTION').toType(InputType.STRING) + }); case 'control_delete_this_clone': - this.script.yields = true; - return { - kind: 'control.deleteClone' - }; + return new IntermediateStackBlock(StackOpcode.CONTROL_CLONE_DELETE, {}, true); case 'control_forever': - this.analyzeLoop(); - return { - kind: 'control.while', - condition: { - kind: 'constant', - value: true - }, + return new IntermediateStackBlock(StackOpcode.CONTROL_WHILE, { + condition: this.createConstantInput(true).toType(InputType.BOOLEAN), do: this.descendSubstack(block, 'SUBSTACK') - }; + }, this.analyzeLoop()); case 'control_for_each': - this.analyzeLoop(); - return { - kind: 'control.for', + return new IntermediateStackBlock(StackOpcode.CONTROL_FOR, { variable: this.descendVariable(block, 'VARIABLE', SCALAR_TYPE), - count: this.descendInputOfBlock(block, 'VALUE'), + count: this.descendInputOfBlock(block, 'VALUE').toType(InputType.NUMBER), do: this.descendSubstack(block, 'SUBSTACK') - }; + }, this.analyzeLoop()); case 'control_if': - return { - kind: 'control.if', - condition: this.descendInputOfBlock(block, 'CONDITION'), + return new IntermediateStackBlock(StackOpcode.CONTROL_IF_ELSE, { + condition: this.descendInputOfBlock(block, 'CONDITION').toType(InputType.BOOLEAN), whenTrue: this.descendSubstack(block, 'SUBSTACK'), - whenFalse: [] - }; + whenFalse: new IntermediateStack() + }); case 'control_if_else': - return { - kind: 'control.if', - condition: this.descendInputOfBlock(block, 'CONDITION'), + return new IntermediateStackBlock(StackOpcode.CONTROL_IF_ELSE, { + condition: this.descendInputOfBlock(block, 'CONDITION').toType(InputType.BOOLEAN), whenTrue: this.descendSubstack(block, 'SUBSTACK'), whenFalse: this.descendSubstack(block, 'SUBSTACK2') - }; - case 'control_incr_counter': - return { - kind: 'counter.increment' - }; + }); case 'control_repeat': - this.analyzeLoop(); - return { - kind: 'control.repeat', - times: this.descendInputOfBlock(block, 'TIMES'), + return new IntermediateStackBlock(StackOpcode.CONTROL_REPEAT, { + times: this.descendInputOfBlock(block, 'TIMES').toType(InputType.NUMBER), do: this.descendSubstack(block, 'SUBSTACK') - }; + }, this.analyzeLoop()); case 'control_repeat_until': { - this.analyzeLoop(); // Dirty hack: automatically enable warp timer for this block if it uses timer // This fixes project that do things like "repeat until timer > 0.5" this.usesTimer = false; const condition = this.descendInputOfBlock(block, 'CONDITION'); const needsWarpTimer = this.usesTimer; - if (needsWarpTimer) { - this.script.yields = true; - } - return { - kind: 'control.while', - condition: { - kind: 'op.not', + return new IntermediateStackBlock(StackOpcode.CONTROL_WHILE, { + condition: new IntermediateInput(InputOpcode.OP_NOT, InputType.BOOLEAN, { operand: condition - }, + }), do: this.descendSubstack(block, 'SUBSTACK'), warpTimer: needsWarpTimer - }; + }, this.analyzeLoop() || needsWarpTimer); } case 'control_stop': { const level = block.fields.STOP_OPTION.value; if (level === 'all') { - this.script.yields = true; - return { - kind: 'control.stopAll' - }; + return new IntermediateStackBlock(StackOpcode.CONTROL_STOP_ALL, {}, true); } else if (level === 'other scripts in sprite' || level === 'other scripts in stage') { - return { - kind: 'control.stopOthers' - }; + return new IntermediateStackBlock(StackOpcode.CONTROL_STOP_OTHERS); } else if (level === 'this script') { - return { - kind: 'control.stopScript' - }; + return new IntermediateStackBlock(StackOpcode.CONTROL_STOP_SCRIPT); } - return { - kind: 'noop' - }; + return new IntermediateStackBlock(StackOpcode.NOP); } case 'control_wait': - this.script.yields = true; - return { - kind: 'control.wait', - seconds: this.descendInputOfBlock(block, 'DURATION') - }; + return new IntermediateStackBlock(StackOpcode.CONTROL_WAIT, { + seconds: this.descendInputOfBlock(block, 'DURATION').toType(InputType.NUMBER) + }, true); case 'control_wait_until': - this.script.yields = true; - return { - kind: 'control.waitUntil', - condition: this.descendInputOfBlock(block, 'CONDITION') - }; + return new IntermediateStackBlock(StackOpcode.CONTROL_WAIT_UNTIL, { + condition: this.descendInputOfBlock(block, 'CONDITION').toType(InputType.BOOLEAN) + }, true); case 'control_while': - this.analyzeLoop(); - return { - kind: 'control.while', - condition: this.descendInputOfBlock(block, 'CONDITION'), + return new IntermediateStackBlock(StackOpcode.CONTROL_WHILE, { + condition: this.descendInputOfBlock(block, 'CONDITION').toType(InputType.BOOLEAN), do: this.descendSubstack(block, 'SUBSTACK'), // We should consider analyzing this like we do for control_repeat_until warpTimer: false - }; + }, this.analyzeLoop()); + case 'control_clear_counter': + return new IntermediateStackBlock(StackOpcode.CONTROL_CLEAR_COUNTER); + case 'control_incr_counter': + return new IntermediateStackBlock(StackOpcode.CONTORL_INCR_COUNTER); case 'data_addtolist': - return { - kind: 'list.add', + return new IntermediateStackBlock(StackOpcode.LIST_ADD, { list: this.descendVariable(block, 'LIST', LIST_TYPE), - item: this.descendInputOfBlock(block, 'ITEM') - }; + item: this.descendInputOfBlock(block, 'ITEM', true) + }); case 'data_changevariableby': { const variable = this.descendVariable(block, 'VARIABLE', SCALAR_TYPE); - return { - kind: 'var.set', + return new IntermediateStackBlock(StackOpcode.VAR_SET, { variable, - value: { - kind: 'op.add', - left: { - kind: 'var.get', - variable - }, - right: this.descendInputOfBlock(block, 'VALUE') - } - }; + value: new IntermediateInput(InputOpcode.OP_ADD, InputType.NUMBER_OR_NAN, { + left: new IntermediateInput(InputOpcode.VAR_GET, InputType.ANY, {variable}).toType(InputType.NUMBER), + right: this.descendInputOfBlock(block, 'VALUE').toType(InputType.NUMBER) + }) + }); } case 'data_deletealloflist': - return { - kind: 'list.deleteAll', + return new IntermediateStackBlock(StackOpcode.LIST_DELETE_ALL, { list: this.descendVariable(block, 'LIST', LIST_TYPE) - }; + }); case 'data_deleteoflist': { const index = this.descendInputOfBlock(block, 'INDEX'); - if (index.kind === 'constant' && index.value === 'all') { - return { - kind: 'list.deleteAll', + if (index.isConstant('all')) { + return new IntermediateStackBlock(StackOpcode.LIST_DELETE_ALL, { list: this.descendVariable(block, 'LIST', LIST_TYPE) - }; + }); } - return { - kind: 'list.delete', + return new IntermediateStackBlock(StackOpcode.LIST_DELETE, { list: this.descendVariable(block, 'LIST', LIST_TYPE), index: index - }; + }); } case 'data_hidelist': - return { - kind: 'list.hide', + return new IntermediateStackBlock(StackOpcode.LIST_HIDE, { list: this.descendVariable(block, 'LIST', LIST_TYPE) - }; + }); case 'data_hidevariable': - return { - kind: 'var.hide', + return new IntermediateStackBlock(StackOpcode.VAR_HIDE, { variable: this.descendVariable(block, 'VARIABLE', SCALAR_TYPE) - }; + }); case 'data_insertatlist': - return { - kind: 'list.insert', + return new IntermediateStackBlock(StackOpcode.LIST_INSERT, { list: this.descendVariable(block, 'LIST', LIST_TYPE), index: this.descendInputOfBlock(block, 'INDEX'), - item: this.descendInputOfBlock(block, 'ITEM') - }; + item: this.descendInputOfBlock(block, 'ITEM', true) + }); case 'data_replaceitemoflist': - return { - kind: 'list.replace', + return new IntermediateStackBlock(StackOpcode.LIST_REPLACE, { list: this.descendVariable(block, 'LIST', LIST_TYPE), index: this.descendInputOfBlock(block, 'INDEX'), - item: this.descendInputOfBlock(block, 'ITEM') - }; + item: this.descendInputOfBlock(block, 'ITEM', true) + }); case 'data_setvariableto': - return { - kind: 'var.set', + return new IntermediateStackBlock(StackOpcode.VAR_SET, { variable: this.descendVariable(block, 'VARIABLE', SCALAR_TYPE), - value: this.descendInputOfBlock(block, 'VALUE') - }; + value: this.descendInputOfBlock(block, 'VALUE', true) + }); case 'data_showlist': - return { - kind: 'list.show', + return new IntermediateStackBlock(StackOpcode.LIST_SHOW, { list: this.descendVariable(block, 'LIST', LIST_TYPE) - }; + }); case 'data_showvariable': - return { - kind: 'var.show', + return new IntermediateStackBlock(StackOpcode.VAR_SHOW, { variable: this.descendVariable(block, 'VARIABLE', SCALAR_TYPE) - }; + }); case 'event_broadcast': - return { - kind: 'event.broadcast', - broadcast: this.descendInputOfBlock(block, 'BROADCAST_INPUT') - }; + return new IntermediateStackBlock(StackOpcode.EVENT_BROADCAST, { + broadcast: this.descendInputOfBlock(block, 'BROADCAST_INPUT').toType(InputType.STRING) + }); case 'event_broadcastandwait': - this.script.yields = true; - return { - kind: 'event.broadcastAndWait', - broadcast: this.descendInputOfBlock(block, 'BROADCAST_INPUT') - }; + return new IntermediateStackBlock(StackOpcode.EVENT_BROADCAST_AND_WAIT, { + broadcast: this.descendInputOfBlock(block, 'BROADCAST_INPUT').toType(InputType.STRING) + }, true); case 'looks_changeeffectby': - return { - kind: 'looks.changeEffect', + return new IntermediateStackBlock(StackOpcode.LOOKS_EFFECT_CHANGE, { effect: block.fields.EFFECT.value.toLowerCase(), - value: this.descendInputOfBlock(block, 'CHANGE') - }; + value: this.descendInputOfBlock(block, 'CHANGE').toType(InputType.NUMBER) + }); case 'looks_changesizeby': - return { - kind: 'looks.changeSize', - size: this.descendInputOfBlock(block, 'CHANGE') - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_SIZE_CHANGE, { + size: this.descendInputOfBlock(block, 'CHANGE').toType(InputType.NUMBER) + }); case 'looks_cleargraphiceffects': - return { - kind: 'looks.clearEffects' - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_EFFECT_CLEAR); case 'looks_goforwardbackwardlayers': if (block.fields.FORWARD_BACKWARD.value === 'forward') { - return { - kind: 'looks.forwardLayers', - layers: this.descendInputOfBlock(block, 'NUM') - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_LAYER_FORWARD, { + layers: this.descendInputOfBlock(block, 'NUM').toType(InputType.NUMBER) + }); } - return { - kind: 'looks.backwardLayers', - layers: this.descendInputOfBlock(block, 'NUM') - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_LAYER_BACKWARD, { + layers: this.descendInputOfBlock(block, 'NUM').toType(InputType.NUMBER) + }); case 'looks_gotofrontback': if (block.fields.FRONT_BACK.value === 'front') { - return { - kind: 'looks.goToFront' - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_LAYER_FRONT); } - return { - kind: 'looks.goToBack' - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_LAYER_BACK); case 'looks_hide': - return { - kind: 'looks.hide' - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_HIDE); case 'looks_nextbackdrop': - return { - kind: 'looks.nextBackdrop' - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_BACKDROP_NEXT); case 'looks_nextcostume': - return { - kind: 'looks.nextCostume' - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_COSTUME_NEXT); case 'looks_seteffectto': - return { - kind: 'looks.setEffect', + return new IntermediateStackBlock(StackOpcode.LOOKS_EFFECT_SET, { effect: block.fields.EFFECT.value.toLowerCase(), - value: this.descendInputOfBlock(block, 'VALUE') - }; + value: this.descendInputOfBlock(block, 'VALUE').toType(InputType.NUMBER) + }); case 'looks_setsizeto': - return { - kind: 'looks.setSize', - size: this.descendInputOfBlock(block, 'SIZE') - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_SIZE_SET, { + size: this.descendInputOfBlock(block, 'SIZE').toType(InputType.NUMBER) + }); case 'looks_show': - return { - kind: 'looks.show' - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_SHOW); case 'looks_switchbackdropto': - return { - kind: 'looks.switchBackdrop', - backdrop: this.descendInputOfBlock(block, 'BACKDROP') - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_BACKDROP_SET, { + backdrop: this.descendInputOfBlock(block, 'BACKDROP', true) + }); case 'looks_switchcostumeto': - return { - kind: 'looks.switchCostume', - costume: this.descendInputOfBlock(block, 'COSTUME') - }; + return new IntermediateStackBlock(StackOpcode.LOOKS_COSTUME_SET, { + costume: this.descendInputOfBlock(block, 'COSTUME', true) + }); case 'motion_changexby': - return { - kind: 'motion.changeX', - dx: this.descendInputOfBlock(block, 'DX') - }; + return new IntermediateStackBlock(StackOpcode.MOTION_X_CHANGE, { + dx: this.descendInputOfBlock(block, 'DX').toType(InputType.NUMBER) + }); case 'motion_changeyby': - return { - kind: 'motion.changeY', - dy: this.descendInputOfBlock(block, 'DY') - }; + return new IntermediateStackBlock(StackOpcode.MOTION_Y_CHANGE, { + dy: this.descendInputOfBlock(block, 'DY').toType(InputType.NUMBER) + }); case 'motion_gotoxy': - return { - kind: 'motion.setXY', - x: this.descendInputOfBlock(block, 'X'), - y: this.descendInputOfBlock(block, 'Y') - }; + return new IntermediateStackBlock(StackOpcode.MOTION_XY_SET, { + x: this.descendInputOfBlock(block, 'X').toType(InputType.NUMBER), + y: this.descendInputOfBlock(block, 'Y').toType(InputType.NUMBER) + }); case 'motion_ifonedgebounce': - return { - kind: 'motion.ifOnEdgeBounce' - }; + return new IntermediateStackBlock(StackOpcode.MOTION_IF_ON_EDGE_BOUNCE); case 'motion_movesteps': - return { - kind: 'motion.step', - steps: this.descendInputOfBlock(block, 'STEPS') - }; + return new IntermediateStackBlock(StackOpcode.MOTION_STEP, { + steps: this.descendInputOfBlock(block, 'STEPS').toType(InputType.NUMBER) + }); case 'motion_pointindirection': - return { - kind: 'motion.setDirection', - direction: this.descendInputOfBlock(block, 'DIRECTION') - }; + return new IntermediateStackBlock(StackOpcode.MOTION_DIRECTION_SET, { + direction: this.descendInputOfBlock(block, 'DIRECTION').toType(InputType.NUMBER) + }); case 'motion_setrotationstyle': - return { - kind: 'motion.setRotationStyle', + return new IntermediateStackBlock(StackOpcode.MOTION_ROTATION_STYLE_SET, { style: block.fields.STYLE.value - }; + }); case 'motion_setx': - return { - kind: 'motion.setX', - x: this.descendInputOfBlock(block, 'X') - }; + return new IntermediateStackBlock(StackOpcode.MOTION_X_SET, { + x: this.descendInputOfBlock(block, 'X').toType(InputType.NUMBER) + }); case 'motion_sety': - return { - kind: 'motion.setY', - y: this.descendInputOfBlock(block, 'Y') - }; + return new IntermediateStackBlock(StackOpcode.MOTION_Y_SET, { + y: this.descendInputOfBlock(block, 'Y').toType(InputType.NUMBER) + }); case 'motion_turnleft': - return { - kind: 'motion.setDirection', - direction: { - kind: 'op.subtract', - left: { - kind: 'motion.direction' - }, + return new IntermediateStackBlock(StackOpcode.MOTION_DIRECTION_SET, { + direction: new IntermediateInput(InputOpcode.OP_SUBTRACT, InputType.NUMBER, { + left: new IntermediateInput(InputOpcode.MOTION_DIRECTION_GET, InputType.NUMBER), right: this.descendInputOfBlock(block, 'DEGREES') - } - }; + }) + }); case 'motion_turnright': - return { - kind: 'motion.setDirection', - direction: { - kind: 'op.add', - left: { - kind: 'motion.direction' - }, + return new IntermediateStackBlock(StackOpcode.MOTION_DIRECTION_SET, { + direction: new IntermediateInput(InputOpcode.OP_ADD, InputType.NUMBER, { + left: new IntermediateInput(InputOpcode.MOTION_DIRECTION_GET, InputType.NUMBER), right: this.descendInputOfBlock(block, 'DEGREES') - } - }; + }) + }); case 'pen_clear': - return { - kind: 'pen.clear' - }; + return new IntermediateStackBlock(StackOpcode.PEN_CLEAR); case 'pen_changePenColorParamBy': - return { - kind: 'pen.changeParam', - param: this.descendInputOfBlock(block, 'COLOR_PARAM'), - value: this.descendInputOfBlock(block, 'VALUE') - }; + return new IntermediateStackBlock(StackOpcode.PEN_COLOR_PARAM_CHANGE, { + param: this.descendInputOfBlock(block, 'COLOR_PARAM').toType(InputType.STRING), + value: this.descendInputOfBlock(block, 'VALUE').toType(InputType.NUMBER) + }); case 'pen_changePenHueBy': - return { - kind: 'pen.legacyChangeHue', - hue: this.descendInputOfBlock(block, 'HUE') - }; + return new IntermediateStackBlock(StackOpcode.PEN_COLOR_HUE_CHANGE_LEGACY, { + hue: this.descendInputOfBlock(block, 'HUE').toType(InputType.NUMBER) + }); case 'pen_changePenShadeBy': - return { - kind: 'pen.legacyChangeShade', - shade: this.descendInputOfBlock(block, 'SHADE') - }; + return new IntermediateStackBlock(StackOpcode.PEN_COLOR_SHADE_CHANGE_LEGACY, { + shade: this.descendInputOfBlock(block, 'SHADE').toType(InputType.NUMBER) + }); case 'pen_penDown': - return { - kind: 'pen.down' - }; + return new IntermediateStackBlock(StackOpcode.PEN_DOWN); case 'pen_penUp': - return { - kind: 'pen.up' - }; + return new IntermediateStackBlock(StackOpcode.PEN_UP); case 'pen_setPenColorParamTo': - return { - kind: 'pen.setParam', - param: this.descendInputOfBlock(block, 'COLOR_PARAM'), - value: this.descendInputOfBlock(block, 'VALUE') - }; + return new IntermediateStackBlock(StackOpcode.PEN_COLOR_PARAM_SET, { + param: this.descendInputOfBlock(block, 'COLOR_PARAM').toType(InputType.STRING), + value: this.descendInputOfBlock(block, 'VALUE').toType(InputType.NUMBER) + }); case 'pen_setPenColorToColor': - return { - kind: 'pen.setColor', + return new IntermediateStackBlock(StackOpcode.PEN_COLOR_SET, { color: this.descendInputOfBlock(block, 'COLOR') - }; + }); case 'pen_setPenHueToNumber': - return { - kind: 'pen.legacySetHue', - hue: this.descendInputOfBlock(block, 'HUE') - }; + return new IntermediateStackBlock(StackOpcode.PEN_COLOR_HUE_SET_LEGACY, { + hue: this.descendInputOfBlock(block, 'HUE').toType(InputType.NUMBER) + }); case 'pen_setPenShadeToNumber': - return { - kind: 'pen.legacySetShade', - shade: this.descendInputOfBlock(block, 'SHADE') - }; + return new IntermediateStackBlock(StackOpcode.PEN_COLOR_SHADE_SET_LEGACY, { + shade: this.descendInputOfBlock(block, 'SHADE').toType(InputType.NUMBER) + }); case 'pen_setPenSizeTo': - return { - kind: 'pen.setSize', - size: this.descendInputOfBlock(block, 'SIZE') - }; + return new IntermediateStackBlock(StackOpcode.PEN_SIZE_SET, { + size: this.descendInputOfBlock(block, 'SIZE').toType(InputType.NUMBER) + }); case 'pen_changePenSizeBy': - return { - kind: 'pen.changeSize', - size: this.descendInputOfBlock(block, 'SIZE') - }; + return new IntermediateStackBlock(StackOpcode.PEN_SIZE_CHANGE, { + size: this.descendInputOfBlock(block, 'SIZE').toType(InputType.NUMBER) + }); case 'pen_stamp': - return { - kind: 'pen.stamp' - }; + return new IntermediateStackBlock(StackOpcode.PEN_STAMP); case 'procedures_call': { const procedureCode = block.mutation.proccode; + if (block.mutation.return) { const visualReport = this.descendVisualReport(block); if (visualReport) { return visualReport; } } + if (procedureCode === 'tw:debugger;') { - return { - kind: 'tw.debugger' - }; + return new IntermediateStackBlock(StackOpcode.DEBUGGER); } - return this.descendProcedure(block); + + const procedure = this.getProcedureInfo(block); + return new IntermediateStackBlock(procedure.opcode, procedure.inputs, procedure.yields); } case 'procedures_return': - return { - kind: 'procedures.return', + return new IntermediateStackBlock(StackOpcode.PROCEDURE_RETURN, { value: this.descendInputOfBlock(block, 'VALUE') - }; + }); case 'sensing_resettimer': - return { - kind: 'timer.reset' - }; + return new IntermediateStackBlock(StackOpcode.SENSING_TIMER_RESET); default: { const opcodeFunction = this.runtime.getOpcodeFunction(block.opcode); if (opcodeFunction) { // It might be a non-compiled primitive from a standard category if (compatBlocks.stacked.includes(block.opcode)) { - return this.descendCompatLayer(block); + return this.descendCompatLayerStack(block); } // It might be an extension block. const blockInfo = this.getBlockInfo(block.opcode); if (blockInfo) { const type = blockInfo.info.blockType; if (type === BlockType.COMMAND || type === BlockType.CONDITIONAL || type === BlockType.LOOP) { - return this.descendCompatLayer(block); + return this.descendCompatLayerStack(block); } } } @@ -1179,14 +953,14 @@ class ScriptTreeGenerator { /** * Descend into a stack of blocks (eg. the blocks contained within an "if" block) * @param {*} parentBlock The parent Scratch block that contains the stack to parse. - * @param {*} substackName The name of the stack to descend into. + * @param {string} substackName The name of the stack to descend into. * @private - * @returns {Node[]} List of stacked block nodes. + * @returns {IntermediateStack} Stacked blocks. */ descendSubstack (parentBlock, substackName) { const input = parentBlock.inputs[substackName]; if (!input) { - return []; + return new IntermediateStack(); } const stackId = input.block; return this.walkStack(stackId); @@ -1196,10 +970,10 @@ class ScriptTreeGenerator { * Descend into and walk the siblings of a stack. * @param {string} startingBlockId The ID of the first block of a stack. * @private - * @returns {Node[]} List of stacked block nodes. + * @returns {IntermediateStack} List of stacked block nodes. */ walkStack (startingBlockId) { - const result = []; + const result = new IntermediateStack(); let blockId = startingBlockId; while (blockId !== null) { @@ -1209,7 +983,8 @@ class ScriptTreeGenerator { } const node = this.descendStackedBlock(block); - result.push(node); + this.script.yields = this.script.yields || node.yields; + result.blocks.push(node); blockId = block.next; } @@ -1217,6 +992,112 @@ class ScriptTreeGenerator { return result; } + /** + * @param {*} block + * @returns {{ + * opcode: StackOpcode & InputOpcode, + * inputs?: *, + * yields: boolean + * }} + */ + getProcedureInfo (block) { + const procedureCode = block.mutation.proccode; + const paramNamesIdsAndDefaults = this.blocks.getProcedureParamNamesIdsAndDefaults(procedureCode); + + if (paramNamesIdsAndDefaults === null) { + return {opcode: StackOpcode.NOP, yields: false}; + } + + const [paramNames, paramIds, paramDefaults] = paramNamesIdsAndDefaults; + + const addonBlock = this.runtime.getAddonBlock(procedureCode); + if (addonBlock) { + const args = {}; + for (let i = 0; i < paramIds.length; i++) { + let value; + if (block.inputs[paramIds[i]] && block.inputs[paramIds[i]].block) { + value = this.descendInputOfBlock(block, paramIds[i], true); + } else { + value = this.createConstantInput(paramDefaults[i], true); + } + args[paramNames[i]] = value; + } + + return { + opcode: StackOpcode.ADDON_CALL, + inputs: { + code: procedureCode, + arguments: args, + blockId: block.id + }, + yields: true + }; + } + + const definitionId = this.blocks.getProcedureDefinition(procedureCode); + const definitionBlock = this.blocks.getBlock(definitionId); + if (!definitionBlock) { + return {opcode: StackOpcode.NOP, yields: false}; + } + const innerDefinition = this.blocks.getBlock(definitionBlock.inputs.custom_block.block); + + let isWarp = this.script.isWarp; + if (!isWarp) { + if (innerDefinition && innerDefinition.mutation) { + const warp = innerDefinition.mutation.warp; + if (typeof warp === 'boolean') { + isWarp = warp; + } else if (typeof warp === 'string') { + isWarp = JSON.parse(warp); + } + } + } + + const variant = generateProcedureVariant(procedureCode, isWarp); + + if (!this.script.dependedProcedures.includes(variant)) { + this.script.dependedProcedures.push(variant); + } + + const args = []; + for (let i = 0; i < paramIds.length; i++) { + let value; + if (block.inputs[paramIds[i]] && block.inputs[paramIds[i]].block) { + value = this.descendInputOfBlock(block, paramIds[i], true); + } else { + value = this.createConstantInput(paramDefaults[i], true); + } + args.push(value); + } + + return { + opcode: StackOpcode.PROCEDURE_CALL, + inputs: { + code: procedureCode, + variant, + arguments: args + }, + yields: !this.script.isWarp && procedureCode === this.script.procedureCode + }; + } + + /** + * @param {*} block + * @returns {IntermediateStackBlock | null} + */ + descendVisualReport (block) { + if (!this.thread.stackClick || block.next) { + return null; + } + try { + return new IntermediateStackBlock(StackOpcode.VISUAL_REPORT, { + input: this.descendInput(block) + }); + } catch (e) { + return null; + } + } + /** * Descend into a variable. * @param {*} block The block that has the variable. @@ -1229,7 +1110,7 @@ class ScriptTreeGenerator { const variable = block.fields[fieldName]; const id = variable.id; - if (Object.prototype.hasOwnProperty.call(this.variableCache, id)) { + if (this.variableCache.hasOwnProperty(id)) { return this.variableCache[id]; } @@ -1250,20 +1131,20 @@ class ScriptTreeGenerator { const stage = this.stage; // Look for by ID in target... - if (Object.prototype.hasOwnProperty.call(target.variables, id)) { + if (target.variables.hasOwnProperty(id)) { return createVariableData('target', target.variables[id]); } // Look for by ID in stage... if (!target.isStage) { - if (stage && Object.prototype.hasOwnProperty.call(stage.variables, id)) { + if (stage && stage.variables.hasOwnProperty(id)) { return createVariableData('stage', stage.variables[id]); } } // Look for by name and type in target... for (const varId in target.variables) { - if (Object.prototype.hasOwnProperty.call(target.variables, varId)) { + if (target.variables.hasOwnProperty(varId)) { const currVar = target.variables[varId]; if (currVar.name === name && currVar.type === type) { return createVariableData('target', currVar); @@ -1274,7 +1155,7 @@ class ScriptTreeGenerator { // Look for by name and type in stage... if (!target.isStage && stage) { for (const varId in stage.variables) { - if (Object.prototype.hasOwnProperty.call(stage.variables, varId)) { + if (stage.variables.hasOwnProperty(varId)) { const currVar = stage.variables[varId]; if (currVar.name === name && currVar.type === type) { return createVariableData('stage', currVar); @@ -1292,7 +1173,7 @@ class ScriptTreeGenerator { // This is necessary because the script cache is shared between clones. // sprite.clones has all instances of this sprite including the original and all clones for (const clone of target.sprite.clones) { - if (!Object.prototype.hasOwnProperty.call(clone.variables, id)) { + if (!clone.variables.hasOwnProperty(id)) { clone.variables[id] = new Variable(id, name, type, false); } } @@ -1301,110 +1182,40 @@ class ScriptTreeGenerator { return createVariableData('target', newVariable); } - descendProcedure (block) { - const procedureCode = block.mutation.proccode; - const paramNamesIdsAndDefaults = this.blocks.getProcedureParamNamesIdsAndDefaults(procedureCode); - if (paramNamesIdsAndDefaults === null) { - return { - kind: 'noop' - }; - } - - const [paramNames, paramIds, paramDefaults] = paramNamesIdsAndDefaults; - - const addonBlock = this.runtime.getAddonBlock(procedureCode); - if (addonBlock) { - this.script.yields = true; - const args = {}; - for (let i = 0; i < paramIds.length; i++) { - let value; - if (block.inputs[paramIds[i]] && block.inputs[paramIds[i]].block) { - value = this.descendInputOfBlock(block, paramIds[i]); - } else { - value = { - kind: 'constant', - value: paramDefaults[i] - }; - } - args[paramNames[i]] = value; - } - return { - kind: 'addons.call', - code: procedureCode, - arguments: args, - blockId: block.id - }; - } - - const definitionId = this.blocks.getProcedureDefinition(procedureCode); - const definitionBlock = this.blocks.getBlock(definitionId); - if (!definitionBlock) { - return { - kind: 'noop' - }; - } - const innerDefinition = this.blocks.getBlock(definitionBlock.inputs.custom_block.block); - - let isWarp = this.script.isWarp; - if (!isWarp) { - if (innerDefinition && innerDefinition.mutation) { - const warp = innerDefinition.mutation.warp; - if (typeof warp === 'boolean') { - isWarp = warp; - } else if (typeof warp === 'string') { - isWarp = JSON.parse(warp); - } - } - } - - const variant = generateProcedureVariant(procedureCode, isWarp); - - if (!this.script.dependedProcedures.includes(variant)) { - this.script.dependedProcedures.push(variant); - } - - // Non-warp direct recursion yields. - if (!this.script.isWarp) { - if (procedureCode === this.script.procedureCode) { - this.script.yields = true; - } + /** + * Descend into an input block that uses the compatibility layer. + * @param {*} block The block to use the compatibility layer for. + * @private + * @returns {IntermediateInput} The parsed node. + */ + descendCompatLayerInput (block) { + const inputs = {}; + const fields = {}; + for (const name of Object.keys(block.inputs)) { + inputs[name] = this.descendInputOfBlock(block, name, true); } - - const args = []; - for (let i = 0; i < paramIds.length; i++) { - let value; - if (block.inputs[paramIds[i]] && block.inputs[paramIds[i]].block) { - value = this.descendInputOfBlock(block, paramIds[i]); - } else { - value = { - kind: 'constant', - value: paramDefaults[i] - }; - } - args.push(value); + for (const name of Object.keys(block.fields)) { + fields[name] = block.fields[name].value; } - - return { - kind: 'procedures.call', - code: procedureCode, - variant, - arguments: args - }; + return new IntermediateInput(InputOpcode.COMPATIBILITY_LAYER, InputType.ANY, { + opcode: block.opcode, + id: block.id, + inputs, + fields + }, true); } /** - * Descend into a block that uses the compatibility layer. + * Descend into a stack block that uses the compatibility layer. * @param {*} block The block to use the compatibility layer for. * @private - * @returns {Node} The parsed node. + * @returns {IntermediateStackBlock} The parsed node. */ - descendCompatLayer (block) { - this.script.yields = true; - + descendCompatLayerStack (block) { const inputs = {}; for (const name of Object.keys(block.inputs)) { if (!name.startsWith('SUBSTACK')) { - inputs[name] = this.descendInputOfBlock(block, name); + inputs[name] = this.descendInputOfBlock(block, name, true); } } @@ -1415,32 +1226,27 @@ class ScriptTreeGenerator { const blockInfo = this.getBlockInfo(block.opcode); const blockType = (blockInfo && blockInfo.info && blockInfo.info.blockType) || BlockType.COMMAND; - const substacks = {}; + const substacks = []; if (blockType === BlockType.CONDITIONAL || blockType === BlockType.LOOP) { - for (const inputName in block.inputs) { - if (!inputName.startsWith('SUBSTACK')) continue; - const branchNum = inputName === 'SUBSTACK' ? 1 : +inputName.substring('SUBSTACK'.length); - if (!isNaN(branchNum)) { - substacks[branchNum] = this.descendSubstack(block, inputName); - } + const branchCount = blockInfo.info.branchCount; + for (let i = 0; i < branchCount; i++) { + const inputName = i === 0 ? 'SUBSTACK' : `SUBSTACK${i + 1}`; + substacks.push(this.descendSubstack(block, inputName)); } } - return { - kind: 'compat', - id: block.id, + return new IntermediateStackBlock(StackOpcode.COMPATIBILITY_LAYER, { opcode: block.opcode, + id: block.id, blockType, inputs, fields, substacks - }; + }, true); } analyzeLoop () { - if (!this.script.isWarp || this.script.warpTimer) { - this.script.yields = true; - } + return !this.script.isWarp || this.script.warpTimer; } readTopBlockComment (commentId) { @@ -1474,22 +1280,9 @@ class ScriptTreeGenerator { } } - descendVisualReport (block) { - if (!this.thread.stackClick || block.next) { - return null; - } - try { - return { - kind: 'visualReport', - input: this.descendInput(block) - }; - } catch (e) { - return null; - } - } - /** - * @param {Block} hatBlock + * @param {*} hatBlock + * @returns {IntermediateStack} */ walkHat (hatBlock) { const nextBlock = hatBlock.next; @@ -1501,10 +1294,10 @@ class ScriptTreeGenerator { // interpreter parity, but the reuslt is ignored. const opcodeFunction = this.runtime.getOpcodeFunction(opcode); if (opcodeFunction) { - return [ - this.descendCompatLayer(hatBlock), - ...this.walkStack(nextBlock) - ]; + return new IntermediateStack([ + this.descendCompatLayerStack(hatBlock), + ...this.walkStack(nextBlock).blocks + ]); } return this.walkStack(nextBlock); } @@ -1513,14 +1306,13 @@ class ScriptTreeGenerator { // Edge-activated HAT this.script.yields = true; this.script.executableHat = true; - return [ - { - kind: 'hat.edge', + return new IntermediateStack([ + new IntermediateStackBlock(StackOpcode.HAT_EDGE, { id: hatBlock.id, - condition: this.descendCompatLayer(hatBlock) - }, - ...this.walkStack(nextBlock) - ]; + condition: this.descendCompatLayerInput(hatBlock).toType(InputType.BOOLEAN) + }), + ...this.walkStack(nextBlock).blocks + ]); } const opcodeFunction = this.runtime.getOpcodeFunction(opcode); @@ -1528,13 +1320,12 @@ class ScriptTreeGenerator { // Predicate-based HAT this.script.yields = true; this.script.executableHat = true; - return [ - { - kind: 'hat.predicate', - condition: this.descendCompatLayer(hatBlock) - }, - ...this.walkStack(nextBlock) - ]; + return new IntermediateStack([ + new IntermediateStackBlock(StackOpcode.HAT_PREDICATE, { + condition: this.descendCompatLayerInput(hatBlock).toType(InputType.BOOLEAN) + }), + ...this.walkStack(nextBlock).blocks + ]); } return this.walkStack(nextBlock); @@ -1601,7 +1392,7 @@ class IRGenerator { addProcedureDependencies (dependencies) { for (const procedureVariant of dependencies) { - if (Object.prototype.hasOwnProperty.call(this.procedures, procedureVariant)) { + if (this.procedures.hasOwnProperty(procedureVariant)) { continue; } if (this.compilingProcedures.has(procedureVariant)) { @@ -1687,14 +1478,8 @@ class IRGenerator { // Analyze scripts until no changes are made. while (this.analyzeScript(entry)); - const ir = new IntermediateRepresentation(); - ir.entry = entry; - ir.procedures = this.procedures; - return ir; + return new IntermediateRepresentation(entry, this.procedures); } } -module.exports = { - ScriptTreeGenerator, - IRGenerator -}; +module.exports = IRGenerator; diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js new file mode 100644 index 00000000000..4e4ce7a5f9d --- /dev/null +++ b/src/compiler/iroptimizer.js @@ -0,0 +1,703 @@ +// @ts-check + +const {IntermediateStack, IntermediateInput, IntermediateScript, IntermediateRepresentation, IntermediateStackBlock} = require('./intermediate'); +const {StackOpcode, InputOpcode, InputType} = require('./enums.js'); + +class TypeState { + constructor () { + /** @type {Object.}*/ + this.variables = {}; + /** @type {InputType | 0} */ + this.defaultType = 0; + } + + /** + * @returns {boolean} + */ + clear () { + let modified = false; + for (const varId in this.variables) { + if (this.variables[varId] !== InputType.ANY) { + modified = true; + break; + } + } + this.variables = {}; + this.defaultType = InputType.ANY; + return modified; + } + + + /** + * @returns {TypeState} + */ + clone () { + const clone = new TypeState(); + for (const varId in this.variables) { + clone.variables[varId] = this.variables[varId]; + } + clone.defaultType = this.defaultType; + return clone; + } + + /** + * @param {TypeState} other + * @param {(varId: string) => InputType | 0} stateMutator + * @returns {boolean} + * @private + */ + mutate (other, stateMutator) { + let modified = false; + for (const varId in other.variables) { + const newValue = stateMutator(varId); + if (newValue !== this.variables[varId]) { + this.variables[varId] = newValue; + modified = modified || true; + } + } + + for (const varId in this.variables) { + if (!other.variables[varId]) { + const newValue = stateMutator(varId); + if (newValue !== this.variables[varId]) { + this.variables[varId] = newValue; + modified = modified || true; + } + } + } + return modified; + } + + /** + * @param {TypeState} other + * @returns {boolean} + */ + or (other) { + return this.mutate(other, varId => { + const thisType = this.variables[varId] ?? this.defaultType; + const otherType = other.variables[varId] ?? other.defaultType; + return thisType | otherType; + }); + } + + /** + * @param {TypeState} other + * @returns {boolean} + */ + after (other) { + return this.mutate(other, varId => { + const otherType = other.variables[varId] ?? other.defaultType; + if (otherType !== 0) return otherType; + return this.variables[varId] ?? this.defaultType; + }); + } + + /** + * @param {*} variable A variable codegen object. + * @param {InputType} type The type to set this variable to + * @returns {boolean} + */ + setVariableType (variable, type) { + if (this.getVariableType(variable) === type) return false; + this.variables[variable.id] = type; + return true; + } + + /** + * + * @param {*} variable A variable codegen object. + * @returns {InputType} + */ + getVariableType (variable) { + return this.variables[variable.id] ?? (this.defaultType === 0 ? InputType.ANY : this.defaultType); + } +} + +class IROptimizer { + + /** + * @param {IntermediateRepresentation} ir + */ + constructor (ir) { + /** @type {IntermediateRepresentation} */ + this.ir = ir; + /** @type {boolean} Used for testing */ + this.ignoreYields = false; + } + + /** + * @param {IntermediateInput} inputBlock + * @param {TypeState} state + * @returns {InputType} + */ + getInputType (inputBlock, state) { + const inputs = inputBlock.inputs; + + switch (inputBlock.opcode) { + case InputOpcode.VAR_GET: + return state.getVariableType(inputs.variable); + + case InputOpcode.ADDON_CALL: + + + case InputOpcode.CAST_NUMBER: { + const innerType = inputs.target.type; + if (innerType & InputType.NUMBER) return innerType; + return InputType.NUMBER; + } case InputOpcode.CAST_NUMBER_OR_NAN: { + const innerType = inputs.target; + if (innerType & InputType.NUMBER_OR_NAN) return innerType; + return InputType.NUMBER_OR_NAN; + } + + case InputOpcode.OP_ADD: { + const leftType = inputs.left.type; + const rightType = inputs.right.type; + + let resultType = 0; + + function canBeNaN () { + // Infinity + (-Infinity) = NaN + if ((leftType & InputType.NUMBER_POS_INF) && (rightType & InputType.NUMBER_NEG_INF)) return true; + // (-Infinity) + Infinity = NaN + if ((leftType & InputType.NUMBER_NEG_INF) && (rightType & InputType.NUMBER_POS_INF)) return true; + } + if (canBeNaN()) resultType |= InputType.NUMBER_NAN; + + function canBeFractional () { + // For the plus operation to return a non-whole number one of it's + // inputs has to be a non-whole number + if (leftType & InputType.NUMBER_FRACT) return true; + if (rightType & InputType.NUMBER_FRACT) return true; + } + const canBeFract = canBeFractional(); + + function canBePos () { + if (leftType & InputType.NUMBER_POS) return true; // POS + ANY ~= POS + if (rightType & InputType.NUMBER_POS) return true; // ANY + POS ~= POS + } + if (canBePos()) { + resultType |= InputType.NUMBER_POS_INT | InputType.NUMBER_POS_INF; + if (canBeFract) resultType |= InputType.NUMBER_POS_FRACT; + } + + function canBeNeg () { + if (leftType & InputType.NUMBER_NEG) return true; // NEG + ANY ~= NEG + if (rightType & InputType.NUMBER_NEG) return true; // ANY + NEG ~= NEG + } + if (canBeNeg()) { + resultType |= InputType.NUMBER_NEG_INT | InputType.NUMBER_NEG_INF; + if (canBeFract) resultType |= InputType.NUMBER_NEG_FRACT; + } + + function canBeZero () { + // POS_REAL + NEG_REAL ~= 0 + if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_NEG_REAL)) return true; + // NEG_REAL + POS_REAL ~= 0 + if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_POS_REAL)) return true; + // 0 + 0 = 0 + if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_ZERO)) return true; + // 0 + -0 = 0 + if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; + // -0 + 0 = 0 + if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_ZERO)) return true; + } + if (canBeZero()) resultType |= InputType.NUMBER_ZERO; + + function canBeNegZero () { + // -0 + -0 = -0 + if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; + } + if (canBeNegZero()) resultType |= InputType.NUMBER_NEG_ZERO; + + return resultType; + } + + case InputOpcode.OP_SUBTRACT: { + const leftType = inputs.left.type; + const rightType = inputs.right.type; + + let resultType = 0; + + function canBeNaN () { + // Infinity - Infinity = NaN + if ((leftType & InputType.NUMBER_POS_INF) && (rightType & InputType.NUMBER_POS_INF)) return true; + // (-Infinity) - (-Infinity) = NaN + if ((leftType & InputType.NUMBER_NEG_INF) && (rightType & InputType.NUMBER_NEG_INF)) return true; + } + if (canBeNaN()) resultType |= InputType.NUMBER_NAN; + + function canBeFractional () { + // For the subtract operation to return a non-whole number one of it's + // inputs has to be a non-whole number + if (leftType & InputType.NUMBER_FRACT) return true; + if (rightType & InputType.NUMBER_FRACT) return true; + } + const canBeFract = canBeFractional(); + + function canBePos () { + if (leftType & InputType.NUMBER_POS) return true; // POS - ANY ~= POS + if (rightType & InputType.NUMBER_NEG) return true; // ANY - NEG ~= POS + } + if (canBePos()) { + resultType |= InputType.NUMBER_POS_INT | InputType.NUMBER_POS_INF; + if (canBeFract) resultType |= InputType.NUMBER_POS_FRACT; + } + + function canBeNeg () { + if (leftType & InputType.NUMBER_NEG) return true; // NEG - ANY ~= NEG + if (rightType & InputType.NUMBER_POS) return true; // ANY - POS ~= NEG + } + if (canBeNeg()) { + resultType |= InputType.NUMBER_NEG_INT | InputType.NUMBER_NEG_INF; + if (canBeFract) resultType |= InputType.NUMBER_NEG_FRACT; + } + + function canBeZero () { + // POS_REAL - POS_REAL ~= 0 + if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_POS_REAL)) return true; + // NEG_REAL - NEG_REAL ~= 0 + if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_NEG_REAL)) return true; + // 0 - 0 = 0 + if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_ZERO)) return true; + // 0 - (-0) = 0 + if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; + // (-0) - (-0) = 0 + if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; + } + if (canBeZero()) resultType |= InputType.NUMBER_ZERO; + + function canBeNegZero () { + // (-0) - 0 = -0 + if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_ZERO)) return true; + } + if (canBeNegZero()) resultType |= InputType.NUMBER_NEG_ZERO; + + return resultType; + } + + case InputOpcode.OP_MULTIPLY: { + const leftType = inputs.left.type; + const rightType = inputs.right.type; + + let resultType = 0; + + function canBeNaN () { + // (-)Infinity * 0 = NaN + if ((leftType & InputType.NUMBER_INF) && (rightType & InputType.NUMBER_ANY_ZERO)) return true; + // 0 * (-)Infinity = NaN + if ((leftType & InputType.NUMBER_ANY_ZERO) && (rightType & InputType.NUMBER_INF)) return true; + } + if (canBeNaN()) resultType |= InputType.NUMBER_NAN; + + function canBeFractional () { + // For the subtract operation to return a non-whole number one of it's + // inputs has to be a non-whole number + if (leftType & InputType.NUMBER_FRACT) return true; + if (rightType & InputType.NUMBER_FRACT) return true; + } + const canBeFract = canBeFractional(); + + function canBePos () { + // POS * POS = POS + if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_POS)) return true; + // NEG * NEG = POS + if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_NEG)) return true; + } + if (canBePos()) { + resultType |= InputType.NUMBER_POS_INT | InputType.NUMBER_POS_INF; + if (canBeFract) resultType |= InputType.NUMBER_POS_FRACT; + } + + function canBeNeg () { + // POS * NEG = NEG + if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_NEG)) return true; + // NEG * POS = NEG + if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_POS)) return true; + } + if (canBeNeg()) { + resultType |= InputType.NUMBER_NEG_INT | InputType.NUMBER_NEG_INF; + if (canBeFract) resultType |= InputType.NUMBER_NEG_FRACT; + } + + function canBeZero () { + // 0 * 0 = 0 + if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_ZERO)) return true; + // -0 * -0 = 0 + if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; + // 0 * POS_REAL = 0 + if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_POS_REAL)) return true; + // -0 * NEG_REAL = 0 + if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_NEG_REAL)) return true; + // POS_REAL * 0 = 0 + if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_ZERO)) return true; + // NEG_REAL * -0 = 0 + if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; + // Rounding errors like 1e-323 * 0.1 = 0 + if ((leftType & InputType.NUMBER_FRACT) && (rightType & InputType.NUMBER_FRACT)) return true; + } + if (canBeZero()) resultType |= InputType.NUMBER_ZERO; + + function canBeNegZero () { + // 0 * -0 = 0 + if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; + // -0 * 0 = 0 + if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_ZERO)) return true; + // -0 * POS_REAL = -0 + if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_POS_REAL)) return true; + // 0 * NEG_REAL = -0 + if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_NEG_REAL)) return true; + // POS_REAL * -0 = -0 + if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; + // NEG_REAL * 0 = -0 + if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_ZERO)) return true; + // Rounding errors like -1e-323 / 10 = -0 + if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_POS_REAL)) return true; + // Rounding errors like 1e-323 / -10 = -0 + if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_NEG_REAL)) return true; + } + if (canBeNegZero()) resultType |= InputType.NUMBER_NEG_ZERO; + + return resultType; + } + + case InputOpcode.OP_DIVIDE: { + const leftType = inputs.left.type; + const rightType = inputs.right.type; + + let resultType = 0; + + function canBeNaN () { + // REAL / 0 = NaN + if ((leftType & InputType.NUMBER_REAL) && (rightType & InputType.NUMBER_ZERO)) return true; + // (-)Infinity / (-)Infinity = NaN + if ((leftType & InputType.NUMBER_INF) && (rightType & InputType.NUMBER_INF)) return true; + // (-)0 / NaN = NaN + if ((leftType & InputType.NUMBER_ANY_ZERO) && (rightType & InputType.NUMBER_NAN)) return true; + } + if (canBeNaN()) resultType |= InputType.NUMBER_NAN; + + function canBePos () { + // POS / POS = POS + if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_POS)) return true; + // NEG / NEG = POS + if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_NEG)) return true; + } + if (canBePos()) resultType |= InputType.NUMBER_POS; + + function canBeNegInfinity () { + // -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; + } + if (canBeNegInfinity()) resultType |= InputType.NUMBER_NEG_INF; + + function canBeInfinity () { + // 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; + } + if (canBeInfinity()) resultType |= InputType.NUMBER_POS_INF; + + function canBeNeg () { + // POS / NEG = NEG + if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_NEG)) return true; + // NEG / POS = NEG + if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_POS)) return true; + } + if (canBeNeg()) resultType |= InputType.NUMBER_NEG; + + function canBeZero () { + // 0 / POS = 0 + if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_POS)) return true; + // -0 / NEG = 0 + if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_NEG)) return true; + // Rounding errors like 1e-323 / 10 = 0 + if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_POS_REAL)) return true; + // Rounding errors like -1e-323 / -10 = 0 + if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_NEG_REAL)) return true; + // NUMBER_POS / Infinity = 0 + if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_POS_INF)) return true; + // NUMBER_NEG / -Infinity = 0 + if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_NEG_INF)) return true; + } + if (canBeZero()) resultType |= InputType.NUMBER_ZERO; + + function canBeNegZero () { + // -0 / POS = -0 + if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_POS)) return true; + // 0 / NEG = -0 + if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_NEG)) return true; + // Rounding errors like -1e-323 / 10 = -0 + if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_POS_REAL)) return true; + // Rounding errors like 1e-323 / -10 = -0 + if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_NEG_REAL)) return true; + // NUMBER_POS / -Infinity = -0 + if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_NEG_INF)) return true; + // NUMBER_NEG / Infinity = -0 + if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_POS_INF)) return true; + } + if (canBeNegZero()) resultType |= InputType.NUMBER_NEG_ZERO; + + return resultType; + } + } + return inputBlock.type; + } + + /** + * @param {IntermediateInput} inputBlock + * @param {TypeState} state + * @returns {boolean} + * @private + */ + analyzeInputBlock (inputBlock, state) { + const inputs = inputBlock.inputs; + + let modified = this.analyzeInputs(inputs, state); + const newType = this.getInputType(inputBlock, state); + + modified = modified || newType !== inputBlock.type; + inputBlock.type = newType; + + switch (inputBlock.opcode) { + case InputOpcode.ADDON_CALL: + modified = state.clear() || modified; + break; + case InputOpcode.PROCEDURE_CALL: + modified = this.analyzeInputs(inputs.inputs, state) || modified; + const script = this.ir.procedures[inputs.variant]; + + if (!script || !script.cachedAnalysisEndState) { + modified = state.clear() || modified; + } else { + modified = state.after(script.cachedAnalysisEndState) || modified; + } + break; + } + + return modified; + } + + /** + * @param {Object} inputs + * @param {TypeState} state + * @returns {boolean} modified + */ + analyzeInputs (inputs, state) { + let modified = false; + for (const inputName in inputs) { + const input = inputs[inputName]; + if (input instanceof IntermediateInput) { + modified = this.analyzeInputBlock(input, state) || modified; + } + } + return modified; + } + + /** + * @param {IntermediateStackBlock} stackBlock + * @param {TypeState} state + * @returns {boolean} + * @private + */ + analyzeStackBlock (stackBlock, state) { + const inputs = stackBlock.inputs; + let modified = false; + + if (stackBlock.ignoreState) { + state = state.clone(); + } + + modified = modified || this.analyzeInputs(inputs, state); + + switch (stackBlock.opcode) { + case StackOpcode.VAR_SET: + modified = state.setVariableType(inputs.variable, inputs.value.type) || modified; + break; + case StackOpcode.CONTROL_WHILE: + case StackOpcode.CONTROL_FOR: + case StackOpcode.CONTROL_REPEAT: + modified = this.analyzeLoopedStack(inputs.do, state, stackBlock) || modified; + break; + case StackOpcode.CONTROL_IF_ELSE: { + const trueState = state.clone(); + modified = this.analyzeStack(inputs.whenTrue, trueState) || modified; + modified = this.analyzeStack(inputs.whenFalse, state) || modified; + modified = state.or(trueState) || modified; + break; + } + case StackOpcode.PROCEDURE_CALL: { + modified = this.analyzeInputs(inputs.inputs, state) || modified; + const script = this.ir.procedures[inputs.variant]; + + if (!script || !script.cachedAnalysisEndState) { + modified = state.clear() || modified; + } else { + modified = state.after(script.cachedAnalysisEndState) || modified; + } + break; + } + case StackOpcode.COMPATIBILITY_LAYER: { + this.analyzeInputs(inputs.inputs, state); + for (const substack of inputs.substacks) { + const newState = state.clone(); + modified = this.analyzeStack(substack, newState) || modified; + modified = state.or(newState) || modified; + } + break; + } + } + + // if (stackBlock.ignoreState) return false; + + return modified; + } + + /** + * @param {IntermediateStack?} stack + * @param {TypeState} state + * @returns {boolean} + * @private + */ + analyzeStack (stack, state) { + if (!stack) return false; + let modified = false; + for (const stackBlock of stack.blocks) { + let stateChanged = this.analyzeStackBlock(stackBlock, state); + + if (!stackBlock.ignoreState) { + if (stackBlock.yields && !this.ignoreYields) stateChanged = state.clear() || stateChanged; + + if (stateChanged) { + if (stackBlock.exitState) stackBlock.exitState.or(state); + else stackBlock.exitState = state.clone(); + modified = true; + } + } + } + return modified; + } + + /** + * @param {IntermediateStack} stack + * @param {TypeState} state + * @param {IntermediateStackBlock} block + * @returns {boolean} + * @private + */ + analyzeLoopedStack (stack, state, block) { + if (block.yields && !this.ignoreYields) { + const modified = state.clear(); + block.entryState = state.clone(); + block.exitState = state.clone(); + return this.analyzeStack(stack, state) || modified; + } + let modified = false; + let keepLooping; + do { + const newState = state.clone(); + this.analyzeStack(stack, newState); + modified = keepLooping = state.or(newState); + } while (keepLooping); + block.entryState = state.clone(); + return modified; + } + + /** + * @param {IntermediateInput} input + * @param {TypeState} state + * @returns {IntermediateInput} + * @private + */ + optimizeInput (input, state) { + for (const inputKey in input.inputs) { + const inputInput = input.inputs[inputKey]; + if (inputInput instanceof IntermediateInput) { + input.inputs[inputKey] = this.optimizeInput(inputInput, state); + } + } + + switch (input.opcode) { + case InputOpcode.CAST_NUMBER: { + const targetType = input.inputs.target.type; + if ((targetType & InputType.NUMBER) === targetType) { + return input.inputs.target; + } + return input; + } case InputOpcode.CAST_NUMBER_OR_NAN: { + const targetType = input.inputs.target.type; + if ((targetType & InputType.NUMBER_OR_NAN) === targetType) { + return input.inputs.target; + } + return input; + } + } + + return input; + } + + /** + * @param {IntermediateStack?} stack + * @param {TypeState} state The state of the project before this stack is run. + * @private + */ + optimizeStack (stack, state) { + if (!stack) return; + for (const stackBlock of stack.blocks) { + if (stackBlock.entryState) state = stackBlock.entryState; + for (const inputKey in stackBlock.inputs) { + const input = stackBlock.inputs[inputKey]; + if (input instanceof IntermediateInput) { + stackBlock.inputs[inputKey] = this.optimizeInput(input, state); + } else if (input instanceof IntermediateStack) { + this.optimizeStack(input, state); + } + } + if (stackBlock.exitState) { + state = stackBlock.exitState; + } + } + } + + /** + * @param {IntermediateScript} script + * @param {Set} alreadyOptimized + * @private + */ + optimizeScript (script, alreadyOptimized) { + if (script.isProcedure) { + if (alreadyOptimized.has(script.procedureCode)) { + return; + } + alreadyOptimized.add(script.procedureCode); + } + + for (const procVariant of script.dependedProcedures) { + this.optimizeScript(this.ir.procedures[procVariant], alreadyOptimized); + } + + script.cachedAnalysisEndState = new TypeState(); + this.analyzeStack(script.stack, script.cachedAnalysisEndState); + + this.optimizeStack(script.stack, new TypeState()); + } + + optimize () { + this.optimizeScript(this.ir.entry, new Set()); + } +} + + +module.exports = { + IROptimizer, + TypeState +}; diff --git a/src/compiler/jsexecute.js b/src/compiler/jsexecute.js index b7bff8956ad..a682f880913 100644 --- a/src/compiler/jsexecute.js +++ b/src/compiler/jsexecute.js @@ -1,3 +1,4 @@ +// @ts-check /** * @fileoverview Runtime for scripts generated by jsgen */ @@ -12,6 +13,7 @@ const globalState = { Cast: require('../util/cast'), log: require('../util/log'), blockUtility: require('./compat-block-utility'), + /** @type{import("../engine/thread")?} */ thread: null }; @@ -119,9 +121,8 @@ const waitPromise = function*(promise) { returnValue = value; thread.status = 0; // STATUS_RUNNING }, error => { - globalState.log.warn('Promise rejected in compiled script:', error); - returnValue = '' + error; thread.status = 0; // STATUS_RUNNING + globalState.log.warn('Promise rejected in compiled script:', error); }); yield; @@ -163,7 +164,7 @@ const executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, use return returnValue; } - if (thread.status === 1 /* STATUS_PROMISE_WAIT */ || thread.status === 4 /* STATUS_DONE */) { + if (thread.status === 1 /* STATUS_PROMISE_WAIT */) { // Something external is forcing us to stop yield; // Make up a return value because whatever is forcing us to stop can't specify one @@ -190,12 +191,14 @@ const executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, use return returnValue; } - if (thread.status === 1 /* STATUS_PROMISE_WAIT */ || thread.status === 4 /* STATUS_DONE */) { + if (thread.status === 1 /* STATUS_PROMISE_WAIT */) { yield; return finish(''); } } + // todo: do we have to do anything extra if status is STATUS_DONE? + return finish(returnValue); }`; @@ -586,7 +589,7 @@ runtimeFunctions.yieldThenCallGenerator = `const yieldThenCallGenerator = functi /** * Step a compiled thread. - * @param {Thread} thread The thread to step. + * @param {import("../engine/thread")} thread The thread to step. */ const execute = thread => { globalState.thread = thread; diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index d3e7784d81f..9f060c59cca 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -1,13 +1,12 @@ +// @ts-check + const log = require('../util/log'); -const Cast = require('../util/cast'); const BlockType = require('../extension-support/block-type'); const VariablePool = require('./variable-pool'); const jsexecute = require('./jsexecute'); const environment = require('./environment'); - -// Imported for JSDoc types, not to actually use -// eslint-disable-next-line no-unused-vars -const {IntermediateScript, IntermediateRepresentation} = require('./intermediate'); +const {StackOpcode, InputOpcode, InputType} = require('./enums.js'); +const {IntermediateStackBlock, IntermediateInput, IntermediateStack, IntermediateScript, IntermediateRepresentation} = require('./intermediate'); /** * @fileoverview Convert intermediate representations to JavaScript functions. @@ -24,12 +23,6 @@ const sanitize = string => { return JSON.stringify(string).slice(1, -1); }; -const TYPE_NUMBER = 1; -const TYPE_STRING = 2; -const TYPE_BOOLEAN = 3; -const TYPE_UNKNOWN = 4; -const TYPE_NUMBER_NAN = 5; - // Pen-related constants const PEN_EXT = 'runtime.ext_pen'; const PEN_STATE = `${PEN_EXT}._getPenState(target)`; @@ -49,281 +42,20 @@ const functionNameVariablePool = new VariablePool('fun'); */ const generatorNameVariablePool = new VariablePool('gen'); -/** - * @typedef Input - * @property {() => string} asNumber - * @property {() => string} asNumberOrNaN - * @property {() => string} asString - * @property {() => string} asBoolean - * @property {() => string} asColor - * @property {() => string} asUnknown - * @property {() => string} asSafe - * @property {() => boolean} isAlwaysNumber - * @property {() => boolean} isAlwaysNumberOrNaN - * @property {() => boolean} isNeverNumber - */ - -/** - * @implements {Input} - */ -class TypedInput { - constructor (source, type) { - // for debugging - if (typeof type !== 'number') throw new Error('type is invalid'); - this.source = source; - this.type = type; - } - - asNumber () { - if (this.type === TYPE_NUMBER) return this.source; - if (this.type === TYPE_NUMBER_NAN) return `(${this.source} || 0)`; - return `(+${this.source} || 0)`; - } - - asNumberOrNaN () { - if (this.type === TYPE_NUMBER || this.type === TYPE_NUMBER_NAN) return this.source; - return `(+${this.source})`; - } - - asString () { - if (this.type === TYPE_STRING) return this.source; - return `("" + ${this.source})`; - } - - asBoolean () { - if (this.type === TYPE_BOOLEAN) return this.source; - return `toBoolean(${this.source})`; - } - - asColor () { - return this.asUnknown(); - } - - asUnknown () { - return this.source; - } - - asSafe () { - return this.asUnknown(); - } - - isAlwaysNumber () { - return this.type === TYPE_NUMBER; - } - - isAlwaysNumberOrNaN () { - return this.type === TYPE_NUMBER || this.type === TYPE_NUMBER_NAN; - } - - isNeverNumber () { - return false; - } -} - -/** - * @implements {Input} - */ -class ConstantInput { - constructor (constantValue, safe) { - this.constantValue = constantValue; - this.safe = safe; - } - - asNumber () { - // Compute at compilation time - const numberValue = +this.constantValue; - if (numberValue) { - // It's important that we use the number's stringified value and not the constant value - // Using the constant value allows numbers such as "010" to be interpreted as 8 (or SyntaxError in strict mode) instead of 10. - return numberValue.toString(); - } - // numberValue is one of 0, -0, or NaN - if (Object.is(numberValue, -0)) { - return '-0'; - } - return '0'; - } - - asNumberOrNaN () { - return this.asNumber(); - } - - asString () { - return `"${sanitize('' + this.constantValue)}"`; - } - - asBoolean () { - // Compute at compilation time - return Cast.toBoolean(this.constantValue).toString(); - } - - asColor () { - // Attempt to parse hex code at compilation time - if (/^#[0-9a-f]{6,8}$/i.test(this.constantValue)) { - const hex = this.constantValue.substr(1); - return Number.parseInt(hex, 16).toString(); - } - return this.asUnknown(); - } - - asUnknown () { - // Attempt to convert strings to numbers if it is unlikely to break things - if (typeof this.constantValue === 'number') { - // todo: handle NaN? - return this.constantValue; - } - const numberValue = +this.constantValue; - if (numberValue.toString() === this.constantValue) { - return this.constantValue; - } - return this.asString(); - } - - asSafe () { - if (this.safe) { - return this.asUnknown(); - } - return this.asString(); - } - - isAlwaysNumber () { - const value = +this.constantValue; - if (Number.isNaN(value)) { - return false; - } - // Empty strings evaluate to 0 but should not be considered a number. - if (value === 0) { - return this.constantValue.toString().trim() !== ''; +const isSafeInputForEqualsOptimization = (input, other) => { + // Only optimize constants + if (input.opcode !== InputOpcode.CONSTANT) return false; + // Only optimize when the constant can always be thought of as a number + if (input.isAlwaysType(InputType.NUMBER) || input.isAlwaysType(InputType.STRING_NUM)) { + if (other.isSometimesType(InputType.STRING_NAN) || other.isSometimesType(InputType.BOOLEAN_INTERPRETABLE)) { + // Never optimize 0 if the other input can be '' or a boolean. + // eg. if '< 0 = "" >' was optimized it would turn into `0 === +""`, + // which would be true even though Scratch would return false. + return (+input.inputs.value) !== 0; } return true; } - - isAlwaysNumberOrNaN () { - return this.isAlwaysNumber(); - } - - isNeverNumber () { - return Number.isNaN(+this.constantValue); - } -} - -/** - * @implements {Input} - */ -class VariableInput { - constructor (source) { - this.source = source; - this.type = TYPE_UNKNOWN; - /** - * The value this variable was most recently set to, if any. - * @type {Input} - * @private - */ - this._value = null; - } - - /** - * @param {Input} input The input this variable was most recently set to. - */ - setInput (input) { - if (input instanceof VariableInput) { - // When being set to another variable, extract the value it was set to. - // Otherwise, you may end up with infinite recursion in analysis methods when a variable is set to itself. - if (input._value) { - input = input._value; - } else { - this.type = TYPE_UNKNOWN; - this._value = null; - return; - } - } - this._value = input; - if (input instanceof TypedInput) { - this.type = input.type; - } else { - this.type = TYPE_UNKNOWN; - } - } - - asNumber () { - if (this.type === TYPE_NUMBER) return this.source; - if (this.type === TYPE_NUMBER_NAN) return `(${this.source} || 0)`; - return `(+${this.source} || 0)`; - } - - asNumberOrNaN () { - if (this.type === TYPE_NUMBER || this.type === TYPE_NUMBER_NAN) return this.source; - return `(+${this.source})`; - } - - asString () { - if (this.type === TYPE_STRING) return this.source; - return `("" + ${this.source})`; - } - - asBoolean () { - if (this.type === TYPE_BOOLEAN) return this.source; - return `toBoolean(${this.source})`; - } - - asColor () { - return this.asUnknown(); - } - - asUnknown () { - return this.source; - } - - asSafe () { - return this.asUnknown(); - } - - isAlwaysNumber () { - if (this._value) { - return this._value.isAlwaysNumber(); - } - return false; - } - - isAlwaysNumberOrNaN () { - if (this._value) { - return this._value.isAlwaysNumberOrNaN(); - } - return false; - } - - isNeverNumber () { - if (this._value) { - return this._value.isNeverNumber(); - } - return false; - } -} - -const getNamesOfCostumesAndSounds = runtime => { - const result = new Set(); - for (const target of runtime.targets) { - if (target.isOriginal) { - const sprite = target.sprite; - for (const costume of sprite.costumes) { - result.add(costume.name); - } - for (const sound of sprite.sounds) { - result.add(sound.name); - } - } - } - return result; -}; - -const isSafeConstantForEqualsOptimization = input => { - const numberValue = +input.constantValue; - // Do not optimize 0 - if (!numberValue) { - return false; - } - // Do not optimize numbers when the original form does not match - return numberValue.toString() === input.constantValue.toString(); + return false; }; /** @@ -350,7 +82,7 @@ class JSGenerator { /** * @param {IntermediateScript} script * @param {IntermediateRepresentation} ir - * @param {Target} target + * @param {import("../sprites/rendered-target")} target */ constructor (script, ir, target) { this.script = script; @@ -358,11 +90,6 @@ class JSGenerator { this.target = target; this.source = ''; - /** - * @type {Object.} - */ - this.variableInputs = {}; - this.isWarp = script.isWarp; this.isProcedure = script.isProcedure; this.warpTimer = script.warpTimer; @@ -375,12 +102,10 @@ class JSGenerator { /** * The current Frame. - * @type {Frame} + * @type {Frame?} */ this.currentFrame = null; - this.namesOfCostumesAndSounds = getNamesOfCostumesAndSounds(target.runtime); - this.localVariables = new VariablePool('a'); this._setupVariablesPool = new VariablePool('b'); this._setupVariables = {}; @@ -425,222 +150,230 @@ class JSGenerator { } /** - * @param {object} node Input node to compile. - * @returns {Input} Compiled input. + * @param {IntermediateInput} block Input node to compile. + * @returns {string} Compiled input. */ - descendInput (node) { - switch (node.kind) { - case 'addons.call': - return new TypedInput(`(${this.descendAddonCall(node)})`, TYPE_UNKNOWN); - - case 'args.boolean': - return new TypedInput(`toBoolean(p${node.index})`, TYPE_BOOLEAN); - case 'args.stringNumber': - return new TypedInput(`p${node.index}`, TYPE_UNKNOWN); - - case 'compat': + descendInput (block) { + const node = block.inputs; + switch (block.opcode) { + case InputOpcode.NOP: + return `""`; + + case InputOpcode.PROCEDURE_ARG_BOOLEAN: + return `toBoolean(p${node.index})`; + case InputOpcode.PROCEDURE_ARG_STRING_NUMBER: + return `p${node.index}`; + + case InputOpcode.ADDON_CALL: + return `(${this.descendAddonCall(node)})`; + + case InputOpcode.CAST_BOOLEAN: + return `toBoolean(${this.descendInput(node.target)})`; + case InputOpcode.CAST_NUMBER: + if (node.target.isAlwaysType(InputType.BOOLEAN_INTERPRETABLE)) { + return `(+${this.descendInput(node.target.toType(InputType.BOOLEAN))})`; + } + if (node.target.isAlwaysType(InputType.NUMBER_OR_NAN)) { + return `(${this.descendInput(node.target)} || 0)`; + } + return `(+${this.descendInput(node.target)} || 0)`; + case InputOpcode.CAST_NUMBER_OR_NAN: + return `(+${this.descendInput(node.target)})`; + case InputOpcode.CAST_NUMBER_INDEX: + return `(${this.descendInput(node.target.toType(InputType.NUMBER_OR_NAN))} | 0)`; + case InputOpcode.CAST_STRING: + return `("" + ${this.descendInput(node.target)})`; + + case InputOpcode.COMPATIBILITY_LAYER: // Compatibility layer inputs never use flags. - return new TypedInput(`(${this.generateCompatibilityLayerCall(node, false)})`, TYPE_UNKNOWN); - - case 'constant': - return this.safeConstantInput(node.value); - - case 'counter.get': - return new TypedInput('runtime.ext_scratch3_control._counter', TYPE_NUMBER); - - case 'keyboard.pressed': - return new TypedInput(`runtime.ioDevices.keyboard.getKeyIsDown(${this.descendInput(node.key).asSafe()})`, TYPE_BOOLEAN); - - case 'list.contains': - return new TypedInput(`listContains(${this.referenceVariable(node.list)}, ${this.descendInput(node.item).asUnknown()})`, TYPE_BOOLEAN); - case 'list.contents': - return new TypedInput(`listContents(${this.referenceVariable(node.list)})`, TYPE_STRING); - case 'list.get': { - const index = this.descendInput(node.index); + return `(${this.generateCompatibilityLayerCall(node, false)})`; + + case InputOpcode.CONSTANT: + if (block.isAlwaysType(InputType.NUMBER)) { + if (typeof node.value !== 'number') throw new Error(`JS: '${block.type}' type constant had ${typeof node.value} type value. Expected number.`); + if (Object.is(node.value, -0)) return '-0'; + return node.value.toString(); + } else if (block.isAlwaysType(InputType.BOOLEAN)) { + if (typeof node.value !== 'boolean') throw new Error(`JS: '${block.type}' type constant had ${typeof node.value} type value. Expected boolean.`); + return node.value.toString(); + } else if (block.isSometimesType(InputType.STRING)) { + return `"${sanitize(node.value.toString())}"`; + } throw new Error(`JS: Unknown constant input type '${block.type}'.`); + + case InputOpcode.SENSING_KEY_DOWN: + return `runtime.ioDevices.keyboard.getKeyIsDown(${this.descendInput(node.key)})`; + + case InputOpcode.LIST_CONTAINS: + return `listContains(${this.referenceVariable(node.list)}, ${this.descendInput(node.item)})`; + case InputOpcode.LIST_CONTENTS: + return `listContents(${this.referenceVariable(node.list)})`; + case InputOpcode.LIST_GET: { if (environment.supportsNullishCoalescing) { - if (index.isAlwaysNumberOrNaN()) { - return new TypedInput(`(${this.referenceVariable(node.list)}.value[(${index.asNumber()} | 0) - 1] ?? "")`, TYPE_UNKNOWN); + if (node.index.isAlwaysType(InputType.NUMBER_INTERPRETABLE | InputType.NUMBER_NAN)) { + return `(${this.referenceVariable(node.list)}.value[${this.descendInput(node.index.toType(InputType.NUMBER_INDEX))} - 1] ?? "")`; } - if (index instanceof ConstantInput && index.constantValue === 'last') { - return new TypedInput(`(${this.referenceVariable(node.list)}.value[${this.referenceVariable(node.list)}.value.length - 1] ?? "")`, TYPE_UNKNOWN); + if (node.index.isConstant('last')) { + return `(${this.referenceVariable(node.list)}.value[${this.referenceVariable(node.list)}.value.length - 1] ?? "")`; } } - return new TypedInput(`listGet(${this.referenceVariable(node.list)}.value, ${index.asUnknown()})`, TYPE_UNKNOWN); + return `listGet(${this.referenceVariable(node.list)}.value, ${this.descendInput(node.index)})`; } - case 'list.indexOf': - return new TypedInput(`listIndexOf(${this.referenceVariable(node.list)}, ${this.descendInput(node.item).asUnknown()})`, TYPE_NUMBER); - case 'list.length': - return new TypedInput(`${this.referenceVariable(node.list)}.value.length`, TYPE_NUMBER); - - case 'looks.size': - return new TypedInput('Math.round(target.size)', TYPE_NUMBER); - case 'looks.backdropName': - return new TypedInput('stage.getCostumes()[stage.currentCostume].name', TYPE_STRING); - case 'looks.backdropNumber': - return new TypedInput('(stage.currentCostume + 1)', TYPE_NUMBER); - case 'looks.costumeName': - return new TypedInput('target.getCostumes()[target.currentCostume].name', TYPE_STRING); - case 'looks.costumeNumber': - return new TypedInput('(target.currentCostume + 1)', TYPE_NUMBER); - - case 'motion.direction': - return new TypedInput('target.direction', TYPE_NUMBER); - case 'motion.x': - return new TypedInput('limitPrecision(target.x)', TYPE_NUMBER); - case 'motion.y': - return new TypedInput('limitPrecision(target.y)', TYPE_NUMBER); - - case 'mouse.down': - return new TypedInput('runtime.ioDevices.mouse.getIsDown()', TYPE_BOOLEAN); - case 'mouse.x': - return new TypedInput('runtime.ioDevices.mouse.getScratchX()', TYPE_NUMBER); - case 'mouse.y': - return new TypedInput('runtime.ioDevices.mouse.getScratchY()', TYPE_NUMBER); - - case 'noop': - return new TypedInput('""', TYPE_STRING); - - case 'op.abs': - return new TypedInput(`Math.abs(${this.descendInput(node.value).asNumber()})`, TYPE_NUMBER); - case 'op.acos': - // Needs to be marked as NaN because Math.acos(1.0001) === NaN - return new TypedInput(`((Math.acos(${this.descendInput(node.value).asNumber()}) * 180) / Math.PI)`, TYPE_NUMBER_NAN); - case 'op.add': - // Needs to be marked as NaN because Infinity + -Infinity === NaN - return new TypedInput(`(${this.descendInput(node.left).asNumber()} + ${this.descendInput(node.right).asNumber()})`, TYPE_NUMBER_NAN); - case 'op.and': - return new TypedInput(`(${this.descendInput(node.left).asBoolean()} && ${this.descendInput(node.right).asBoolean()})`, TYPE_BOOLEAN); - case 'op.asin': - // Needs to be marked as NaN because Math.asin(1.0001) === NaN - return new TypedInput(`((Math.asin(${this.descendInput(node.value).asNumber()}) * 180) / Math.PI)`, TYPE_NUMBER_NAN); - case 'op.atan': - return new TypedInput(`((Math.atan(${this.descendInput(node.value).asNumber()}) * 180) / Math.PI)`, TYPE_NUMBER); - case 'op.ceiling': - return new TypedInput(`Math.ceil(${this.descendInput(node.value).asNumber()})`, TYPE_NUMBER); - case 'op.contains': - return new TypedInput(`(${this.descendInput(node.string).asString()}.toLowerCase().indexOf(${this.descendInput(node.contains).asString()}.toLowerCase()) !== -1)`, TYPE_BOOLEAN); - case 'op.cos': - return new TypedInput(`(Math.round(Math.cos((Math.PI * ${this.descendInput(node.value).asNumber()}) / 180) * 1e10) / 1e10)`, TYPE_NUMBER_NAN); - case 'op.divide': - // Needs to be marked as NaN because 0 / 0 === NaN - return new TypedInput(`(${this.descendInput(node.left).asNumber()} / ${this.descendInput(node.right).asNumber()})`, TYPE_NUMBER_NAN); - case 'op.equals': { - const left = this.descendInput(node.left); - const right = this.descendInput(node.right); - // When both operands are known to never be numbers, only use string comparison to avoid all number parsing. - if (left.isNeverNumber() || right.isNeverNumber()) { - return new TypedInput(`(${left.asString()}.toLowerCase() === ${right.asString()}.toLowerCase())`, TYPE_BOOLEAN); - } - const leftAlwaysNumber = left.isAlwaysNumber(); - const rightAlwaysNumber = right.isAlwaysNumber(); + case InputOpcode.LIST_INDEX_OF: + return `listIndexOf(${this.referenceVariable(node.list)}, ${this.descendInput(node.item)})`; + case InputOpcode.LIST_LENGTH: + return `${this.referenceVariable(node.list)}.value.length`; + + case InputOpcode.LOOKS_SIZE_GET: + return 'Math.round(target.size)'; + case InputOpcode.LOOKS_BACKDROP_NAME: + return 'stage.getCostumes()[stage.currentCostume].name'; + case InputOpcode.LOOKS_BACKDROP_NUMBER: + return '(stage.currentCostume + 1)'; + case InputOpcode.LOOKS_COSTUME_NAME: + return 'target.getCostumes()[target.currentCostume].name'; + case InputOpcode.LOOKS_COSTUME_NUMBER: + return '(target.currentCostume + 1)'; + + case InputOpcode.MOTION_DIRECTION_GET: + return 'target.direction'; + case InputOpcode.MOTION_X_GET: + return 'limitPrecision(target.x)'; + case InputOpcode.MOTION_Y_GET: + return 'limitPrecision(target.y)'; + + case InputOpcode.SENSING_MOUSE_DOWN: + return 'runtime.ioDevices.mouse.getIsDown()'; + case InputOpcode.SENSING_MOUSE_X: + return 'runtime.ioDevices.mouse.getScratchX()'; + case InputOpcode.SENSING_MOUSE_Y: + return 'runtime.ioDevices.mouse.getScratchY()'; + + case InputOpcode.OP_ABS: + return `Math.abs(${this.descendInput(node.value)})`; + case InputOpcode.OP_ACOS: + return `((Math.acos(${this.descendInput(node.value)}) * 180) / Math.PI)`; + case InputOpcode.OP_ADD: + return `(${this.descendInput(node.left)} + ${this.descendInput(node.right)})`; + case InputOpcode.OP_AND: + return `(${this.descendInput(node.left)} && ${this.descendInput(node.right)})`; + case InputOpcode.OP_ASIN: + return `((Math.asin(${this.descendInput(node.value)}) * 180) / Math.PI)`; + case InputOpcode.OP_ATAN: + return `((Math.atan(${this.descendInput(node.value)}) * 180) / Math.PI)`; + case InputOpcode.OP_CEILING: + return `Math.ceil(${this.descendInput(node.value)})`; + case InputOpcode.OP_CONTAINS: + return `(${this.descendInput(node.string)}.toLowerCase().indexOf(${this.descendInput(node.contains)}.toLowerCase()) !== -1)`; + case InputOpcode.OP_COS: + return `(Math.round(Math.cos((Math.PI * ${this.descendInput(node.value)}) / 180) * 1e10) / 1e10)`; + case InputOpcode.OP_DIVIDE: + return `(${this.descendInput(node.left)} / ${this.descendInput(node.right)})`; + case InputOpcode.OP_EQUALS: { + const left = node.left; + const right = node.right; + // When both operands are known to be numbers, we can use === - if (leftAlwaysNumber && rightAlwaysNumber) { - return new TypedInput(`(${left.asNumber()} === ${right.asNumber()})`, TYPE_BOOLEAN); + if (left.isAlwaysType(InputType.NUMBER_INTERPRETABLE) && right.isAlwaysType(InputType.NUMBER_INTERPRETABLE)) { + return `(${this.descendInput(left.toType(InputType.NUMBER))} === ${this.descendInput(right.toType(InputType.NUMBER))})`; } // In certain conditions, we can use === when one of the operands is known to be a safe number. - if (leftAlwaysNumber && left instanceof ConstantInput && isSafeConstantForEqualsOptimization(left)) { - return new TypedInput(`(${left.asNumber()} === ${right.asNumber()})`, TYPE_BOOLEAN); + if (isSafeInputForEqualsOptimization(left, right) || isSafeInputForEqualsOptimization(right, left)) { + return `(${this.descendInput(left.toType(InputType.NUMBER))} === ${this.descendInput(right.toType(InputType.NUMBER))})`; } - if (rightAlwaysNumber && right instanceof ConstantInput && isSafeConstantForEqualsOptimization(right)) { - return new TypedInput(`(${left.asNumber()} === ${right.asNumber()})`, TYPE_BOOLEAN); + // When either operand is known to never be a number, only use string comparison to avoid all number parsing. + if (!left.isSometimesType(InputType.NUMBER_INTERPRETABLE) || !right.isSometimesType(InputType.NUMBER_INTERPRETABLE)) { + return `(${this.descendInput(left.toType(InputType.STRING))}.toLowerCase() === ${this.descendInput(right.toType(InputType.STRING))}.toLowerCase())`; } // No compile-time optimizations possible - use fallback method. - return new TypedInput(`compareEqual(${left.asUnknown()}, ${right.asUnknown()})`, TYPE_BOOLEAN); + return `compareEqual(${this.descendInput(left)}, ${this.descendInput(right)})`; } - case 'op.e^': - return new TypedInput(`Math.exp(${this.descendInput(node.value).asNumber()})`, TYPE_NUMBER); - case 'op.floor': - return new TypedInput(`Math.floor(${this.descendInput(node.value).asNumber()})`, TYPE_NUMBER); - case 'op.greater': { - const left = this.descendInput(node.left); - const right = this.descendInput(node.right); + case InputOpcode.OP_POW_E: + return `Math.exp(${this.descendInput(node.value)})`; + case InputOpcode.OP_FLOOR: + return `Math.floor(${this.descendInput(node.value)})`; + case InputOpcode.OP_GREATER: { + const left = node.left; + const right = node.right; // When the left operand is a number and the right operand is a number or NaN, we can use > - if (left.isAlwaysNumber() && right.isAlwaysNumberOrNaN()) { - return new TypedInput(`(${left.asNumber()} > ${right.asNumberOrNaN()})`, TYPE_BOOLEAN); + if (left.isAlwaysType(InputType.NUMBER_INTERPRETABLE) && right.isAlwaysType(InputType.NUMBER_INTERPRETABLE | InputType.NUMBER_NAN)) { + return `(${this.descendInput(left.toType(InputType.NUMBER))} > ${this.descendInput(right.toType(InputType.NUMBER_OR_NAN))})`; } // When the left operand is a number or NaN and the right operand is a number, we can negate <= - if (left.isAlwaysNumberOrNaN() && right.isAlwaysNumber()) { - return new TypedInput(`!(${left.asNumberOrNaN()} <= ${right.asNumber()})`, TYPE_BOOLEAN); + if (left.isAlwaysType(InputType.NUMBER_INTERPRETABLE | InputType.NUMBER_NAN) && right.isAlwaysType(InputType.NUMBER_INTERPRETABLE)) { + return `!(${this.descendInput(left.toType(InputType.NUMBER_OR_NAN))} <= ${this.descendInput(right.toType(InputType.NUMBER))})`; } // When either operand is known to never be a number, avoid all number parsing. - if (left.isNeverNumber() || right.isNeverNumber()) { - return new TypedInput(`(${left.asString()}.toLowerCase() > ${right.asString()}.toLowerCase())`, TYPE_BOOLEAN); + if (!left.isSometimesType(InputType.NUMBER_INTERPRETABLE) || !right.isSometimesType(InputType.NUMBER_INTERPRETABLE)) { + return `(${this.descendInput(left.toType(InputType.STRING))}.toLowerCase() > ${this.descendInput(right.toType(InputType.STRING))}.toLowerCase())`; } // No compile-time optimizations possible - use fallback method. - return new TypedInput(`compareGreaterThan(${left.asUnknown()}, ${right.asUnknown()})`, TYPE_BOOLEAN); + return `compareGreaterThan(${this.descendInput(left)}, ${this.descendInput(right)})`; } - case 'op.join': - return new TypedInput(`(${this.descendInput(node.left).asString()} + ${this.descendInput(node.right).asString()})`, TYPE_STRING); - case 'op.length': - return new TypedInput(`${this.descendInput(node.string).asString()}.length`, TYPE_NUMBER); - case 'op.less': { - const left = this.descendInput(node.left); - const right = this.descendInput(node.right); + case InputOpcode.OP_JOIN: + return `(${this.descendInput(node.left)} + ${this.descendInput(node.right)})`; + case InputOpcode.OP_LENGTH: + return `${this.descendInput(node.string)}.length`; + case InputOpcode.OP_LESS: { + const left = node.left; + const right = node.right; // When the left operand is a number or NaN and the right operand is a number, we can use < - if (left.isAlwaysNumberOrNaN() && right.isAlwaysNumber()) { - return new TypedInput(`(${left.asNumberOrNaN()} < ${right.asNumber()})`, TYPE_BOOLEAN); + if (left.isAlwaysType(InputType.NUMBER_INTERPRETABLE | InputType.NUMBER_NAN) && right.isAlwaysType(InputType.NUMBER_INTERPRETABLE)) { + return `(${this.descendInput(left.toType(InputType.NUMBER_OR_NAN))} < ${this.descendInput(right.toType(InputType.NUMBER))})`; } // When the left operand is a number and the right operand is a number or NaN, we can negate >= - if (left.isAlwaysNumber() && right.isAlwaysNumberOrNaN()) { - return new TypedInput(`!(${left.asNumber()} >= ${right.asNumberOrNaN()})`, TYPE_BOOLEAN); + if (left.isAlwaysType(InputType.NUMBER_INTERPRETABLE) && right.isAlwaysType(InputType.NUMBER_INTERPRETABLE | InputType.NUMBER_NAN)) { + return `!(${this.descendInput(left.toType(InputType.NUMBER))} >= ${this.descendInput(right.toType(InputType.NUMBER_OR_NAN))})`; } // When either operand is known to never be a number, avoid all number parsing. - if (left.isNeverNumber() || right.isNeverNumber()) { - return new TypedInput(`(${left.asString()}.toLowerCase() < ${right.asString()}.toLowerCase())`, TYPE_BOOLEAN); + if (!left.isSometimesType(InputType.NUMBER_INTERPRETABLE) || !right.isSometimesType(InputType.NUMBER_INTERPRETABLE)) { + return `(${this.descendInput(left.toType(InputType.STRING))}.toLowerCase() < ${this.descendInput(right.toType(InputType.STRING))}.toLowerCase())`; } // No compile-time optimizations possible - use fallback method. - return new TypedInput(`compareLessThan(${left.asUnknown()}, ${right.asUnknown()})`, TYPE_BOOLEAN); + return `compareLessThan(${this.descendInput(left)}, ${this.descendInput(right)})`; } - case 'op.letterOf': - return new TypedInput(`((${this.descendInput(node.string).asString()})[(${this.descendInput(node.letter).asNumber()} | 0) - 1] || "")`, TYPE_STRING); - case 'op.ln': - // Needs to be marked as NaN because Math.log(-1) == NaN - return new TypedInput(`Math.log(${this.descendInput(node.value).asNumber()})`, TYPE_NUMBER_NAN); - case 'op.log': - // Needs to be marked as NaN because Math.log(-1) == NaN - return new TypedInput(`(Math.log(${this.descendInput(node.value).asNumber()}) / Math.LN10)`, TYPE_NUMBER_NAN); - case 'op.mod': + case InputOpcode.OP_LETTER_OF: + return `((${this.descendInput(node.string)})[${this.descendInput(node.letter)} - 1] || "")`; + case InputOpcode.OP_LOG_E: + return `Math.log(${this.descendInput(node.value)})`; + case InputOpcode.OP_LOG_10: + return `(Math.log(${this.descendInput(node.value)}) / Math.LN10)`; + case InputOpcode.OP_MOD: this.descendedIntoModulo = true; - // Needs to be marked as NaN because mod(0, 0) (and others) == NaN - return new TypedInput(`mod(${this.descendInput(node.left).asNumber()}, ${this.descendInput(node.right).asNumber()})`, TYPE_NUMBER_NAN); - case 'op.multiply': - // Needs to be marked as NaN because Infinity * 0 === NaN - return new TypedInput(`(${this.descendInput(node.left).asNumber()} * ${this.descendInput(node.right).asNumber()})`, TYPE_NUMBER_NAN); - case 'op.not': - return new TypedInput(`!${this.descendInput(node.operand).asBoolean()}`, TYPE_BOOLEAN); - case 'op.or': - return new TypedInput(`(${this.descendInput(node.left).asBoolean()} || ${this.descendInput(node.right).asBoolean()})`, TYPE_BOOLEAN); - case 'op.random': + return `mod(${this.descendInput(node.left)}, ${this.descendInput(node.right)})`; + case InputOpcode.OP_MULTIPLY: + return `(${this.descendInput(node.left)} * ${this.descendInput(node.right)})`; + case InputOpcode.OP_NOT: + return `!${this.descendInput(node.operand)}`; + case InputOpcode.OP_OR: + return `(${this.descendInput(node.left)} || ${this.descendInput(node.right)})`; + case InputOpcode.OP_RANDOM: if (node.useInts) { - // Both inputs are ints, so we know neither are NaN - return new TypedInput(`randomInt(${this.descendInput(node.low).asNumber()}, ${this.descendInput(node.high).asNumber()})`, TYPE_NUMBER); + return `randomInt(${this.descendInput(node.low)}, ${this.descendInput(node.high)})`; } if (node.useFloats) { - return new TypedInput(`randomFloat(${this.descendInput(node.low).asNumber()}, ${this.descendInput(node.high).asNumber()})`, TYPE_NUMBER_NAN); + return `randomFloat(${this.descendInput(node.low)}, ${this.descendInput(node.high)})`; } - return new TypedInput(`runtime.ext_scratch3_operators._random(${this.descendInput(node.low).asUnknown()}, ${this.descendInput(node.high).asUnknown()})`, TYPE_NUMBER_NAN); - case 'op.round': - return new TypedInput(`Math.round(${this.descendInput(node.value).asNumber()})`, TYPE_NUMBER); - case 'op.sin': - return new TypedInput(`(Math.round(Math.sin((Math.PI * ${this.descendInput(node.value).asNumber()}) / 180) * 1e10) / 1e10)`, TYPE_NUMBER_NAN); - case 'op.sqrt': - // Needs to be marked as NaN because Math.sqrt(-1) === NaN - return new TypedInput(`Math.sqrt(${this.descendInput(node.value).asNumber()})`, TYPE_NUMBER_NAN); - case 'op.subtract': - // Needs to be marked as NaN because Infinity - Infinity === NaN - return new TypedInput(`(${this.descendInput(node.left).asNumber()} - ${this.descendInput(node.right).asNumber()})`, TYPE_NUMBER_NAN); - case 'op.tan': - return new TypedInput(`tan(${this.descendInput(node.value).asNumber()})`, TYPE_NUMBER_NAN); - case 'op.10^': - return new TypedInput(`(10 ** ${this.descendInput(node.value).asNumber()})`, TYPE_NUMBER); - - case 'procedures.call': { + return `runtime.ext_scratch3_operators._random(${this.descendInput(node.low)}, ${this.descendInput(node.high)})`; + case InputOpcode.OP_ROUND: + return `Math.round(${this.descendInput(node.value)})`; + case InputOpcode.OP_SIN: + return `(Math.round(Math.sin((Math.PI * ${this.descendInput(node.value)}) / 180) * 1e10) / 1e10)`; + case InputOpcode.OP_SQRT: + return `Math.sqrt(${this.descendInput(node.value)})`; + case InputOpcode.OP_SUBTRACT: + return `(${this.descendInput(node.left)} - ${this.descendInput(node.right)})`; + case InputOpcode.OP_TAN: + return `tan(${this.descendInput(node.value)})`; + case InputOpcode.OP_POW_10: + return `(10 ** ${this.descendInput(node.value)})`; + + case InputOpcode.PROCEDURE_CALL: { const procedureCode = node.code; const procedureVariant = node.variant; const procedureData = this.ir.procedures[procedureVariant]; if (procedureData.stack === null) { // TODO still need to evaluate arguments for side effects - return new TypedInput('""', TYPE_STRING); + return '""'; } // Recursion makes this complicated because: @@ -650,7 +383,7 @@ class JSGenerator { const procedureReference = `thread.procedures["${sanitize(procedureVariant)}"]`; const args = []; for (const input of node.arguments) { - args.push(this.descendInput(input).asSafe()); + args.push(this.descendInput(input)); } const joinedArgs = args.join(','); @@ -658,109 +391,105 @@ class JSGenerator { const yieldForHat = this.isInHat; if (yieldForRecursion || yieldForHat) { const runtimeFunction = procedureData.yields ? 'yieldThenCallGenerator' : 'yieldThenCall'; - return new TypedInput(`(yield* ${runtimeFunction}(${procedureReference}, ${joinedArgs}))`, TYPE_UNKNOWN); + return `(yield* ${runtimeFunction}(${procedureReference}, ${joinedArgs}))`; } if (procedureData.yields) { - return new TypedInput(`(yield* ${procedureReference}(${joinedArgs}))`, TYPE_UNKNOWN); + return `(yield* ${procedureReference}(${joinedArgs}))`; } - return new TypedInput(`${procedureReference}(${joinedArgs})`, TYPE_UNKNOWN); + return `${procedureReference}(${joinedArgs})`; } - case 'sensing.answer': - return new TypedInput(`runtime.ext_scratch3_sensing._answer`, TYPE_STRING); - case 'sensing.colorTouchingColor': - return new TypedInput(`target.colorIsTouchingColor(colorToList(${this.descendInput(node.target).asColor()}), colorToList(${this.descendInput(node.mask).asColor()}))`, TYPE_BOOLEAN); - case 'sensing.date': - return new TypedInput(`(new Date().getDate())`, TYPE_NUMBER); - case 'sensing.dayofweek': - return new TypedInput(`(new Date().getDay() + 1)`, TYPE_NUMBER); - case 'sensing.daysSince2000': - return new TypedInput('daysSince2000()', TYPE_NUMBER); - case 'sensing.distance': + case InputOpcode.SENSING_ANSWER: + return `runtime.ext_scratch3_sensing._answer`; + case InputOpcode.SENSING_COLOR_TOUCHING_COLOR: + return `target.colorIsTouchingColor(colorToList(${this.descendInput(node.target)}), colorToList(${this.descendInput(node.mask)}))`; + case InputOpcode.SENSING_TIME_DATE: + return `(new Date().getDate())`; + case InputOpcode.SENSING_TIME_WEEKDAY: + return `(new Date().getDay() + 1)`; + case InputOpcode.SENSING_TIME_DAYS_SINCE_2000: + return 'daysSince2000()'; + case InputOpcode.SENSING_DISTANCE: // TODO: on stages, this can be computed at compile time - return new TypedInput(`distance(${this.descendInput(node.target).asString()})`, TYPE_NUMBER); - case 'sensing.hour': - return new TypedInput(`(new Date().getHours())`, TYPE_NUMBER); - case 'sensing.minute': - return new TypedInput(`(new Date().getMinutes())`, TYPE_NUMBER); - case 'sensing.month': - return new TypedInput(`(new Date().getMonth() + 1)`, TYPE_NUMBER); - case 'sensing.of': { - const object = this.descendInput(node.object).asString(); - const property = node.property; - if (node.object.kind === 'constant') { - const isStage = node.object.value === '_stage_'; - // Note that if target isn't a stage, we can't assume it exists - const objectReference = isStage ? 'stage' : this.evaluateOnce(`runtime.getSpriteTargetByName(${object})`); - if (property === 'volume') { - return new TypedInput(`(${objectReference} ? ${objectReference}.volume : 0)`, TYPE_NUMBER); - } - if (isStage) { - switch (property) { - case 'background #': - // fallthrough for scratch 1.0 compatibility - case 'backdrop #': - return new TypedInput(`(${objectReference}.currentCostume + 1)`, TYPE_NUMBER); - case 'backdrop name': - return new TypedInput(`${objectReference}.getCostumes()[${objectReference}.currentCostume].name`, TYPE_STRING); - } - } else { - switch (property) { - case 'x position': - return new TypedInput(`(${objectReference} ? ${objectReference}.x : 0)`, TYPE_NUMBER); - case 'y position': - return new TypedInput(`(${objectReference} ? ${objectReference}.y : 0)`, TYPE_NUMBER); - case 'direction': - return new TypedInput(`(${objectReference} ? ${objectReference}.direction : 0)`, TYPE_NUMBER); - case 'costume #': - return new TypedInput(`(${objectReference} ? ${objectReference}.currentCostume + 1 : 0)`, TYPE_NUMBER); - case 'costume name': - return new TypedInput(`(${objectReference} ? ${objectReference}.getCostumes()[${objectReference}.currentCostume].name : 0)`, TYPE_UNKNOWN); - case 'size': - return new TypedInput(`(${objectReference} ? ${objectReference}.size : 0)`, TYPE_NUMBER); - } - } - const variableReference = this.evaluateOnce(`${objectReference} && ${objectReference}.lookupVariableByNameAndType("${sanitize(property)}", "", true)`); - return new TypedInput(`(${variableReference} ? ${variableReference}.value : 0)`, TYPE_UNKNOWN); - } - return new TypedInput(`runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ${object}, PROPERTY: "${sanitize(property)}" })`, TYPE_UNKNOWN); - } - case 'sensing.second': - return new TypedInput(`(new Date().getSeconds())`, TYPE_NUMBER); - case 'sensing.touching': - return new TypedInput(`target.isTouchingObject(${this.descendInput(node.object).asUnknown()})`, TYPE_BOOLEAN); - case 'sensing.touchingColor': - return new TypedInput(`target.isTouchingColor(colorToList(${this.descendInput(node.color).asColor()}))`, TYPE_BOOLEAN); - case 'sensing.username': - return new TypedInput('runtime.ioDevices.userData.getUsername()', TYPE_STRING); - case 'sensing.year': - return new TypedInput(`(new Date().getFullYear())`, TYPE_NUMBER); - - case 'timer.get': - return new TypedInput('runtime.ioDevices.clock.projectTimer()', TYPE_NUMBER); - - case 'tw.lastKeyPressed': - return new TypedInput('runtime.ioDevices.keyboard.getLastKeyPressed()', TYPE_STRING); - - case 'var.get': - return this.descendVariable(node.variable); + return `distance(${this.descendInput(node.target)})`; + case InputOpcode.SENSING_TIME_HOUR: + return `(new Date().getHours())`; + case InputOpcode.SENSING_TIME_MINUTE: + return `(new Date().getMinutes())`; + case InputOpcode.SENSING_TIME_MONTH: + return `(new Date().getMonth() + 1)`; + case InputOpcode.SENSING_OF: + return `runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ${this.descendInput(node.object)}, PROPERTY: "${sanitize(node.property)}" })`; + case InputOpcode.SENSING_OF_VOLUME: { + const targetRef = this.descendTargetReference(node.object); + return `(${targetRef} ? ${targetRef}.volume : 0)`; + } case InputOpcode.SENSING_OF_BACKDROP_NUMBER: + return `(stage.currentCostume + 1)`; + case InputOpcode.SENSING_OF_BACKDROP_NAME: + return `stage.getCostumes()[stage.currentCostume].name`; + case InputOpcode.SENSING_OF_POS_X: { + const targetRef = this.descendTargetReference(node.object); + return `(${targetRef} ? ${targetRef}.x : 0)`; + } case InputOpcode.SENSING_OF_POS_Y: { + const targetRef = this.descendTargetReference(node.object); + return `(${targetRef} ? ${targetRef}.y : 0)`; + } case InputOpcode.SENSING_OF_DIRECTION: { + const targetRef = this.descendTargetReference(node.object); + return `(${targetRef} ? ${targetRef}.direction : 0)`; + } case InputOpcode.SENSING_OF_COSTUME_NUMBER: { + const targetRef = this.descendTargetReference(node.object); + return `(${targetRef} ? ${targetRef}.currentCostume + 1 : 0)`; + } case InputOpcode.SENSING_OF_COSTUME_NAME: { + const targetRef = this.descendTargetReference(node.object); + return `(${targetRef} ? ${targetRef}.getCostumes()[${targetRef}.currentCostume].name : 0)`; + } case InputOpcode.SENSING_OF_SIZE: { + const targetRef = this.descendTargetReference(node.object); + return `(${targetRef} ? ${targetRef}.size : 0)`; + } case InputOpcode.SENSING_OF_VAR: { + const targetRef = this.descendTargetReference(node.object); + const varRef = this.evaluateOnce(`${targetRef} && ${targetRef}.lookupVariableByNameAndType("${sanitize(node.property)}", "", true)`); + return `(${varRef} ? ${varRef}.value : 0)`; + } case InputOpcode.SENSING_TIME_SECOND: + return `(new Date().getSeconds())`; + case InputOpcode.SENSING_TOUCHING_OBJECT: + return `target.isTouchingObject(${this.descendInput(node.object)})`; + case InputOpcode.SENSING_TOUCHING_COLOR: + return `target.isTouchingColor(colorToList(${this.descendInput(node.color)}))`; + case InputOpcode.SENSING_USERNAME: + return 'runtime.ioDevices.userData.getUsername()'; + case InputOpcode.SENSING_TIME_YEAR: + return `(new Date().getFullYear())`; + + case InputOpcode.SENSING_TIMER_GET: + return 'runtime.ioDevices.clock.projectTimer()'; + + case InputOpcode.CONTROL_COUNTER: + return 'runtime.ext_scratch3_control._counter'; + + case InputOpcode.TW_KEY_LAST_PRESSED: + return 'runtime.ioDevices.keyboard.getLastKeyPressed()'; + + case InputOpcode.VAR_GET: + return `${this.referenceVariable(node.variable)}.value`; default: - log.warn(`JS: Unknown input: ${node.kind}`, node); - throw new Error(`JS: Unknown input: ${node.kind}`); + log.warn(`JS: Unknown input: ${block.opcode}`, node); + throw new Error(`JS: Unknown input: ${block.opcode}`); } } /** - * @param {*} node Stacked node to compile. + * @param {IntermediateStackBlock} block Stacked block to compile. */ - descendStackedBlock (node) { - switch (node.kind) { - case 'addons.call': + descendStackedBlock (block) { + const node = block.inputs; + switch (block.opcode) { + case StackOpcode.ADDON_CALL: { this.source += `${this.descendAddonCall(node)};\n`; break; + } - case 'compat': { + case StackOpcode.COMPATIBILITY_LAYER: { // If the last command in a loop returns a promise, immediately continue to the next iteration. // If you don't do this, the loop effectively yields twice per iteration and will run at half-speed. const isLastInLoop = this.isLastBlockInLoop(); @@ -773,9 +502,9 @@ class JSGenerator { this.source += `const ${branchVariable} = createBranchInfo(${blockType === BlockType.LOOP});\n`; this.source += `while (${branchVariable}.branch = +(${this.generateCompatibilityLayerCall(node, false, branchVariable)})) {\n`; this.source += `switch (${branchVariable}.branch) {\n`; - for (const index in node.substacks) { - this.source += `case ${+index}: {\n`; - this.descendStack(node.substacks[index], new Frame(false)); + for (let i = 0; i < node.substacks.length; i++) { + this.source += `case ${i + 1}: {\n`; + this.descendStack(node.substacks[i], new Frame(false)); this.source += `break;\n`; this.source += `}\n`; // close case } @@ -793,61 +522,86 @@ class JSGenerator { break; } - case 'control.createClone': - this.source += `runtime.ext_scratch3_control._createClone(${this.descendInput(node.target).asString()}, target);\n`; + case StackOpcode.HAT_EDGE: + this.isInHat = true; + this.source += '{\n'; + // For exact Scratch parity, evaluate the input before checking old edge state. + // Can matter if the input is not instantly evaluated. + this.source += `const resolvedValue = ${this.descendInput(node.condition)};\n`; + this.source += `const id = "${sanitize(node.id)}";\n`; + this.source += 'const hasOldEdgeValue = target.hasEdgeActivatedValue(id);\n'; + this.source += `const oldEdgeValue = target.updateEdgeActivatedValue(id, resolvedValue);\n`; + this.source += `const edgeWasActivated = hasOldEdgeValue ? (!oldEdgeValue && resolvedValue) : resolvedValue;\n`; + this.source += `if (!edgeWasActivated) {\n`; + this.retire(); + this.source += '}\n'; + this.source += 'yield;\n'; + this.source += '}\n'; + this.isInHat = false; break; - case 'control.deleteClone': + + case StackOpcode.HAT_PREDICATE: + this.isInHat = true; + this.source += `if (!${this.descendInput(node.condition)}) {\n`; + this.retire(); + this.source += '}\n'; + this.source += 'yield;\n'; + this.isInHat = false; + break; + + case StackOpcode.CONTROL_CLONE_CREATE: + this.source += `runtime.ext_scratch3_control._createClone(${this.descendInput(node.target)}, target);\n`; + break; + case StackOpcode.CONTROL_CLONE_DELETE: this.source += 'if (!target.isOriginal) {\n'; this.source += ' runtime.disposeTarget(target);\n'; this.source += ' runtime.stopForTarget(target);\n'; this.retire(); this.source += '}\n'; break; - case 'control.for': { - this.resetVariableInputs(); + case StackOpcode.CONTROL_FOR: const index = this.localVariables.next(); this.source += `var ${index} = 0; `; - this.source += `while (${index} < ${this.descendInput(node.count).asNumber()}) { `; + this.source += `while (${index} < ${this.descendInput(node.count)}) { `; this.source += `${index}++; `; this.source += `${this.referenceVariable(node.variable)}.value = ${index};\n`; this.descendStack(node.do, new Frame(true)); this.yieldLoop(); this.source += '}\n'; break; - } - case 'control.if': - this.source += `if (${this.descendInput(node.condition).asBoolean()}) {\n`; + case StackOpcode.CONTROL_IF_ELSE: + this.source += `if (${this.descendInput(node.condition)}) {\n`; this.descendStack(node.whenTrue, new Frame(false)); // only add the else branch if it won't be empty // this makes scripts have a bit less useless noise in them - if (node.whenFalse.length) { + if (node.whenFalse.blocks.length) { this.source += `} else {\n`; this.descendStack(node.whenFalse, new Frame(false)); } this.source += `}\n`; break; - case 'control.repeat': { + case StackOpcode.CONTROL_REPEAT: { const i = this.localVariables.next(); - this.source += `for (var ${i} = ${this.descendInput(node.times).asNumber()}; ${i} >= 0.5; ${i}--) {\n`; + this.source += `for (var ${i} = ${this.descendInput(node.times)}; ${i} >= 0.5; ${i}--) {\n`; this.descendStack(node.do, new Frame(true)); this.yieldLoop(); this.source += `}\n`; break; } - case 'control.stopAll': + case StackOpcode.CONTROL_STOP_ALL: this.source += 'runtime.stopAll();\n'; this.retire(); break; - case 'control.stopOthers': + case StackOpcode.CONTROL_STOP_OTHERS: this.source += 'runtime.stopForTarget(target, thread);\n'; break; - case 'control.stopScript': + case StackOpcode.CONTROL_STOP_SCRIPT: this.stopScript(); break; - case 'control.wait': { + case StackOpcode.CONTROL_WAIT: { const duration = this.localVariables.next(); this.source += `thread.timer = timer();\n`; - this.source += `var ${duration} = Math.max(0, 1000 * ${this.descendInput(node.seconds).asNumber()});\n`; + this.source += `var ${duration} = Math.max(0, 1000 * ${this.descendInput(node.seconds)});\n`; this.requestRedraw(); // always yield at least once, even on 0 second durations this.yieldNotWarp(); @@ -857,16 +611,14 @@ class JSGenerator { this.source += 'thread.timer = null;\n'; break; } - case 'control.waitUntil': { - this.resetVariableInputs(); - this.source += `while (!${this.descendInput(node.condition).asBoolean()}) {\n`; + case StackOpcode.CONTROL_WAIT_UNTIL: { + this.source += `while (!${this.descendInput(node.condition)}) {\n`; this.yieldStuckOrNotWarp(); this.source += `}\n`; break; } - case 'control.while': - this.resetVariableInputs(); - this.source += `while (${this.descendInput(node.condition).asBoolean()}) {\n`; + case StackOpcode.CONTROL_WHILE: + this.source += `while (${this.descendInput(node.condition)}) {\n`; this.descendStack(node.do, new Frame(true)); if (node.warpTimer) { this.yieldStuckOrNotWarp(); @@ -875,234 +627,202 @@ class JSGenerator { } this.source += `}\n`; break; - - case 'counter.clear': + case StackOpcode.CONTROL_CLEAR_COUNTER: this.source += 'runtime.ext_scratch3_control._counter = 0;\n'; break; - case 'counter.increment': + case StackOpcode.CONTORL_INCR_COUNTER: this.source += 'runtime.ext_scratch3_control._counter++;\n'; break; - case 'hat.edge': - this.isInHat = true; - this.source += '{\n'; - // For exact Scratch parity, evaluate the input before checking old edge state. - // Can matter if the input is not instantly evaluated. - this.source += `const resolvedValue = ${this.descendInput(node.condition).asBoolean()};\n`; - this.source += `const id = "${sanitize(node.id)}";\n`; - this.source += 'const hasOldEdgeValue = target.hasEdgeActivatedValue(id);\n'; - this.source += `const oldEdgeValue = target.updateEdgeActivatedValue(id, resolvedValue);\n`; - this.source += `const edgeWasActivated = hasOldEdgeValue ? (!oldEdgeValue && resolvedValue) : resolvedValue;\n`; - this.source += `if (!edgeWasActivated) {\n`; - this.retire(); - this.source += '}\n'; - this.source += 'yield;\n'; - this.source += '}\n'; - this.isInHat = false; - break; - case 'hat.predicate': - this.isInHat = true; - this.source += `if (!${this.descendInput(node.condition).asBoolean()}) {\n`; - this.retire(); - this.source += '}\n'; - this.source += 'yield;\n'; - this.isInHat = false; - break; - - case 'event.broadcast': - this.source += `startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: ${this.descendInput(node.broadcast).asString()} });\n`; - this.resetVariableInputs(); + case StackOpcode.EVENT_BROADCAST: + this.source += `startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: ${this.descendInput(node.broadcast)} });\n`; break; - case 'event.broadcastAndWait': - this.source += `yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: ${this.descendInput(node.broadcast).asString()} }));\n`; + case StackOpcode.EVENT_BROADCAST_AND_WAIT: + this.source += `yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: ${this.descendInput(node.broadcast)} }));\n`; this.yielded(); break; - case 'list.add': { + case StackOpcode.LIST_ADD: { const list = this.referenceVariable(node.list); - this.source += `${list}.value.push(${this.descendInput(node.item).asSafe()});\n`; + this.source += `${list}.value.push(${this.descendInput(node.item)});\n`; this.source += `${list}._monitorUpToDate = false;\n`; break; } - case 'list.delete': { + case StackOpcode.LIST_DELETE: { const list = this.referenceVariable(node.list); - const index = this.descendInput(node.index); - if (index instanceof ConstantInput) { - if (index.constantValue === 'last') { - this.source += `${list}.value.pop();\n`; - this.source += `${list}._monitorUpToDate = false;\n`; - break; - } - if (+index.constantValue === 1) { - this.source += `${list}.value.shift();\n`; - this.source += `${list}._monitorUpToDate = false;\n`; - break; - } - // do not need a special case for all as that is handled in IR generation (list.deleteAll) + if (node.index.isConstant('last')) { + this.source += `${list}.value.pop();\n`; + this.source += `${list}._monitorUpToDate = false;\n`; + break; + } + if (node.index.isConstant(1)) { + this.source += `${list}.value.shift();\n`; + this.source += `${list}._monitorUpToDate = false;\n`; + break; } - this.source += `listDelete(${list}, ${index.asUnknown()});\n`; + // do not need a special case for all as that is handled in IR generation (list.deleteAll) + this.source += `listDelete(${list}, ${this.descendInput(node.index)});\n`; break; } - case 'list.deleteAll': + case StackOpcode.LIST_DELETE_ALL: this.source += `${this.referenceVariable(node.list)}.value = [];\n`; break; - case 'list.hide': + case StackOpcode.LIST_HIDE: this.source += `runtime.monitorBlocks.changeBlock({ id: "${sanitize(node.list.id)}", element: "checkbox", value: false }, runtime);\n`; break; - case 'list.insert': { + case StackOpcode.LIST_INSERT: { const list = this.referenceVariable(node.list); - const index = this.descendInput(node.index); const item = this.descendInput(node.item); - if (index instanceof ConstantInput && +index.constantValue === 1) { - this.source += `${list}.value.unshift(${item.asSafe()});\n`; + if (node.index.isConstant(1)) { + this.source += `${list}.value.unshift(${item});\n`; this.source += `${list}._monitorUpToDate = false;\n`; break; } - this.source += `listInsert(${list}, ${index.asUnknown()}, ${item.asSafe()});\n`; + this.source += `listInsert(${list}, ${this.descendInput(node.index)}, ${item});\n`; break; } - case 'list.replace': - this.source += `listReplace(${this.referenceVariable(node.list)}, ${this.descendInput(node.index).asUnknown()}, ${this.descendInput(node.item).asSafe()});\n`; + case StackOpcode.LIST_REPLACE: + this.source += `listReplace(${this.referenceVariable(node.list)}, ${this.descendInput(node.index)}, ${this.descendInput(node.item)});\n`; break; - case 'list.show': + case StackOpcode.LIST_SHOW: this.source += `runtime.monitorBlocks.changeBlock({ id: "${sanitize(node.list.id)}", element: "checkbox", value: true }, runtime);\n`; break; - case 'looks.backwardLayers': + case StackOpcode.LOOKS_LAYER_BACKWARD: if (!this.target.isStage) { - this.source += `target.goBackwardLayers(${this.descendInput(node.layers).asNumber()});\n`; + this.source += `target.goBackwardLayers(${this.descendInput(node.layers)});\n`; } break; - case 'looks.clearEffects': + case StackOpcode.LOOKS_EFFECT_CLEAR: this.source += 'target.clearEffects();\n'; break; - case 'looks.changeEffect': - if (Object.prototype.hasOwnProperty.call(this.target.effects, node.effect)) { - this.source += `target.setEffect("${sanitize(node.effect)}", runtime.ext_scratch3_looks.clampEffect("${sanitize(node.effect)}", ${this.descendInput(node.value).asNumber()} + target.effects["${sanitize(node.effect)}"]));\n`; + case StackOpcode.LOOKS_EFFECT_CHANGE: + if (this.target.effects.hasOwnProperty(node.effect)) { + this.source += `target.setEffect("${sanitize(node.effect)}", runtime.ext_scratch3_looks.clampEffect("${sanitize(node.effect)}", ${this.descendInput(node.value)} + target.effects["${sanitize(node.effect)}"]));\n`; } break; - case 'looks.changeSize': - this.source += `target.setSize(target.size + ${this.descendInput(node.size).asNumber()});\n`; + case StackOpcode.LOOKS_SIZE_CHANGE: + this.source += `target.setSize(target.size + ${this.descendInput(node.size)});\n`; break; - case 'looks.forwardLayers': + case StackOpcode.LOOKS_LAYER_FORWARD: if (!this.target.isStage) { - this.source += `target.goForwardLayers(${this.descendInput(node.layers).asNumber()});\n`; + this.source += `target.goForwardLayers(${this.descendInput(node.layers)});\n`; } break; - case 'looks.goToBack': + case StackOpcode.LOOKS_LAYER_BACK: if (!this.target.isStage) { this.source += 'target.goToBack();\n'; } break; - case 'looks.goToFront': + case StackOpcode.LOOKS_LAYER_FRONT: if (!this.target.isStage) { this.source += 'target.goToFront();\n'; } break; - case 'looks.hide': + case StackOpcode.LOOKS_HIDE: this.source += 'target.setVisible(false);\n'; this.source += 'runtime.ext_scratch3_looks._renderBubble(target);\n'; break; - case 'looks.nextBackdrop': + case StackOpcode.LOOKS_BACKDROP_NEXT: this.source += 'runtime.ext_scratch3_looks._setBackdrop(stage, stage.currentCostume + 1, true);\n'; break; - case 'looks.nextCostume': + case StackOpcode.LOOKS_COSTUME_NEXT: this.source += 'target.setCostume(target.currentCostume + 1);\n'; break; - case 'looks.setEffect': - if (Object.prototype.hasOwnProperty.call(this.target.effects, node.effect)) { - this.source += `target.setEffect("${sanitize(node.effect)}", runtime.ext_scratch3_looks.clampEffect("${sanitize(node.effect)}", ${this.descendInput(node.value).asNumber()}));\n`; + case StackOpcode.LOOKS_EFFECT_SET: + if (this.target.effects.hasOwnProperty(node.effect)) { + this.source += `target.setEffect("${sanitize(node.effect)}", runtime.ext_scratch3_looks.clampEffect("${sanitize(node.effect)}", ${this.descendInput(node.value)}));\n`; } break; - case 'looks.setSize': - this.source += `target.setSize(${this.descendInput(node.size).asNumber()});\n`; + case StackOpcode.LOOKS_SIZE_SET: + this.source += `target.setSize(${this.descendInput(node.size)});\n`; break; - case 'looks.show': + case StackOpcode.LOOKS_SHOW: this.source += 'target.setVisible(true);\n'; this.source += 'runtime.ext_scratch3_looks._renderBubble(target);\n'; break; - case 'looks.switchBackdrop': - this.source += `runtime.ext_scratch3_looks._setBackdrop(stage, ${this.descendInput(node.backdrop).asSafe()});\n`; + case StackOpcode.LOOKS_BACKDROP_SET: + this.source += `runtime.ext_scratch3_looks._setBackdrop(stage, ${this.descendInput(node.backdrop)});\n`; break; - case 'looks.switchCostume': - this.source += `runtime.ext_scratch3_looks._setCostume(target, ${this.descendInput(node.costume).asSafe()});\n`; + case StackOpcode.LOOKS_COSTUME_SET: + this.source += `runtime.ext_scratch3_looks._setCostume(target, ${this.descendInput(node.costume)});\n`; break; - case 'motion.changeX': - this.source += `target.setXY(target.x + ${this.descendInput(node.dx).asNumber()}, target.y);\n`; + case StackOpcode.MOTION_X_CHANGE: + this.source += `target.setXY(target.x + ${this.descendInput(node.dx)}, target.y);\n`; break; - case 'motion.changeY': - this.source += `target.setXY(target.x, target.y + ${this.descendInput(node.dy).asNumber()});\n`; + case StackOpcode.MOTION_Y_CHANGE: + this.source += `target.setXY(target.x, target.y + ${this.descendInput(node.dy)});\n`; break; - case 'motion.ifOnEdgeBounce': + case StackOpcode.MOTION_IF_ON_EDGE_BOUNCE: this.source += `runtime.ext_scratch3_motion._ifOnEdgeBounce(target);\n`; break; - case 'motion.setDirection': - this.source += `target.setDirection(${this.descendInput(node.direction).asNumber()});\n`; + case StackOpcode.MOTION_DIRECTION_SET: + this.source += `target.setDirection(${this.descendInput(node.direction)});\n`; break; - case 'motion.setRotationStyle': + case StackOpcode.MOTION_ROTATION_STYLE_SET: this.source += `target.setRotationStyle("${sanitize(node.style)}");\n`; break; - case 'motion.setX': // fallthrough - case 'motion.setY': // fallthrough - case 'motion.setXY': { + case StackOpcode.MOTION_X_SET: // fallthrough + case StackOpcode.MOTION_Y_SET: // fallthrough + case StackOpcode.MOTION_XY_SET: { this.descendedIntoModulo = false; - const x = 'x' in node ? this.descendInput(node.x).asNumber() : 'target.x'; - const y = 'y' in node ? this.descendInput(node.y).asNumber() : 'target.y'; + const x = 'x' in node ? this.descendInput(node.x) : 'target.x'; + const y = 'y' in node ? this.descendInput(node.y) : 'target.y'; this.source += `target.setXY(${x}, ${y});\n`; if (this.descendedIntoModulo) { this.source += `if (target.interpolationData) target.interpolationData = null;\n`; } break; } - case 'motion.step': - this.source += `runtime.ext_scratch3_motion._moveSteps(${this.descendInput(node.steps).asNumber()}, target);\n`; + case StackOpcode.MOTION_STEP: + this.source += `runtime.ext_scratch3_motion._moveSteps(${this.descendInput(node.steps)}, target);\n`; break; - case 'noop': + case StackOpcode.NOP: break; - case 'pen.clear': + case StackOpcode.PEN_CLEAR: this.source += `${PEN_EXT}.clear();\n`; break; - case 'pen.down': + case StackOpcode.PEN_DOWN: this.source += `${PEN_EXT}._penDown(target);\n`; break; - case 'pen.changeParam': - this.source += `${PEN_EXT}._setOrChangeColorParam(${this.descendInput(node.param).asString()}, ${this.descendInput(node.value).asNumber()}, ${PEN_STATE}, true);\n`; + case StackOpcode.PEN_COLOR_PARAM_CHANGE: + this.source += `${PEN_EXT}._setOrChangeColorParam(${this.descendInput(node.param)}, ${this.descendInput(node.value)}, ${PEN_STATE}, true);\n`; break; - case 'pen.changeSize': - this.source += `${PEN_EXT}._changePenSizeBy(${this.descendInput(node.size).asNumber()}, target);\n`; + case StackOpcode.PEN_SIZE_CHANGE: + this.source += `${PEN_EXT}._changePenSizeBy(${this.descendInput(node.size)}, target);\n`; break; - case 'pen.legacyChangeHue': - this.source += `${PEN_EXT}._changePenHueBy(${this.descendInput(node.hue).asNumber()}, target);\n`; + case StackOpcode.PEN_COLOR_HUE_CHANGE_LEGACY: + this.source += `${PEN_EXT}._changePenHueBy(${this.descendInput(node.hue)}, target);\n`; break; - case 'pen.legacyChangeShade': - this.source += `${PEN_EXT}._changePenShadeBy(${this.descendInput(node.shade).asNumber()}, target);\n`; + case StackOpcode.PEN_COLOR_SHADE_CHANGE_LEGACY: + this.source += `${PEN_EXT}._changePenShadeBy(${this.descendInput(node.shade)}, target);\n`; break; - case 'pen.legacySetHue': - this.source += `${PEN_EXT}._setPenHueToNumber(${this.descendInput(node.hue).asNumber()}, target);\n`; + case StackOpcode.PEN_COLOR_HUE_SET_LEGACY: + this.source += `${PEN_EXT}._setPenHueToNumber(${this.descendInput(node.hue)}, target);\n`; break; - case 'pen.legacySetShade': - this.source += `${PEN_EXT}._setPenShadeToNumber(${this.descendInput(node.shade).asNumber()}, target);\n`; + case StackOpcode.PEN_COLOR_SHADE_SET_LEGACY: + this.source += `${PEN_EXT}._setPenShadeToNumber(${this.descendInput(node.shade)}, target);\n`; break; - case 'pen.setColor': - this.source += `${PEN_EXT}._setPenColorToColor(${this.descendInput(node.color).asColor()}, target);\n`; + case StackOpcode.PEN_COLOR_SET: + this.source += `${PEN_EXT}._setPenColorToColor(${this.descendInput(node.color)}, target);\n`; break; - case 'pen.setParam': - this.source += `${PEN_EXT}._setOrChangeColorParam(${this.descendInput(node.param).asString()}, ${this.descendInput(node.value).asNumber()}, ${PEN_STATE}, false);\n`; + case StackOpcode.PEN_COLOR_PARAM_SET: + this.source += `${PEN_EXT}._setOrChangeColorParam(${this.descendInput(node.param)}, ${this.descendInput(node.value)}, ${PEN_STATE}, false);\n`; break; - case 'pen.setSize': - this.source += `${PEN_EXT}._setPenSizeTo(${this.descendInput(node.size).asNumber()}, target);\n`; + case StackOpcode.PEN_SIZE_SET: + this.source += `${PEN_EXT}._setPenSizeTo(${this.descendInput(node.size)}, target);\n`; break; - case 'pen.stamp': + case StackOpcode.PEN_STAMP: this.source += `${PEN_EXT}._stamp(target);\n`; break; - case 'pen.up': + case StackOpcode.PEN_UP: this.source += `${PEN_EXT}._penUp(target);\n`; break; - case 'procedures.call': { + case StackOpcode.PROCEDURE_CALL: { const procedureCode = node.code; const procedureVariant = node.variant; const procedureData = this.ir.procedures[procedureVariant]; @@ -1110,114 +830,129 @@ class JSGenerator { // TODO still need to evaluate arguments break; } - const yieldForRecursion = !this.isWarp && procedureCode === this.script.procedureCode; if (yieldForRecursion) { + // Direct yields. this.yieldNotWarp(); } - if (procedureData.yields) { this.source += 'yield* '; + if (!this.script.yields) { + throw new Error('Script uses yielding procedure but is not marked as yielding.'); + } } this.source += `thread.procedures["${sanitize(procedureVariant)}"](`; const args = []; for (const input of node.arguments) { - args.push(this.descendInput(input).asSafe()); + args.push(this.descendInput(input)); } this.source += args.join(','); - this.source += ');\n'; - - this.resetVariableInputs(); + this.source += `);\n`; break; } - case 'procedures.return': - this.stopScriptAndReturn(this.descendInput(node.value).asSafe()); + case StackOpcode.PROCEDURE_RETURN: + this.stopScriptAndReturn(this.descendInput(node.value)); break; - case 'timer.reset': + case StackOpcode.SENSING_TIMER_RESET: this.source += 'runtime.ioDevices.clock.resetProjectTimer();\n'; break; - case 'tw.debugger': + case StackOpcode.DEBUGGER: this.source += 'debugger;\n'; break; - case 'var.hide': + case StackOpcode.VAR_HIDE: this.source += `runtime.monitorBlocks.changeBlock({ id: "${sanitize(node.variable.id)}", element: "checkbox", value: false }, runtime);\n`; break; - case 'var.set': { - const variable = this.descendVariable(node.variable); - const value = this.descendInput(node.value); - variable.setInput(value); - this.source += `${variable.source} = ${value.asSafe()};\n`; + case StackOpcode.VAR_SET: { + const varReference = this.referenceVariable(node.variable); + this.source += `${varReference}.value = ${this.descendInput(node.value)};\n`; if (node.variable.isCloud) { - this.source += `runtime.ioDevices.cloud.requestUpdateVariable("${sanitize(node.variable.name)}", ${variable.source});\n`; + this.source += `runtime.ioDevices.cloud.requestUpdateVariable("${sanitize(node.variable.name)}", ${varReference}.value);\n`; } break; } - case 'var.show': + case StackOpcode.VAR_SHOW: this.source += `runtime.monitorBlocks.changeBlock({ id: "${sanitize(node.variable.id)}", element: "checkbox", value: true }, runtime);\n`; break; - case 'visualReport': { + case StackOpcode.VISUAL_REPORT: { const value = this.localVariables.next(); - this.source += `const ${value} = ${this.descendInput(node.input).asUnknown()};`; + this.source += `const ${value} = ${this.descendInput(node.input)};`; // blocks like legacy no-ops can return a literal `undefined` this.source += `if (${value} !== undefined) runtime.visualReport("${sanitize(this.script.topBlockId)}", ${value});\n`; break; } default: - log.warn(`JS: Unknown stacked block: ${node.kind}`, node); - throw new Error(`JS: Unknown stacked block: ${node.kind}`); + log.warn(`JS: Unknown stacked block: ${block.opcode}`, node); + throw new Error(`JS: Unknown stacked block: ${block.opcode}`); } } + /** + * Compiles a reference to a target. + * @param {IntermediateInput} input The target reference. Must be a string. + * @returns {string} The compiled target reference + */ + descendTargetReference (input) { + if (!input.isAlwaysType(InputType.STRING)) { + throw new Error(`JS: Object references must be strings!`); + } + if (input.isConstant('_stage_')) return 'stage'; + return this.evaluateOnce(`runtime.getSpriteTargetByName(${this.descendInput(input)})`); + } + /** * Compile a Record of input objects into a safe JS string. - * @param {Record} inputs + * @param {Record} inputs * @returns {string} */ descendInputRecord (inputs) { let result = '{'; for (const name of Object.keys(inputs)) { const node = inputs[name]; - result += `"${sanitize(name)}":${this.descendInput(node).asSafe()},`; + result += `"${sanitize(name)}":${this.descendInput(node)},`; } result += '}'; return result; } - resetVariableInputs () { - this.variableInputs = {}; - } - - descendStack (nodes, frame) { + /** + * @param {IntermediateStack} stack + * @param {Frame} frame + */ + descendStack (stack, frame) { // Entering a stack -- all bets are off. // TODO: allow if/else to inherit values - this.resetVariableInputs(); this.pushFrame(frame); - for (let i = 0; i < nodes.length; i++) { - frame.isLastBlock = i === nodes.length - 1; - this.descendStackedBlock(nodes[i]); + for (let i = 0; i < stack.blocks.length; i++) { + frame.isLastBlock = i === stack.blocks.length - 1; + this.descendStackedBlock(stack.blocks[i]); } // Leaving a stack -- any assumptions made in the current stack do not apply outside of it // TODO: in if/else this might create an extra unused object - this.resetVariableInputs(); this.popFrame(); } - descendVariable (variable) { - if (Object.prototype.hasOwnProperty.call(this.variableInputs, variable.id)) { - return this.variableInputs[variable.id]; - } - const input = new VariableInput(`${this.referenceVariable(variable)}.value`); - this.variableInputs[variable.id] = input; - return input; + /** + * @param {*} node + * @returns {string} + */ + descendAddonCall (node) { + const inputs = this.descendInputRecord(node.arguments); + const blockFunction = `runtime.getAddonBlock("${sanitize(node.code)}").callback`; + const blockId = `"${sanitize(node.blockId)}"`; + return `yield* executeInCompatibilityLayer(${inputs}, ${blockFunction}, ${this.isWarp}, false, ${blockId})`; } + /** + * @param {*} variable + * @returns {string} + */ referenceVariable (variable) { if (variable.scope === 'target') { return this.evaluateOnce(`target.variables["${sanitize(variable.id)}"]`); @@ -1225,15 +960,12 @@ class JSGenerator { return this.evaluateOnce(`stage.variables["${sanitize(variable.id)}"]`); } - descendAddonCall (node) { - const inputs = this.descendInputRecord(node.arguments); - const blockFunction = `runtime.getAddonBlock("${sanitize(node.code)}").callback`; - const blockId = `"${sanitize(node.blockId)}"`; - return `yield* executeInCompatibilityLayer(${inputs}, ${blockFunction}, ${this.isWarp}, false, ${blockId})`; - } - + /** + * @param {string} source + * @returns {string} + */ evaluateOnce (source) { - if (Object.prototype.hasOwnProperty.call(this._setupVariables, source)) { + if (this._setupVariables.hasOwnProperty(source)) { return this._setupVariables[source]; } const variable = this._setupVariablesPool.next(); @@ -1252,25 +984,6 @@ class JSGenerator { } } - stopScript () { - if (this.isProcedure) { - this.source += 'return "";\n'; - } else { - this.retire(); - } - } - - /** - * @param {string} valueJS JS code of value to return. - */ - stopScriptAndReturn (valueJS) { - if (this.isProcedure) { - this.source += `return ${valueJS};\n`; - } else { - this.retire(); - } - } - yieldLoop () { if (this.warpTimer) { this.yieldStuckOrNotWarp(); @@ -1306,7 +1019,6 @@ class JSGenerator { throw new Error('Script yielded but is not marked as yielding.'); } // Control may have been yielded to another script -- all bets are off. - this.resetVariableInputs(); } /** @@ -1316,14 +1028,9 @@ class JSGenerator { this.source += 'runtime.requestRedraw();\n'; } - safeConstantInput (value) { - const unsafe = typeof value === 'string' && this.namesOfCostumesAndSounds.has(value); - return new ConstantInput(value, !unsafe); - } - /** * Generate a call into the compatibility layer. - * @param {*} node The "compat" kind node to generate from. + * @param {*} node The node of the block to generate from. * @param {boolean} setFlags Whether flags should be set describing how this function was processed. * @param {string|null} [frameName] Name of the stack frame variable, if any * @returns {string} The JS of the call. @@ -1335,7 +1042,7 @@ class JSGenerator { for (const inputName of Object.keys(node.inputs)) { const input = node.inputs[inputName]; - const compiledInput = this.descendInput(input).asSafe(); + const compiledInput = this.descendInput(input); result += `"${sanitize(inputName)}":${compiledInput},`; } for (const fieldName of Object.keys(node.fields)) { @@ -1364,6 +1071,25 @@ class JSGenerator { return name; } + stopScript () { + if (this.isProcedure) { + this.source += 'return "";\n'; + } else { + this.retire(); + } + } + + /** + * @param {string} valueJS JS code of value to return. + */ + stopScriptAndReturn (valueJS) { + if (this.isProcedure) { + this.source += `return ${valueJS};\n`; + } else { + this.retire(); + } + } + /** * Generate the JS to pass into eval() based on the current state of the compiler. * @returns {string} JS to pass into eval() @@ -1431,26 +1157,6 @@ class JSGenerator { } } -// For extensions. -JSGenerator.unstable_exports = { - TYPE_NUMBER, - TYPE_STRING, - TYPE_BOOLEAN, - TYPE_UNKNOWN, - TYPE_NUMBER_NAN, - factoryNameVariablePool, - functionNameVariablePool, - generatorNameVariablePool, - VariablePool, - PEN_EXT, - PEN_STATE, - TypedInput, - ConstantInput, - VariableInput, - Frame, - sanitize -}; - // Test hook used by automated snapshot testing. JSGenerator.testingApparatus = null; diff --git a/src/compiler/variable-pool.js b/src/compiler/variable-pool.js index 11f50594021..47f463e97b3 100644 --- a/src/compiler/variable-pool.js +++ b/src/compiler/variable-pool.js @@ -1,3 +1,5 @@ +// @ts-check + class VariablePool { /** * @param {string} prefix The prefix at the start of the variable name. diff --git a/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot b/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot index 91457816d33..96c7ced79c1 100644 --- a/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot @@ -17,7 +17,7 @@ yield; } thread.timer = null; b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 1)) { +if ((b0.value === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "]4hbk*5ix]V00h|!x1oy", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 1 != " + ("" + b0.value)),}, b2, false, false, "H=x@7SpNJeX|!}8x5y4,", null); @@ -75,7 +75,7 @@ yield; } thread.timer = null; b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 2)) { +if ((b0.value === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "0i[-T:vYTt=bi47@byUE", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 2 != " + ("" + b0.value)),}, b2, false, false, "Coc1aZ;L9M-RyEt`syps", null); diff --git a/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot b/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot index 2d10b51e1ce..5145078f7aa 100644 --- a/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot @@ -51,7 +51,7 @@ yield; } thread.timer = null; b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 1)) { +if ((b0.value === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "RSQ{nVCc)6E)(`KlnFCF", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 1 != " + ("" + b0.value)),}, b2, false, false, "8k^j~`c^|YO@hkFd?~2d", null); @@ -75,7 +75,7 @@ yield; } thread.timer = null; b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 2)) { +if ((b0.value === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "KP?op(=Vg2#;@]!,C#.~", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 2 != " + ("" + b0.value)),}, b2, false, false, "=]|}L~4uQXTNtwJKw_;R", null); diff --git a/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot index 106f6edd6d0..417094fef11 100644 --- a/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot @@ -9,61 +9,61 @@ yield* executeInCompatibilityLayer({"MESSAGE":"plan 20",}, b0, false, false, "v" if ((("" + (0 * Infinity)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "6", null); } -if (compareEqual((((0 * Infinity) || 0) * 1), 0)) { +if (((((0 * Infinity) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "#", null); } if ((("" + ((Math.acos(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "9", null); } -if (compareEqual(((((Math.acos(1.01) * 180) / Math.PI) || 0) * 1), 0)) { +if ((((((Math.acos(1.01) * 180) / Math.PI) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "(", null); } if ((("" + ((Math.asin(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "*", null); } -if (compareEqual(((((Math.asin(1.01) * 180) / Math.PI) || 0) * 1), 0)) { +if ((((((Math.asin(1.01) * 180) / Math.PI) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ",", null); } if ((("" + (0 / 0)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ".", null); } -if (compareEqual((((0 / 0) || 0) * 1), 0)) { +if (((((0 / 0) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ":", null); } if ((("" + Math.sqrt(-1)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "?", null); } -if (compareEqual(((Math.sqrt(-1) || 0) * 1), 0)) { +if ((((Math.sqrt(-1) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "@", null); } if ((("" + mod(0, 0)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "]", null); } -if (compareEqual(((mod(0, 0) || 0) * 1), 0)) { +if ((((mod(0, 0) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "_", null); } if ((("" + Math.log(-1)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "{", null); } -if (compareEqual(((Math.log(-1) || 0) * 1), 0)) { +if ((((Math.log(-1) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "}", null); } if ((("" + (Math.log(-1) / Math.LN10)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aa", null); } -if (compareEqual((((Math.log(-1) / Math.LN10) || 0) * 1), 0)) { +if (((((Math.log(-1) / Math.LN10) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ac", null); } -if (compareEqual((((Math.round(Math.sin((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1), 0)) { +if (((((Math.round(Math.sin((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ae", null); } -if (compareEqual((((Math.round(Math.cos((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1), 0)) { +if (((((Math.round(Math.cos((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ag", null); } -if (compareEqual(((tan(((1 / 0) || 0)) || 0) * 1), 0)) { +if ((((tan(((1 / 0) || 0)) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ai", null); } -if (compareEqual(((runtime.ext_scratch3_operators._random((-1 / 0), (1 / 0)) || 0) * 1), 0)) { +if ((((runtime.ext_scratch3_operators._random((-1 / 0), (1 / 0)) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ak", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "7", null); diff --git a/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot index c133a6cb76f..b7f47584e4f 100644 --- a/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot @@ -11,7 +11,7 @@ target.setSize(96); b1.value = 0; while (!(100 === Math.round(target.size))) { b1.value = ((+b1.value || 0) + 1); -target.setSize(target.size + ((((100 - Math.round(target.size)) || 0) / 10) || 0)); +target.setSize(target.size + ((100 - Math.round(target.size)) / 10)); yield; } if (((+b1.value || 0) === 20)) { diff --git a/test/snapshot/__snapshots__/tw-color-input-returns-hex.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-color-input-returns-hex.sb3.tw-snapshot index bccad8ff318..070b355da4a 100644 --- a/test/snapshot/__snapshots__/tw-color-input-returns-hex.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-color-input-returns-hex.sb3.tw-snapshot @@ -8,7 +8,7 @@ const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); b1.value = "#22388a"; -if ((("" + b1.value).toLowerCase() === "#22388a".toLowerCase())) { +if ((b1.value.toLowerCase() === "#22388a".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "f", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "e", null); diff --git a/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot index 66d03cf758d..741ccca8ae7 100644 --- a/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot @@ -123,13 +123,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 38: 0 should be = 🎉",}, b if (!(("" + ("0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 39: 0 should be > 🎉",}, b0, false, false, "uq", null); } -if (!(("" + compareLessThan(0, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 40: 0 should be < ",}, b0, false, false, "us", null); } -if (!(("" + compareEqual(0, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 41: 0 should be = ",}, b0, false, false, "uu", null); } -if (!(("" + compareGreaterThan(0, "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 42: 0 should be > ",}, b0, false, false, "uw", null); } if (!(("" + (0 < 0)).toLowerCase() === "false".toLowerCase())) { @@ -249,13 +249,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 80: 0.0 should be = 🎉",}, if (!(("" + ("0.0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 81: 0.0 should be > 🎉",}, b0, false, false, "vn", null); } -if (!(("" + compareLessThan("0.0", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 82: 0.0 should be < ",}, b0, false, false, "vp", null); } -if (!(("" + compareEqual("0.0", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 83: 0.0 should be = ",}, b0, false, false, "vr", null); } -if (!(("" + compareGreaterThan("0.0", "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("0.0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 84: 0.0 should be > ",}, b0, false, false, "vt", null); } if (!(("" + (1.23 < 0)).toLowerCase() === "false".toLowerCase())) { @@ -324,7 +324,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 105: 1.23 should be > -1",}, if (!(("" + ("1.23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 106: 1.23 should be < true",}, b0, false, false, "v#", null); } -if (!(("" + ("1.23".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1.23 === 1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 107: 1.23 should be = true",}, b0, false, false, "v(", null); } if (!(("" + ("1.23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -333,7 +333,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 108: 1.23 should be > true", if (!(("" + ("1.23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 109: 1.23 should be < false",}, b0, false, false, "v,", null); } -if (!(("" + ("1.23".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 110: 1.23 should be = false",}, b0, false, false, "v.", null); } if (!(("" + ("1.23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -342,7 +342,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 111: 1.23 should be > false" if (!(("" + ("1.23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 112: 1.23 should be < NaN",}, b0, false, false, "v=", null); } -if (!(("" + ("1.23".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 113: 1.23 should be = NaN",}, b0, false, false, "v@", null); } if (!(("" + ("1.23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -360,7 +360,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 117: 1.23 should be > Infini if (!(("" + ("1.23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 118: 1.23 should be < banana",}, b0, false, false, "wa", null); } -if (!(("" + ("1.23".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 119: 1.23 should be = banana",}, b0, false, false, "wc", null); } if (!(("" + ("1.23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -369,19 +369,19 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 120: 1.23 should be > banana if (!(("" + ("1.23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 121: 1.23 should be < 🎉",}, b0, false, false, "wg", null); } -if (!(("" + ("1.23".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 122: 1.23 should be = 🎉",}, b0, false, false, "wi", null); } if (!(("" + ("1.23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 123: 1.23 should be > 🎉",}, b0, false, false, "wk", null); } -if (!(("" + compareLessThan(1.23, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 124: 1.23 should be < ",}, b0, false, false, "wm", null); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 125: 1.23 should be = ",}, b0, false, false, "wo", null); } -if (!(("" + compareGreaterThan(1.23, "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 126: 1.23 should be > ",}, b0, false, false, "wq", null); } if (!(("" + (0.23 < 0)).toLowerCase() === "false".toLowerCase())) { @@ -450,7 +450,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 147: .23 should be > -1",}, if (!(("" + (".23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 148: .23 should be < true",}, b0, false, false, "w8", null); } -if (!(("" + (".23".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 149: .23 should be = true",}, b0, false, false, "w!", null); } if (!(("" + (".23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -459,7 +459,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 150: .23 should be > true",} if (!(("" + (".23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 151: .23 should be < false",}, b0, false, false, "w)", null); } -if (!(("" + (".23".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 152: .23 should be = false",}, b0, false, false, "w+", null); } if (!(("" + (".23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -468,7 +468,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 153: .23 should be > false", if (!(("" + (".23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 154: .23 should be < NaN",}, b0, false, false, "w/", null); } -if (!(("" + (".23".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 155: .23 should be = NaN",}, b0, false, false, "w;", null); } if (!(("" + (".23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -486,7 +486,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 159: .23 should be > Infinit if (!(("" + (".23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 160: .23 should be < banana",}, b0, false, false, "w|", null); } -if (!(("" + (".23".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 161: .23 should be = banana",}, b0, false, false, "w~", null); } if (!(("" + (".23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -495,19 +495,19 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 162: .23 should be > banana" if (!(("" + (".23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 163: .23 should be < 🎉",}, b0, false, false, "xd", null); } -if (!(("" + (".23".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 164: .23 should be = 🎉",}, b0, false, false, "xf", null); } if (!(("" + (".23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 165: .23 should be > 🎉",}, b0, false, false, "xh", null); } -if (!(("" + compareLessThan(".23", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 166: .23 should be < ",}, b0, false, false, "xj", null); } -if (!(("" + compareEqual(".23", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 167: .23 should be = ",}, b0, false, false, "xl", null); } -if (!(("" + compareGreaterThan(".23", "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + (".23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 168: .23 should be > ",}, b0, false, false, "xn", null); } if (!(("" + (0.123 < 0)).toLowerCase() === "false".toLowerCase())) { @@ -576,7 +576,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 189: 0.123 should be > -1",} if (!(("" + ("0.123".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 190: 0.123 should be < true",}, b0, false, false, "x5", null); } -if (!(("" + ("0.123".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.123 === 1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 191: 0.123 should be = true",}, b0, false, false, "x7", null); } if (!(("" + ("0.123".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -585,7 +585,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 192: 0.123 should be > true" if (!(("" + ("0.123".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 193: 0.123 should be < false",}, b0, false, false, "x#", null); } -if (!(("" + ("0.123".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 194: 0.123 should be = false",}, b0, false, false, "x(", null); } if (!(("" + ("0.123".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -594,7 +594,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 195: 0.123 should be > false if (!(("" + ("0.123".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 196: 0.123 should be < NaN",}, b0, false, false, "x,", null); } -if (!(("" + ("0.123".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 197: 0.123 should be = NaN",}, b0, false, false, "x.", null); } if (!(("" + ("0.123".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -612,7 +612,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 201: 0.123 should be > Infin if (!(("" + ("0.123".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 202: 0.123 should be < banana",}, b0, false, false, "x_", null); } -if (!(("" + ("0.123".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 203: 0.123 should be = banana",}, b0, false, false, "x{", null); } if (!(("" + ("0.123".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -621,19 +621,19 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 204: 0.123 should be > banan if (!(("" + ("0.123".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 205: 0.123 should be < 🎉",}, b0, false, false, "ya", null); } -if (!(("" + ("0.123".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 206: 0.123 should be = 🎉",}, b0, false, false, "yc", null); } if (!(("" + ("0.123".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 207: 0.123 should be > 🎉",}, b0, false, false, "ye", null); } -if (!(("" + compareLessThan(0.123, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 208: 0.123 should be < ",}, b0, false, false, "yg", null); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 209: 0.123 should be = ",}, b0, false, false, "yi", null); } -if (!(("" + compareGreaterThan(0.123, "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 210: 0.123 should be > ",}, b0, false, false, "yk", null); } if (!(("" + (-0 < 0)).toLowerCase() === "false".toLowerCase())) { @@ -753,13 +753,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 248: -0 should be = 🎉",}, if (!(("" + ("-0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 249: -0 should be > 🎉",}, b0, false, false, "zb", null); } -if (!(("" + compareLessThan("-0", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 250: -0 should be < ",}, b0, false, false, "zd", null); } -if (!(("" + compareEqual("-0", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 251: -0 should be = ",}, b0, false, false, "zf", null); } -if (!(("" + compareGreaterThan("-0", "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("-0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 252: -0 should be > ",}, b0, false, false, "zh", null); } if (!(("" + (-1 < 0)).toLowerCase() === "true".toLowerCase())) { @@ -828,7 +828,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 273: -1 should be > -1",}, b if (!(("" + ("-1".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 274: -1 should be < true",}, b0, false, false, "zZ", null); } -if (!(("" + ("-1".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (-1 === 1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 275: -1 should be = true",}, b0, false, false, "z1", null); } if (!(("" + ("-1".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -837,7 +837,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 276: -1 should be > true",}, if (!(("" + ("-1".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 277: -1 should be < false",}, b0, false, false, "z5", null); } -if (!(("" + ("-1".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 278: -1 should be = false",}, b0, false, false, "z7", null); } if (!(("" + ("-1".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -846,7 +846,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 279: -1 should be > false",} if (!(("" + ("-1".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 280: -1 should be < NaN",}, b0, false, false, "z#", null); } -if (!(("" + ("-1".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 281: -1 should be = NaN",}, b0, false, false, "z(", null); } if (!(("" + ("-1".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -864,7 +864,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 285: -1 should be > Infinity if (!(("" + ("-1".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 286: -1 should be < banana",}, b0, false, false, "z=", null); } -if (!(("" + ("-1".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 287: -1 should be = banana",}, b0, false, false, "z@", null); } if (!(("" + ("-1".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -873,19 +873,19 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 288: -1 should be > banana", if (!(("" + ("-1".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 289: -1 should be < 🎉",}, b0, false, false, "z_", null); } -if (!(("" + ("-1".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 290: -1 should be = 🎉",}, b0, false, false, "z{", null); } if (!(("" + ("-1".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 291: -1 should be > 🎉",}, b0, false, false, "z}", null); } -if (!(("" + compareLessThan(-1, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 292: -1 should be < ",}, b0, false, false, "Aa", null); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 293: -1 should be = ",}, b0, false, false, "Ac", null); } -if (!(("" + compareGreaterThan(-1, "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 294: -1 should be > ",}, b0, false, false, "Ae", null); } if (!(("" + ("true".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -909,7 +909,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 300: true should be > 0.0",} if (!(("" + ("true".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 301: true should be < 1.23",}, b0, false, false, "As", null); } -if (!(("" + ("true".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 302: true should be = 1.23",}, b0, false, false, "Au", null); } if (!(("" + ("true".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -918,7 +918,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 303: true should be > 1.23", if (!(("" + ("true".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 304: true should be < .23",}, b0, false, false, "Ay", null); } -if (!(("" + ("true".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 305: true should be = .23",}, b0, false, false, "AA", null); } if (!(("" + ("true".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -927,7 +927,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 306: true should be > .23",} if (!(("" + ("true".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 307: true should be < 0.123",}, b0, false, false, "AE", null); } -if (!(("" + ("true".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 308: true should be = 0.123",}, b0, false, false, "AG", null); } if (!(("" + ("true".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -945,7 +945,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 312: true should be > -0",}, if (!(("" + ("true".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 313: true should be < -1",}, b0, false, false, "AQ", null); } -if (!(("" + ("true".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 314: true should be = -1",}, b0, false, false, "AS", null); } if (!(("" + ("true".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -981,7 +981,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 324: true should be > NaN",} if (!(("" + ("true".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 325: true should be < Infinity",}, b0, false, false, "A)", null); } -if (!(("" + ("true".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 326: true should be = Infinity",}, b0, false, false, "A+", null); } if (!(("" + ("true".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1035,7 +1035,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 342: false should be > 0.0", if (!(("" + ("false".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 343: false should be < 1.23",}, b0, false, false, "Bp", null); } -if (!(("" + ("false".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 344: false should be = 1.23",}, b0, false, false, "Br", null); } if (!(("" + ("false".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1044,7 +1044,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 345: false should be > 1.23" if (!(("" + ("false".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 346: false should be < .23",}, b0, false, false, "Bv", null); } -if (!(("" + ("false".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 347: false should be = .23",}, b0, false, false, "Bx", null); } if (!(("" + ("false".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1053,7 +1053,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 348: false should be > .23", if (!(("" + ("false".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 349: false should be < 0.123",}, b0, false, false, "BB", null); } -if (!(("" + ("false".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 350: false should be = 0.123",}, b0, false, false, "BD", null); } if (!(("" + ("false".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1071,7 +1071,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 354: false should be > -0",} if (!(("" + ("false".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 355: false should be < -1",}, b0, false, false, "BN", null); } -if (!(("" + ("false".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 356: false should be = -1",}, b0, false, false, "BP", null); } if (!(("" + ("false".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1107,7 +1107,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 366: false should be > NaN", if (!(("" + ("false".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 367: false should be < Infinity",}, b0, false, false, "B#", null); } -if (!(("" + ("false".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 368: false should be = Infinity",}, b0, false, false, "B(", null); } if (!(("" + ("false".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1161,7 +1161,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 384: NaN should be > 0.0",}, if (!(("" + ("NaN".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 385: NaN should be < 1.23",}, b0, false, false, "Cm", null); } -if (!(("" + ("NaN".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 386: NaN should be = 1.23",}, b0, false, false, "Co", null); } if (!(("" + ("NaN".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1170,7 +1170,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 387: NaN should be > 1.23",} if (!(("" + ("NaN".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 388: NaN should be < .23",}, b0, false, false, "Cs", null); } -if (!(("" + ("NaN".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 389: NaN should be = .23",}, b0, false, false, "Cu", null); } if (!(("" + ("NaN".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1179,7 +1179,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 390: NaN should be > .23",}, if (!(("" + ("NaN".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 391: NaN should be < 0.123",}, b0, false, false, "Cy", null); } -if (!(("" + ("NaN".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 392: NaN should be = 0.123",}, b0, false, false, "CA", null); } if (!(("" + ("NaN".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1197,7 +1197,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 396: NaN should be > -0",}, if (!(("" + ("NaN".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 397: NaN should be < -1",}, b0, false, false, "CK", null); } -if (!(("" + ("NaN".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 398: NaN should be = -1",}, b0, false, false, "CM", null); } if (!(("" + ("NaN".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1233,7 +1233,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 408: NaN should be > NaN",}, if (!(("" + ("NaN".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 409: NaN should be < Infinity",}, b0, false, false, "C8", null); } -if (!(("" + ("NaN".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 410: NaN should be = Infinity",}, b0, false, false, "C!", null); } if (!(("" + ("NaN".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1332,7 +1332,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 441: Infinity should be > -1 if (!(("" + ("Infinity".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 442: Infinity should be < true",}, b0, false, false, "DN", null); } -if (!(("" + ("Infinity".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (Infinity === 1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 443: Infinity should be = true",}, b0, false, false, "DP", null); } if (!(("" + ("Infinity".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1341,7 +1341,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 444: Infinity should be > tr if (!(("" + ("Infinity".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 445: Infinity should be < false",}, b0, false, false, "DT", null); } -if (!(("" + ("Infinity".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 446: Infinity should be = false",}, b0, false, false, "DV", null); } if (!(("" + ("Infinity".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1350,7 +1350,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 447: Infinity should be > fa if (!(("" + ("Infinity".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 448: Infinity should be < NaN",}, b0, false, false, "DZ", null); } -if (!(("" + ("Infinity".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 449: Infinity should be = NaN",}, b0, false, false, "D1", null); } if (!(("" + ("Infinity".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1368,7 +1368,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 453: Infinity should be > In if (!(("" + ("Infinity".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 454: Infinity should be < banana",}, b0, false, false, "D#", null); } -if (!(("" + ("Infinity".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 455: Infinity should be = banana",}, b0, false, false, "D(", null); } if (!(("" + ("Infinity".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1377,19 +1377,19 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 456: Infinity should be > ba if (!(("" + ("Infinity".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 457: Infinity should be < 🎉",}, b0, false, false, "D,", null); } -if (!(("" + ("Infinity".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 458: Infinity should be = 🎉",}, b0, false, false, "D.", null); } if (!(("" + ("Infinity".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 459: Infinity should be > 🎉",}, b0, false, false, "D:", null); } -if (!(("" + compareLessThan(Infinity, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 460: Infinity should be < ",}, b0, false, false, "D=", null); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 461: Infinity should be = ",}, b0, false, false, "D@", null); } -if (!(("" + compareGreaterThan(Infinity, "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 462: Infinity should be > ",}, b0, false, false, "D]", null); } if (!(("" + ("banana".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1413,7 +1413,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 468: banana should be > 0.0" if (!(("" + ("banana".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 469: banana should be < 1.23",}, b0, false, false, "Eg", null); } -if (!(("" + ("banana".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 470: banana should be = 1.23",}, b0, false, false, "Ei", null); } if (!(("" + ("banana".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1422,7 +1422,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 471: banana should be > 1.23 if (!(("" + ("banana".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 472: banana should be < .23",}, b0, false, false, "Em", null); } -if (!(("" + ("banana".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 473: banana should be = .23",}, b0, false, false, "Eo", null); } if (!(("" + ("banana".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1431,7 +1431,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 474: banana should be > .23" if (!(("" + ("banana".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 475: banana should be < 0.123",}, b0, false, false, "Es", null); } -if (!(("" + ("banana".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 476: banana should be = 0.123",}, b0, false, false, "Eu", null); } if (!(("" + ("banana".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1449,7 +1449,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 480: banana should be > -0", if (!(("" + ("banana".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 481: banana should be < -1",}, b0, false, false, "EE", null); } -if (!(("" + ("banana".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 482: banana should be = -1",}, b0, false, false, "EG", null); } if (!(("" + ("banana".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1485,7 +1485,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 492: banana should be > NaN" if (!(("" + ("banana".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 493: banana should be < Infinity",}, b0, false, false, "E2", null); } -if (!(("" + ("banana".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 494: banana should be = Infinity",}, b0, false, false, "E4", null); } if (!(("" + ("banana".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1539,7 +1539,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 510: 🎉 should be > 0.0",} if (!(("" + ("🎉".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 511: 🎉 should be < 1.23",}, b0, false, false, "Fd", null); } -if (!(("" + ("🎉".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 512: 🎉 should be = 1.23",}, b0, false, false, "Ff", null); } if (!(("" + ("🎉".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1548,7 +1548,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 513: 🎉 should be > 1.23", if (!(("" + ("🎉".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 514: 🎉 should be < .23",}, b0, false, false, "Fj", null); } -if (!(("" + ("🎉".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 515: 🎉 should be = .23",}, b0, false, false, "Fl", null); } if (!(("" + ("🎉".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1557,7 +1557,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 516: 🎉 should be > .23",} if (!(("" + ("🎉".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 517: 🎉 should be < 0.123",}, b0, false, false, "Fp", null); } -if (!(("" + ("🎉".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 518: 🎉 should be = 0.123",}, b0, false, false, "Fr", null); } if (!(("" + ("🎉".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1575,7 +1575,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 522: 🎉 should be > -0",}, if (!(("" + ("🎉".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 523: 🎉 should be < -1",}, b0, false, false, "FB", null); } -if (!(("" + ("🎉".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 524: 🎉 should be = -1",}, b0, false, false, "FD", null); } if (!(("" + ("🎉".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1611,7 +1611,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 534: 🎉 should be > NaN",} if (!(("" + ("🎉".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 535: 🎉 should be < Infinity",}, b0, false, false, "FZ", null); } -if (!(("" + ("🎉".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 536: 🎉 should be = Infinity",}, b0, false, false, "F1", null); } if (!(("" + ("🎉".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1644,67 +1644,67 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 545: 🎉 should be = ",}, b if (!(("" + ("🎉".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 546: 🎉 should be > ",}, b0, false, false, "F:", null); } -if (!(("" + compareLessThan("", 0)).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 547: should be < 0",}, b0, false, false, "F=", null); } -if (!(("" + compareEqual("", 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 548: should be = 0",}, b0, false, false, "F@", null); } -if (!(("" + compareGreaterThan("", 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 549: should be > 0",}, b0, false, false, "F]", null); } -if (!(("" + compareLessThan("", "0.0")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 550: should be < 0.0",}, b0, false, false, "F_", null); } -if (!(("" + compareEqual("", "0.0")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 551: should be = 0.0",}, b0, false, false, "F{", null); } -if (!(("" + compareGreaterThan("", "0.0")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 552: should be > 0.0",}, b0, false, false, "F}", null); } -if (!(("" + compareLessThan("", 1.23)).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 553: should be < 1.23",}, b0, false, false, "Ga", null); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 554: should be = 1.23",}, b0, false, false, "Gc", null); } -if (!(("" + compareGreaterThan("", 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 555: should be > 1.23",}, b0, false, false, "Ge", null); } -if (!(("" + compareLessThan("", ".23")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 556: should be < .23",}, b0, false, false, "Gg", null); } -if (!(("" + compareEqual("", ".23")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 557: should be = .23",}, b0, false, false, "Gi", null); } -if (!(("" + compareGreaterThan("", ".23")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 558: should be > .23",}, b0, false, false, "Gk", null); } -if (!(("" + compareLessThan("", 0.123)).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 559: should be < 0.123",}, b0, false, false, "Gm", null); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 560: should be = 0.123",}, b0, false, false, "Go", null); } -if (!(("" + compareGreaterThan("", 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 561: should be > 0.123",}, b0, false, false, "Gq", null); } -if (!(("" + compareLessThan("", "-0")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 562: should be < -0",}, b0, false, false, "Gs", null); } -if (!(("" + compareEqual("", "-0")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 563: should be = -0",}, b0, false, false, "Gu", null); } -if (!(("" + compareGreaterThan("", "-0")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 564: should be > -0",}, b0, false, false, "Gw", null); } -if (!(("" + compareLessThan("", -1)).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 565: should be < -1",}, b0, false, false, "Gy", null); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 566: should be = -1",}, b0, false, false, "GA", null); } -if (!(("" + compareGreaterThan("", -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 567: should be > -1",}, b0, false, false, "GC", null); } if (!(("" + ("".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1734,13 +1734,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 575: should be = NaN",}, b0 if (!(("" + ("".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 576: should be > NaN",}, b0, false, false, "GU", null); } -if (!(("" + compareLessThan("", Infinity)).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 577: should be < Infinity",}, b0, false, false, "GW", null); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 578: should be = Infinity",}, b0, false, false, "GY", null); } -if (!(("" + compareGreaterThan("", Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 579: should be > Infinity",}, b0, false, false, "G0", null); } if (!(("" + ("".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1761,13 +1761,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 584: should be = 🎉",}, b if (!(("" + ("".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 585: should be > 🎉",}, b0, false, false, "G%", null); } -if (!(("" + compareLessThan("", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 586: should be < ",}, b0, false, false, "G)", null); } -if (!(("" + compareEqual("", "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 587: should be = ",}, b0, false, false, "G+", null); } -if (!(("" + compareGreaterThan("", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 588: should be > ",}, b0, false, false, "G.", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "G-", null); diff --git a/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot index f97edfc1438..69c59c95f94 100644 --- a/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot @@ -11,7 +11,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "aZ", n retire(); return; }; }) -// Sprite1 Wrun test +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["mfV;yS}9e:%h5UZ)QyiY"]; const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; @@ -29,15 +29,15 @@ b3.value = 0; for (var a1 = b2.value.length; a1 >= 0.5; a1--) { b3.value = ((+b3.value || 0) + 1); b0.value = ((+b0.value || 0) + 1); -if (!compareEqual(compareGreaterThan(listGet(b2.value, b1.value), (b2.value[((b3.value || 0) | 0) - 1] ?? "")), (b4.value[((b0.value || 0) | 0) - 1] ?? ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be > " + ("" + listGet(b2.value, b3.value))))),}, b5, true, false, "]", null); +if (!compareEqual(compareGreaterThan(listGet(b2.value, b1.value), (b2.value[(b3.value | 0) - 1] ?? "")), (b4.value[(b0.value | 0) - 1] ?? ""))) { +yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be > " + ("" + (b2.value[(b3.value | 0) - 1] ?? ""))))),}, b5, true, false, "]", null); } b0.value = ((+b0.value || 0) + 1); -if (!compareEqual(compareEqual(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[((b0.value || 0) | 0) - 1] ?? ""))) { +if (!compareEqual(compareEqual(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be = " + ("" + listGet(b2.value, b3.value))))),}, b5, true, false, "|", null); } b0.value = ((+b0.value || 0) + 1); -if (!compareEqual(compareLessThan(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[((b0.value || 0) | 0) - 1] ?? ""))) { +if (!compareEqual(compareLessThan(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be < " + ("" + listGet(b2.value, b3.value))))),}, b5, true, true, "ab", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } @@ -46,7 +46,7 @@ if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} return ""; }; }) -// Sprite1 Wsetup values +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["n^wm8jw#b24sggt.S^tD"]; return function funXYZ_setup_values () { @@ -105,7 +105,7 @@ b0.value.push((-1 / 0)); b0._monitorUpToDate = false; b0.value.push((0 / 0)); b0._monitorUpToDate = false; -b0.value.push(NaN); +b0.value.push("NaN"); b0._monitorUpToDate = false; b0.value.push("nan"); b0._monitorUpToDate = false; diff --git a/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot index 060537d67aa..1442da79f1a 100644 --- a/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot @@ -19,7 +19,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", nu retire(); return; }; }) -// Sprite1 Zblock name +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_block_name () { return 40; diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot index a63ba8842c5..5f84b8b41da 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot @@ -12,10 +12,10 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "k", n if (compareLessThan(("something".toLowerCase() === "else".toLowerCase()), ("1" + ""))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "m", null); } -if (compareGreaterThan(("something".toLowerCase() === "something".toLowerCase()), (0 + 0))) { +if (((+("something".toLowerCase() === "something".toLowerCase())) > (0 + 0))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "n", null); } -if (compareLessThan(("something".toLowerCase() === "else".toLowerCase()), (1 + 0))) { +if (((+("something".toLowerCase() === "else".toLowerCase())) < (1 + 0))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "o", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot index 7c736d4333e..d52a998ab3e 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot @@ -9,13 +9,13 @@ const b2 = target.variables["zShM`!CD?d_|Z,]5X}N6"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "d", null); b1.value = 2; -if (((+b1.value || 0) === 2)) { +if ((b1.value === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass variable",}, b0, false, false, "k", null); } b2.value = []; b2.value.push(3); b2._monitorUpToDate = false; -if (((+(b2.value[(1 | 0) - 1] ?? "") || 0) === 3)) { +if (((+(b2.value[1 - 1] ?? "") || 0) === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass list",}, b0, false, false, "m", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot index 704116bfee2..27d2ced7847 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot @@ -21,7 +21,7 @@ retire(); return; retire(); return; }; }) -// Sprite1 Wno refresh +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); @@ -41,14 +41,14 @@ runtime.ext_scratch3_motion._moveSteps(0, target); return ""; }; }) -// Sprite1 Wruns below with no refresh +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_runs_below_with_no_r () { yield* thread.procedures["Whas refresh"](); return ""; }; }) -// Sprite1 Whas refresh +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); diff --git a/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot index 07442f3cde8..1fc921d2408 100644 --- a/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot @@ -11,14 +11,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", nu retire(); return; }; }) -// Sprite1 Zfoo %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_foo_ (p0) { return ""; return ""; }; }) -// Sprite1 Zno op +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_no_op () { return ""; diff --git a/test/snapshot/__snapshots__/tw-list-any.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-list-any.sb3.tw-snapshot index cb39a249b24..d6988304d85 100644 --- a/test/snapshot/__snapshots__/tw-list-any.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-list-any.sb3.tw-snapshot @@ -30,7 +30,7 @@ listDelete(b1, "any"); if ((b1.value.length === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "C", null); } -if (compareEqual(listGet(b1.value, "*"), "")) { +if ((("" + listGet(b1.value, "*")).toLowerCase() === "".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "F", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "E", null); diff --git a/test/snapshot/__snapshots__/tw-one-divide-negative-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-one-divide-negative-zero.sb3.tw-snapshot index 2557ac32e0b..d87b4b227fe 100644 --- a/test/snapshot/__snapshots__/tw-one-divide-negative-zero.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-one-divide-negative-zero.sb3.tw-snapshot @@ -6,7 +6,7 @@ const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "@|B*yJ0zKh!acN`7L-N5", null); -if ((((1 / -0) || 0) === -Infinity)) { +if (((1 / -0) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "=enYDFG11Nj/0BL:y56w", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",Cpv8W0RH0RgNky[1xb:", null); diff --git a/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot index 58b908a70ce..d6e18a37046 100644 --- a/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot @@ -11,7 +11,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Q^(MKg retire(); return; }; }) -// Player ZSet Costume +// Player script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_Set_Costume () { diff --git a/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot index f2456f2e254..2555707ccc2 100644 --- a/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot @@ -12,7 +12,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb retire(); return; }; }) -// Sprite1 Znumber or text %s %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_number_or_text__ (p0,p1) { @@ -22,7 +22,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "HH`yR return ""; }; }) -// Sprite1 Zboolean %b %b +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_boolean__ (p0,p1) { diff --git a/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot index 548eb4b32c7..4c4667116e7 100644 --- a/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot @@ -9,14 +9,14 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "qf{MD}-f+l?U+)KA#Vnm", null); b1.value = ""; thread.procedures["Zdo something"](); -if (!compareEqual(b1.value, "")) { +if (!(b1.value.toLowerCase() === "".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "Sgf_#7|GOpx!R]?Q3]$s", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",vD-ZG7f{]FoJ`,))JWh", null); retire(); return; }; }) -// Sprite1 Zdo something +// 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 funXYZ_do_something () { diff --git a/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot index 2aa9b207d24..4e435ae0fdb 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot @@ -39,14 +39,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "P", nu retire(); return; }; }) -// Sprite1 Zinvalid params - reporter +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_invalid_params___rep () { return 0; return ""; }; }) -// Sprite1 Zinvalid params - boolean +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_invalid_params___boo () { return 0; diff --git a/test/snapshot/__snapshots__/tw-procedure-return-non-existent.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-non-existent.sb3.tw-snapshot index 8a2837c67b0..cea7ecccc17 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-non-existent.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-non-existent.sb3.tw-snapshot @@ -9,7 +9,7 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); b1.value = "discard me"; b1.value = ""; -if (compareEqual(b1.value, "")) { +if ((("" + b1.value).toLowerCase() === "".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent procedure returned empty string",}, b0, false, false, "h", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null); 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 6251bdac2ea..e1176792d95 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 (((+b1.value || 0) === 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"); @@ -30,7 +30,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "av", n retire(); return; }; }) -// Sprite1 Znon warp recursion should yield %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_non_warp_recursion_s (p0) { if (compareGreaterThan(p0, 0)) { @@ -39,7 +39,7 @@ return (yield* yieldThenCallGenerator(thread.procedures["Znon warp recursion sho return ""; }; }) -// Sprite1 Wwarp recursion should not yield %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_warp_recursion_shoul (p0) { if (compareGreaterThan(p0, 0)) { @@ -48,7 +48,7 @@ return thread.procedures["Wwarp recursion should not yield %s"](((+p0 || 0) - 1) return ""; }; }) -// Sprite1 Zfib %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { @@ -59,7 +59,7 @@ return ((+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], ((+p0 || return ""; }; }) -// Sprite1 Zrecursing yields between each %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; @@ -68,7 +68,7 @@ return function* genXYZ_recursing_yields_bet (p0) { if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = 0; b1.value = ((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0) + (+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0)) || 0)) || 0)) || 0)) || 0)); -if (((+b0.value || 0) === 3)) { +if ((b0.value === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recursing between calls yields final",}, b2, false, false, "aK", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":"fail recursing between calls yields final",}, b2, false, false, "aL", null); @@ -83,7 +83,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":("fail recursing between calls yie return ""; }; }) -// Sprite1 Zrecursing arguments eval order %s %s %s %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["4HH82mPlVMOONdl(Ot*7"]; const b1 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; @@ -94,25 +94,25 @@ if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = []; b1.value = 0; b2.value = (yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 1",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 2",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 3",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 4","","","")),(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 5","","","")),(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 6","","","")))),"","")),"",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 7","","","")))); -if ((("" + (b0.value[(1 | 0) - 1] ?? "")).toLowerCase() === "1/child 4".toLowerCase())) { +if ((("" + (b0.value[1 - 1] ?? "")).toLowerCase() === "1/child 4".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 1",}, b3, false, false, "aZ", null); } -if ((("" + (b0.value[(2 | 0) - 1] ?? "")).toLowerCase() === "1/child 5".toLowerCase())) { +if ((("" + (b0.value[2 - 1] ?? "")).toLowerCase() === "1/child 5".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 2",}, b3, false, false, "a#", null); } -if ((("" + (b0.value[(3 | 0) - 1] ?? "")).toLowerCase() === "2/child 6".toLowerCase())) { +if ((("" + (b0.value[3 - 1] ?? "")).toLowerCase() === "2/child 6".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 3",}, b3, false, false, "a(", null); } -if ((("" + (b0.value[(4 | 0) - 1] ?? "")).toLowerCase() === "2/child 3".toLowerCase())) { +if ((("" + (b0.value[4 - 1] ?? "")).toLowerCase() === "2/child 3".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 4",}, b3, false, false, "a*", null); } -if ((("" + (b0.value[(5 | 0) - 1] ?? "")).toLowerCase() === "3/child 2".toLowerCase())) { +if ((("" + (b0.value[5 - 1] ?? "")).toLowerCase() === "3/child 2".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 5",}, b3, false, false, "a,", null); } -if ((("" + (b0.value[(6 | 0) - 1] ?? "")).toLowerCase() === "3/child 7".toLowerCase())) { +if ((("" + (b0.value[6 - 1] ?? "")).toLowerCase() === "3/child 7".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 6",}, b3, false, false, "a.", null); } -if ((("" + (b0.value[(7 | 0) - 1] ?? "")).toLowerCase() === "4/child 1".toLowerCase())) { +if ((("" + (b0.value[7 - 1] ?? "")).toLowerCase() === "4/child 1".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 7",}, b3, false, false, "a:", null); } if ((b0.value.length === 7)) { diff --git a/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot index b0ae54eb5bc..c37d030d128 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot @@ -20,21 +20,21 @@ if (((+thread.procedures["Wfactorial %s"](12) || 0) === 479001600)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass factorial 12",}, b0, false, false, "]", null); } b1.value = (yield* thread.procedures["Zno shadowing 1 %s %s"]("f","g")); -if (compareEqual(b1.value, "")) { +if ((("" + b1.value).toLowerCase() === "".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass default return value",}, b0, false, false, "|", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "`", null); retire(); return; }; }) -// Sprite1 Zsimplest +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_simplest () { return "It works!"; return ""; }; }) -// Sprite1 Znesting 1 +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_1 () { thread.procedures["Znesting 2"](); @@ -42,14 +42,14 @@ return (("" + thread.procedures["Znesting 3 %s %s"](6,7)) + ("" + thread.procedu return ""; }; }) -// Sprite1 Wwarp fib %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_warp_fib_ (p0) { return thread.procedures["Wfib %s"](p0); return ""; }; }) -// Sprite1 Wfactorial %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_factorial_ (p0) { if (compareGreaterThan(p0, 1)) { @@ -59,7 +59,7 @@ return 1; return ""; }; }) -// Sprite1 Zno shadowing 1 %s %s +// 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"]; @@ -78,21 +78,21 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass shadow check 3",}, b0, false return ""; }; }) -// Sprite1 Znesting 2 +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_2 () { return "discard nesting 2"; return ""; }; }) -// Sprite1 Znesting 3 %s %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_3__ (p0,p1) { return ((+p0 || 0) * (+p1 || 0)); return ""; }; }) -// Sprite1 Wfib %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { @@ -103,7 +103,7 @@ return ((+thread.procedures["Wfib %s"](((+p0 || 0) - 1)) || 0) + (+thread.proced return ""; }; }) -// Sprite1 Zno shadowing 2 %s %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_no_shadowing_2__ (p0,p1) { return "discard shadow 2"; diff --git a/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot index 29d85a58139..4980c3d3459 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot @@ -19,15 +19,15 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "v", nu retire(); return; }; }) -// Sprite1 Wreturn stops the script immediately +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_return_stops_the_scr () { b0.value = 0; for (var a0 = 100; a0 >= 0.5; a0--) { -b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 25)) { +b0.value = (b0.value + 1); +if ((b0.value === 25)) { return "stopped!"; } } @@ -42,7 +42,7 @@ return function* genXYZ () { b0.value = 0; while (true) { b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 18)) { +if ((b0.value === 18)) { retire(); return; } yield; diff --git a/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot index fde5f016583..cc9735dfe4b 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot @@ -32,7 +32,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "N", nu retire(); return; }; }) -// Sprite1 Znon warp +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); @@ -73,7 +73,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 2",}, b1, false, fa return ""; }; }) -// Sprite1 Wverify runs warp %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); @@ -95,7 +95,7 @@ return ("warp: " + ("" + p0)); return ""; }; }) -// Sprite1 Zverify runs non warp %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); diff --git a/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot index 88f7ab0b015..033cebf8ce1 100644 --- a/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot @@ -18,7 +18,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb retire(); return; }; }) -// Sprite1 Zswitch %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_switch_ (p0) { runtime.ext_scratch3_looks._setCostume(target, p0); diff --git a/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot index ee91780681f..a370af3e46d 100644 --- a/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot @@ -36,7 +36,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass direction",}, b0, false, fal if (((b2 ? b2.currentCostume + 1 : 0) === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass costume #",}, b0, false, false, "+zO[+f?c7F`ZGTbD.oqI", null); } -if ((("" + (b2 ? b2.getCostumes()[b2.currentCostume].name : 0)).toLowerCase() === "Costume name test".toLowerCase())) { +if (((b2 ? b2.getCostumes()[b2.currentCostume].name : 0).toLowerCase() === "Costume name test".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass costume name",}, b0, false, false, "Y6L|T0Pvwsct2gq+HGvv", null); } if (((b2 ? b2.size : 0) === 76.01)) { @@ -52,7 +52,7 @@ if (compareEqual((b4 ? b4.value : 0), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent variable",}, b0, false, false, ")nnN?*l+E)dC(fT5(_@q", null); } b5.value = (("" + randomInt(1, 9)) + ("" + randomInt(1, 9))); -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b5.value, PROPERTY: "backdrop #" }), 0)) { +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "backdrop #" }), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop #",}, b0, false, false, "UFr{fbR3@a.u_paq:r]F", null); } if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "backdrop name" }), 0)) { diff --git a/test/snapshot/__snapshots__/tw-tab-equals-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-tab-equals-zero.sb3.tw-snapshot index 0169ba16db3..119556a43f1 100644 --- a/test/snapshot/__snapshots__/tw-tab-equals-zero.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-tab-equals-zero.sb3.tw-snapshot @@ -29,7 +29,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t and other spaces = strin if (compareEqual(b0.value, (0 + 0))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t in a variable = number 0",}, b1, false, false, "z", null); } -if (compareEqual("\t", (0 + 0))) { +if ((0 === (0 + 0))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass literal \\t = number 0",}, b1, false, false, "B", null); } if (compareEqual((" " + ("" + b0.value)), (0 + 0))) { diff --git a/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot index b2ccf9ce3a3..17992397285 100644 --- a/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot @@ -6,31 +6,31 @@ const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b0, false, false, "p", null); -if (compareEqual(tan(0), 0)) { +if (((tan(0) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 0",}, b0, false, false, "O", null); } if (((tan(90) || 0) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 90",}, b0, false, false, "G", null); } -if (compareEqual(tan(180), 0)) { +if (((tan(180) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 180",}, b0, false, false, "I", null); } if (((tan(270) || 0) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 270",}, b0, false, false, "K", null); } -if (compareEqual(tan(360), 0)) { +if (((tan(360) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 360",}, b0, false, false, "M", null); } if (((tan(450) || 0) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 450",}, b0, false, false, "Q", null); } -if (compareEqual(tan(540), 0)) { +if (((tan(540) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 540",}, b0, false, false, "S", null); } if (((tan(630) || 0) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 630",}, b0, false, false, "U", null); } -if (compareEqual(tan(720), 0)) { +if (((tan(720) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 720",}, b0, false, false, "W", null); } if (((tan(810) || 0) === Infinity)) { @@ -39,13 +39,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass 810",}, b0, false, false, "Y if (((tan(-90) || 0) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -90",}, b0, false, false, "0", null); } -if (compareEqual(tan(-180), 0)) { +if (((tan(-180) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -180",}, b0, false, false, "2", null); } if (((tan(-270) || 0) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -270",}, b0, false, false, "4", null); } -if (compareEqual(tan(-360), 0)) { +if (((tan(-360) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -360",}, b0, false, false, "6", null); } if (((tan(-450) || 0) === -Infinity)) { diff --git a/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot index 082b46ce62d..90a01cba05d 100644 --- a/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot @@ -15,23 +15,23 @@ if ((10 === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 2",}, b0, false, false, "@A5}x{mm-Gk?CVz3o0Yn", null); } b1.value = 10; -if (((+b1.value || 0) === 10)) { +if ((b1.value === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 3",}, b0, false, false, "Ul:BCck-}Fvdux~x#$${", null); } -if (compareEqual(b1.value, "010")) { +if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 4",}, b0, false, false, "8]2$7P)o#+#Lo]mFSBbx", null); } -if (compareEqual(b1.value, "0000000010")) { +if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 5",}, b0, false, false, "ZU^{OfKTg|+Au$$q0[]u", null); } for (var a0 = 1; a0 >= 0.5; a0--) { if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 6",}, b0, false, false, "HB+_IN}6=K[*ksxKXH0`", null); } -if (compareEqual(b1.value, "010")) { +if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 7",}, b0, false, false, ";73ODiwcp8IthYURTX;S", null); } -if (compareEqual(b1.value, "0000000010")) { +if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 8",}, b0, false, true, "${[MFmBL-D*1rbas9Q89", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } @@ -41,20 +41,20 @@ b2.value = "010"; if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 9",}, b0, false, false, "#.`@SBj!g-c0:_q/tMZo", null); } -if (compareEqual(b2.value, "010")) { +if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 10",}, b0, false, false, "B`o?V6/q6g),/2w};a#y", null); } -if (compareEqual(b2.value, "0000000010")) { +if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 11",}, b0, false, false, "TJ:#TkYBys*!RYiKLXb)", null); } for (var a1 = 1; a1 >= 0.5; a1--) { if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 12",}, b0, false, false, ",Z,~10Qo~j;(+VL+I3q:", null); } -if (compareEqual(b2.value, "010")) { +if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 13",}, b0, false, false, "|Mqx([(26M%#ggW9)U0s", null); } -if (compareEqual(b2.value, "0000000010")) { +if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 14",}, b0, false, true, "YvtiKF231lU8p5Qd97RP", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } @@ -69,16 +69,16 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "XzQt! if ((0 === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "rxZqw7cv8g;PDM4B%{`?", null); } -if (compareEqual(" ", 0)) { +if ((" ".toLowerCase() === "0".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "3G|)eVw1mQm;O~cRy`}0", null); } -if (compareEqual(0, " ")) { +if (("0".toLowerCase() === " ".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "sd5xXX*tsW/~A_Q!0;^w", null); } -if (compareEqual("", 0)) { +if (("".toLowerCase() === "0".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "7**baE=].WD9OoY1+IEu", null); } -if (compareEqual(0, "")) { +if (("0".toLowerCase() === "".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "7!IB!=o/2H.Jqj-8Vwhz", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "df{tf!WhfRwXgQ?SN_dj", null); diff --git a/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot index bd4bdca8439..d986e3e81a9 100644 --- a/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot @@ -11,14 +11,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "s", nu retire(); return; }; }) -// Sprite1 Wrun without screen refresh +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["F?*}X,`9XBpN_[piGRrz"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_run_without_screen_r () { -b0.value = (((daysSince2000() * 86400) || 0) + 3); +b0.value = ((daysSince2000() * 86400) + 3); runtime.ioDevices.clock.resetProjectTimer(); -while (!((runtime.ioDevices.clock.projectTimer() > 0.1) || compareGreaterThan((daysSince2000() * 86400), b0.value))) { +while (!((runtime.ioDevices.clock.projectTimer() > 0.1) || ((daysSince2000() * 86400) > b0.value))) { if (isStuck()) yield; } if (compareLessThan((daysSince2000() * 86400), b0.value)) { diff --git a/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot index 2faaed414da..826f1e0058f 100644 --- a/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot @@ -10,7 +10,7 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, ",a.euo_AgQTxR+D^x0M0", null); b1.value = 0; b2.value = ""; -while (!compareGreaterThan(b2.value, "")) { +while (!(b2.value.toLowerCase() > "".toLowerCase())) { startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "step" }); yield; } @@ -25,7 +25,7 @@ const b0 = stage.variables["7qur6!bGgvC9I(Nd5.HP"]; const b1 = stage.variables["sUOp@-6J4y0PqwiXit4!"]; return function* genXYZ () { b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 5)) { +if ((b0.value === 5)) { b1.value = "end"; } retire(); return; diff --git a/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot index 91457816d33..96c7ced79c1 100644 --- a/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot @@ -17,7 +17,7 @@ yield; } thread.timer = null; b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 1)) { +if ((b0.value === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "]4hbk*5ix]V00h|!x1oy", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 1 != " + ("" + b0.value)),}, b2, false, false, "H=x@7SpNJeX|!}8x5y4,", null); @@ -75,7 +75,7 @@ yield; } thread.timer = null; b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 2)) { +if ((b0.value === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "0i[-T:vYTt=bi47@byUE", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 2 != " + ("" + b0.value)),}, b2, false, false, "Coc1aZ;L9M-RyEt`syps", null); diff --git a/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot index 2d10b51e1ce..5145078f7aa 100644 --- a/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot @@ -51,7 +51,7 @@ yield; } thread.timer = null; b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 1)) { +if ((b0.value === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "RSQ{nVCc)6E)(`KlnFCF", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 1 != " + ("" + b0.value)),}, b2, false, false, "8k^j~`c^|YO@hkFd?~2d", null); @@ -75,7 +75,7 @@ yield; } thread.timer = null; b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 2)) { +if ((b0.value === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "KP?op(=Vg2#;@]!,C#.~", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 2 != " + ("" + b0.value)),}, b2, false, false, "=]|}L~4uQXTNtwJKw_;R", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot index 106f6edd6d0..417094fef11 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot @@ -9,61 +9,61 @@ yield* executeInCompatibilityLayer({"MESSAGE":"plan 20",}, b0, false, false, "v" if ((("" + (0 * Infinity)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "6", null); } -if (compareEqual((((0 * Infinity) || 0) * 1), 0)) { +if (((((0 * Infinity) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "#", null); } if ((("" + ((Math.acos(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "9", null); } -if (compareEqual(((((Math.acos(1.01) * 180) / Math.PI) || 0) * 1), 0)) { +if ((((((Math.acos(1.01) * 180) / Math.PI) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "(", null); } if ((("" + ((Math.asin(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "*", null); } -if (compareEqual(((((Math.asin(1.01) * 180) / Math.PI) || 0) * 1), 0)) { +if ((((((Math.asin(1.01) * 180) / Math.PI) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ",", null); } if ((("" + (0 / 0)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ".", null); } -if (compareEqual((((0 / 0) || 0) * 1), 0)) { +if (((((0 / 0) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ":", null); } if ((("" + Math.sqrt(-1)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "?", null); } -if (compareEqual(((Math.sqrt(-1) || 0) * 1), 0)) { +if ((((Math.sqrt(-1) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "@", null); } if ((("" + mod(0, 0)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "]", null); } -if (compareEqual(((mod(0, 0) || 0) * 1), 0)) { +if ((((mod(0, 0) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "_", null); } if ((("" + Math.log(-1)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "{", null); } -if (compareEqual(((Math.log(-1) || 0) * 1), 0)) { +if ((((Math.log(-1) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "}", null); } if ((("" + (Math.log(-1) / Math.LN10)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aa", null); } -if (compareEqual((((Math.log(-1) / Math.LN10) || 0) * 1), 0)) { +if (((((Math.log(-1) / Math.LN10) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ac", null); } -if (compareEqual((((Math.round(Math.sin((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1), 0)) { +if (((((Math.round(Math.sin((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ae", null); } -if (compareEqual((((Math.round(Math.cos((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1), 0)) { +if (((((Math.round(Math.cos((Math.PI * ((1 / 0) || 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ag", null); } -if (compareEqual(((tan(((1 / 0) || 0)) || 0) * 1), 0)) { +if ((((tan(((1 / 0) || 0)) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ai", null); } -if (compareEqual(((runtime.ext_scratch3_operators._random((-1 / 0), (1 / 0)) || 0) * 1), 0)) { +if ((((runtime.ext_scratch3_operators._random((-1 / 0), (1 / 0)) || 0) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ak", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "7", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot index c133a6cb76f..b7f47584e4f 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot @@ -11,7 +11,7 @@ target.setSize(96); b1.value = 0; while (!(100 === Math.round(target.size))) { b1.value = ((+b1.value || 0) + 1); -target.setSize(target.size + ((((100 - Math.round(target.size)) || 0) / 10) || 0)); +target.setSize(target.size + ((100 - Math.round(target.size)) / 10)); yield; } if (((+b1.value || 0) === 20)) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-color-input-returns-hex.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-color-input-returns-hex.sb3.tw-snapshot index bccad8ff318..070b355da4a 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-color-input-returns-hex.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-color-input-returns-hex.sb3.tw-snapshot @@ -8,7 +8,7 @@ const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); b1.value = "#22388a"; -if ((("" + b1.value).toLowerCase() === "#22388a".toLowerCase())) { +if ((b1.value.toLowerCase() === "#22388a".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "f", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "e", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot index 66d03cf758d..741ccca8ae7 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot @@ -123,13 +123,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 38: 0 should be = 🎉",}, b if (!(("" + ("0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 39: 0 should be > 🎉",}, b0, false, false, "uq", null); } -if (!(("" + compareLessThan(0, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 40: 0 should be < ",}, b0, false, false, "us", null); } -if (!(("" + compareEqual(0, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 41: 0 should be = ",}, b0, false, false, "uu", null); } -if (!(("" + compareGreaterThan(0, "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 42: 0 should be > ",}, b0, false, false, "uw", null); } if (!(("" + (0 < 0)).toLowerCase() === "false".toLowerCase())) { @@ -249,13 +249,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 80: 0.0 should be = 🎉",}, if (!(("" + ("0.0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 81: 0.0 should be > 🎉",}, b0, false, false, "vn", null); } -if (!(("" + compareLessThan("0.0", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 82: 0.0 should be < ",}, b0, false, false, "vp", null); } -if (!(("" + compareEqual("0.0", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 83: 0.0 should be = ",}, b0, false, false, "vr", null); } -if (!(("" + compareGreaterThan("0.0", "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("0.0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 84: 0.0 should be > ",}, b0, false, false, "vt", null); } if (!(("" + (1.23 < 0)).toLowerCase() === "false".toLowerCase())) { @@ -324,7 +324,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 105: 1.23 should be > -1",}, if (!(("" + ("1.23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 106: 1.23 should be < true",}, b0, false, false, "v#", null); } -if (!(("" + ("1.23".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1.23 === 1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 107: 1.23 should be = true",}, b0, false, false, "v(", null); } if (!(("" + ("1.23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -333,7 +333,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 108: 1.23 should be > true", if (!(("" + ("1.23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 109: 1.23 should be < false",}, b0, false, false, "v,", null); } -if (!(("" + ("1.23".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 110: 1.23 should be = false",}, b0, false, false, "v.", null); } if (!(("" + ("1.23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -342,7 +342,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 111: 1.23 should be > false" if (!(("" + ("1.23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 112: 1.23 should be < NaN",}, b0, false, false, "v=", null); } -if (!(("" + ("1.23".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 113: 1.23 should be = NaN",}, b0, false, false, "v@", null); } if (!(("" + ("1.23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -360,7 +360,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 117: 1.23 should be > Infini if (!(("" + ("1.23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 118: 1.23 should be < banana",}, b0, false, false, "wa", null); } -if (!(("" + ("1.23".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 119: 1.23 should be = banana",}, b0, false, false, "wc", null); } if (!(("" + ("1.23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -369,19 +369,19 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 120: 1.23 should be > banana if (!(("" + ("1.23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 121: 1.23 should be < 🎉",}, b0, false, false, "wg", null); } -if (!(("" + ("1.23".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 122: 1.23 should be = 🎉",}, b0, false, false, "wi", null); } if (!(("" + ("1.23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 123: 1.23 should be > 🎉",}, b0, false, false, "wk", null); } -if (!(("" + compareLessThan(1.23, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 124: 1.23 should be < ",}, b0, false, false, "wm", null); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 125: 1.23 should be = ",}, b0, false, false, "wo", null); } -if (!(("" + compareGreaterThan(1.23, "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 126: 1.23 should be > ",}, b0, false, false, "wq", null); } if (!(("" + (0.23 < 0)).toLowerCase() === "false".toLowerCase())) { @@ -450,7 +450,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 147: .23 should be > -1",}, if (!(("" + (".23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 148: .23 should be < true",}, b0, false, false, "w8", null); } -if (!(("" + (".23".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 149: .23 should be = true",}, b0, false, false, "w!", null); } if (!(("" + (".23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -459,7 +459,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 150: .23 should be > true",} if (!(("" + (".23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 151: .23 should be < false",}, b0, false, false, "w)", null); } -if (!(("" + (".23".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 152: .23 should be = false",}, b0, false, false, "w+", null); } if (!(("" + (".23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -468,7 +468,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 153: .23 should be > false", if (!(("" + (".23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 154: .23 should be < NaN",}, b0, false, false, "w/", null); } -if (!(("" + (".23".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 155: .23 should be = NaN",}, b0, false, false, "w;", null); } if (!(("" + (".23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -486,7 +486,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 159: .23 should be > Infinit if (!(("" + (".23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 160: .23 should be < banana",}, b0, false, false, "w|", null); } -if (!(("" + (".23".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 161: .23 should be = banana",}, b0, false, false, "w~", null); } if (!(("" + (".23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -495,19 +495,19 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 162: .23 should be > banana" if (!(("" + (".23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 163: .23 should be < 🎉",}, b0, false, false, "xd", null); } -if (!(("" + (".23".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 164: .23 should be = 🎉",}, b0, false, false, "xf", null); } if (!(("" + (".23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 165: .23 should be > 🎉",}, b0, false, false, "xh", null); } -if (!(("" + compareLessThan(".23", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 166: .23 should be < ",}, b0, false, false, "xj", null); } -if (!(("" + compareEqual(".23", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 167: .23 should be = ",}, b0, false, false, "xl", null); } -if (!(("" + compareGreaterThan(".23", "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + (".23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 168: .23 should be > ",}, b0, false, false, "xn", null); } if (!(("" + (0.123 < 0)).toLowerCase() === "false".toLowerCase())) { @@ -576,7 +576,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 189: 0.123 should be > -1",} if (!(("" + ("0.123".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 190: 0.123 should be < true",}, b0, false, false, "x5", null); } -if (!(("" + ("0.123".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.123 === 1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 191: 0.123 should be = true",}, b0, false, false, "x7", null); } if (!(("" + ("0.123".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -585,7 +585,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 192: 0.123 should be > true" if (!(("" + ("0.123".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 193: 0.123 should be < false",}, b0, false, false, "x#", null); } -if (!(("" + ("0.123".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 194: 0.123 should be = false",}, b0, false, false, "x(", null); } if (!(("" + ("0.123".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -594,7 +594,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 195: 0.123 should be > false if (!(("" + ("0.123".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 196: 0.123 should be < NaN",}, b0, false, false, "x,", null); } -if (!(("" + ("0.123".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 197: 0.123 should be = NaN",}, b0, false, false, "x.", null); } if (!(("" + ("0.123".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -612,7 +612,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 201: 0.123 should be > Infin if (!(("" + ("0.123".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 202: 0.123 should be < banana",}, b0, false, false, "x_", null); } -if (!(("" + ("0.123".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 203: 0.123 should be = banana",}, b0, false, false, "x{", null); } if (!(("" + ("0.123".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -621,19 +621,19 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 204: 0.123 should be > banan if (!(("" + ("0.123".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 205: 0.123 should be < 🎉",}, b0, false, false, "ya", null); } -if (!(("" + ("0.123".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 206: 0.123 should be = 🎉",}, b0, false, false, "yc", null); } if (!(("" + ("0.123".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 207: 0.123 should be > 🎉",}, b0, false, false, "ye", null); } -if (!(("" + compareLessThan(0.123, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 208: 0.123 should be < ",}, b0, false, false, "yg", null); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 209: 0.123 should be = ",}, b0, false, false, "yi", null); } -if (!(("" + compareGreaterThan(0.123, "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 210: 0.123 should be > ",}, b0, false, false, "yk", null); } if (!(("" + (-0 < 0)).toLowerCase() === "false".toLowerCase())) { @@ -753,13 +753,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 248: -0 should be = 🎉",}, if (!(("" + ("-0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 249: -0 should be > 🎉",}, b0, false, false, "zb", null); } -if (!(("" + compareLessThan("-0", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 250: -0 should be < ",}, b0, false, false, "zd", null); } -if (!(("" + compareEqual("-0", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 251: -0 should be = ",}, b0, false, false, "zf", null); } -if (!(("" + compareGreaterThan("-0", "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("-0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 252: -0 should be > ",}, b0, false, false, "zh", null); } if (!(("" + (-1 < 0)).toLowerCase() === "true".toLowerCase())) { @@ -828,7 +828,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 273: -1 should be > -1",}, b if (!(("" + ("-1".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 274: -1 should be < true",}, b0, false, false, "zZ", null); } -if (!(("" + ("-1".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (-1 === 1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 275: -1 should be = true",}, b0, false, false, "z1", null); } if (!(("" + ("-1".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -837,7 +837,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 276: -1 should be > true",}, if (!(("" + ("-1".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 277: -1 should be < false",}, b0, false, false, "z5", null); } -if (!(("" + ("-1".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 278: -1 should be = false",}, b0, false, false, "z7", null); } if (!(("" + ("-1".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -846,7 +846,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 279: -1 should be > false",} if (!(("" + ("-1".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 280: -1 should be < NaN",}, b0, false, false, "z#", null); } -if (!(("" + ("-1".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 281: -1 should be = NaN",}, b0, false, false, "z(", null); } if (!(("" + ("-1".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -864,7 +864,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 285: -1 should be > Infinity if (!(("" + ("-1".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 286: -1 should be < banana",}, b0, false, false, "z=", null); } -if (!(("" + ("-1".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 287: -1 should be = banana",}, b0, false, false, "z@", null); } if (!(("" + ("-1".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -873,19 +873,19 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 288: -1 should be > banana", if (!(("" + ("-1".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 289: -1 should be < 🎉",}, b0, false, false, "z_", null); } -if (!(("" + ("-1".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 290: -1 should be = 🎉",}, b0, false, false, "z{", null); } if (!(("" + ("-1".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 291: -1 should be > 🎉",}, b0, false, false, "z}", null); } -if (!(("" + compareLessThan(-1, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 292: -1 should be < ",}, b0, false, false, "Aa", null); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 293: -1 should be = ",}, b0, false, false, "Ac", null); } -if (!(("" + compareGreaterThan(-1, "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 294: -1 should be > ",}, b0, false, false, "Ae", null); } if (!(("" + ("true".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -909,7 +909,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 300: true should be > 0.0",} if (!(("" + ("true".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 301: true should be < 1.23",}, b0, false, false, "As", null); } -if (!(("" + ("true".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 302: true should be = 1.23",}, b0, false, false, "Au", null); } if (!(("" + ("true".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -918,7 +918,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 303: true should be > 1.23", if (!(("" + ("true".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 304: true should be < .23",}, b0, false, false, "Ay", null); } -if (!(("" + ("true".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 305: true should be = .23",}, b0, false, false, "AA", null); } if (!(("" + ("true".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -927,7 +927,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 306: true should be > .23",} if (!(("" + ("true".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 307: true should be < 0.123",}, b0, false, false, "AE", null); } -if (!(("" + ("true".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 308: true should be = 0.123",}, b0, false, false, "AG", null); } if (!(("" + ("true".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -945,7 +945,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 312: true should be > -0",}, if (!(("" + ("true".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 313: true should be < -1",}, b0, false, false, "AQ", null); } -if (!(("" + ("true".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 314: true should be = -1",}, b0, false, false, "AS", null); } if (!(("" + ("true".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -981,7 +981,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 324: true should be > NaN",} if (!(("" + ("true".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 325: true should be < Infinity",}, b0, false, false, "A)", null); } -if (!(("" + ("true".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (1 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 326: true should be = Infinity",}, b0, false, false, "A+", null); } if (!(("" + ("true".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1035,7 +1035,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 342: false should be > 0.0", if (!(("" + ("false".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 343: false should be < 1.23",}, b0, false, false, "Bp", null); } -if (!(("" + ("false".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 344: false should be = 1.23",}, b0, false, false, "Br", null); } if (!(("" + ("false".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1044,7 +1044,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 345: false should be > 1.23" if (!(("" + ("false".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 346: false should be < .23",}, b0, false, false, "Bv", null); } -if (!(("" + ("false".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 347: false should be = .23",}, b0, false, false, "Bx", null); } if (!(("" + ("false".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1053,7 +1053,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 348: false should be > .23", if (!(("" + ("false".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 349: false should be < 0.123",}, b0, false, false, "BB", null); } -if (!(("" + ("false".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 350: false should be = 0.123",}, b0, false, false, "BD", null); } if (!(("" + ("false".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1071,7 +1071,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 354: false should be > -0",} if (!(("" + ("false".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 355: false should be < -1",}, b0, false, false, "BN", null); } -if (!(("" + ("false".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 356: false should be = -1",}, b0, false, false, "BP", null); } if (!(("" + ("false".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1107,7 +1107,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 366: false should be > NaN", if (!(("" + ("false".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 367: false should be < Infinity",}, b0, false, false, "B#", null); } -if (!(("" + ("false".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 368: false should be = Infinity",}, b0, false, false, "B(", null); } if (!(("" + ("false".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1161,7 +1161,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 384: NaN should be > 0.0",}, if (!(("" + ("NaN".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 385: NaN should be < 1.23",}, b0, false, false, "Cm", null); } -if (!(("" + ("NaN".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 386: NaN should be = 1.23",}, b0, false, false, "Co", null); } if (!(("" + ("NaN".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1170,7 +1170,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 387: NaN should be > 1.23",} if (!(("" + ("NaN".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 388: NaN should be < .23",}, b0, false, false, "Cs", null); } -if (!(("" + ("NaN".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 389: NaN should be = .23",}, b0, false, false, "Cu", null); } if (!(("" + ("NaN".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1179,7 +1179,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 390: NaN should be > .23",}, if (!(("" + ("NaN".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 391: NaN should be < 0.123",}, b0, false, false, "Cy", null); } -if (!(("" + ("NaN".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 392: NaN should be = 0.123",}, b0, false, false, "CA", null); } if (!(("" + ("NaN".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1197,7 +1197,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 396: NaN should be > -0",}, if (!(("" + ("NaN".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 397: NaN should be < -1",}, b0, false, false, "CK", null); } -if (!(("" + ("NaN".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 398: NaN should be = -1",}, b0, false, false, "CM", null); } if (!(("" + ("NaN".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1233,7 +1233,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 408: NaN should be > NaN",}, if (!(("" + ("NaN".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 409: NaN should be < Infinity",}, b0, false, false, "C8", null); } -if (!(("" + ("NaN".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 410: NaN should be = Infinity",}, b0, false, false, "C!", null); } if (!(("" + ("NaN".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1332,7 +1332,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 441: Infinity should be > -1 if (!(("" + ("Infinity".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 442: Infinity should be < true",}, b0, false, false, "DN", null); } -if (!(("" + ("Infinity".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (Infinity === 1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 443: Infinity should be = true",}, b0, false, false, "DP", null); } if (!(("" + ("Infinity".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1341,7 +1341,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 444: Infinity should be > tr if (!(("" + ("Infinity".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 445: Infinity should be < false",}, b0, false, false, "DT", null); } -if (!(("" + ("Infinity".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 446: Infinity should be = false",}, b0, false, false, "DV", null); } if (!(("" + ("Infinity".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1350,7 +1350,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 447: Infinity should be > fa if (!(("" + ("Infinity".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 448: Infinity should be < NaN",}, b0, false, false, "DZ", null); } -if (!(("" + ("Infinity".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 449: Infinity should be = NaN",}, b0, false, false, "D1", null); } if (!(("" + ("Infinity".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1368,7 +1368,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 453: Infinity should be > In if (!(("" + ("Infinity".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 454: Infinity should be < banana",}, b0, false, false, "D#", null); } -if (!(("" + ("Infinity".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 455: Infinity should be = banana",}, b0, false, false, "D(", null); } if (!(("" + ("Infinity".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1377,19 +1377,19 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 456: Infinity should be > ba if (!(("" + ("Infinity".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 457: Infinity should be < 🎉",}, b0, false, false, "D,", null); } -if (!(("" + ("Infinity".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 458: Infinity should be = 🎉",}, b0, false, false, "D.", null); } if (!(("" + ("Infinity".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 459: Infinity should be > 🎉",}, b0, false, false, "D:", null); } -if (!(("" + compareLessThan(Infinity, "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 460: Infinity should be < ",}, b0, false, false, "D=", null); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 461: Infinity should be = ",}, b0, false, false, "D@", null); } -if (!(("" + compareGreaterThan(Infinity, "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 462: Infinity should be > ",}, b0, false, false, "D]", null); } if (!(("" + ("banana".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1413,7 +1413,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 468: banana should be > 0.0" if (!(("" + ("banana".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 469: banana should be < 1.23",}, b0, false, false, "Eg", null); } -if (!(("" + ("banana".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 470: banana should be = 1.23",}, b0, false, false, "Ei", null); } if (!(("" + ("banana".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1422,7 +1422,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 471: banana should be > 1.23 if (!(("" + ("banana".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 472: banana should be < .23",}, b0, false, false, "Em", null); } -if (!(("" + ("banana".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 473: banana should be = .23",}, b0, false, false, "Eo", null); } if (!(("" + ("banana".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1431,7 +1431,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 474: banana should be > .23" if (!(("" + ("banana".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 475: banana should be < 0.123",}, b0, false, false, "Es", null); } -if (!(("" + ("banana".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 476: banana should be = 0.123",}, b0, false, false, "Eu", null); } if (!(("" + ("banana".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1449,7 +1449,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 480: banana should be > -0", if (!(("" + ("banana".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 481: banana should be < -1",}, b0, false, false, "EE", null); } -if (!(("" + ("banana".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 482: banana should be = -1",}, b0, false, false, "EG", null); } if (!(("" + ("banana".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1485,7 +1485,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 492: banana should be > NaN" if (!(("" + ("banana".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 493: banana should be < Infinity",}, b0, false, false, "E2", null); } -if (!(("" + ("banana".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 494: banana should be = Infinity",}, b0, false, false, "E4", null); } if (!(("" + ("banana".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1539,7 +1539,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 510: 🎉 should be > 0.0",} if (!(("" + ("🎉".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 511: 🎉 should be < 1.23",}, b0, false, false, "Fd", null); } -if (!(("" + ("🎉".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 512: 🎉 should be = 1.23",}, b0, false, false, "Ff", null); } if (!(("" + ("🎉".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1548,7 +1548,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 513: 🎉 should be > 1.23", if (!(("" + ("🎉".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 514: 🎉 should be < .23",}, b0, false, false, "Fj", null); } -if (!(("" + ("🎉".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 515: 🎉 should be = .23",}, b0, false, false, "Fl", null); } if (!(("" + ("🎉".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1557,7 +1557,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 516: 🎉 should be > .23",} if (!(("" + ("🎉".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 517: 🎉 should be < 0.123",}, b0, false, false, "Fp", null); } -if (!(("" + ("🎉".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 518: 🎉 should be = 0.123",}, b0, false, false, "Fr", null); } if (!(("" + ("🎉".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1575,7 +1575,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 522: 🎉 should be > -0",}, if (!(("" + ("🎉".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 523: 🎉 should be < -1",}, b0, false, false, "FB", null); } -if (!(("" + ("🎉".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 524: 🎉 should be = -1",}, b0, false, false, "FD", null); } if (!(("" + ("🎉".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1611,7 +1611,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 534: 🎉 should be > NaN",} if (!(("" + ("🎉".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 535: 🎉 should be < Infinity",}, b0, false, false, "FZ", null); } -if (!(("" + ("🎉".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 536: 🎉 should be = Infinity",}, b0, false, false, "F1", null); } if (!(("" + ("🎉".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1644,67 +1644,67 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 545: 🎉 should be = ",}, b if (!(("" + ("🎉".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 546: 🎉 should be > ",}, b0, false, false, "F:", null); } -if (!(("" + compareLessThan("", 0)).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 547: should be < 0",}, b0, false, false, "F=", null); } -if (!(("" + compareEqual("", 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 548: should be = 0",}, b0, false, false, "F@", null); } -if (!(("" + compareGreaterThan("", 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 549: should be > 0",}, b0, false, false, "F]", null); } -if (!(("" + compareLessThan("", "0.0")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 550: should be < 0.0",}, b0, false, false, "F_", null); } -if (!(("" + compareEqual("", "0.0")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 551: should be = 0.0",}, b0, false, false, "F{", null); } -if (!(("" + compareGreaterThan("", "0.0")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 552: should be > 0.0",}, b0, false, false, "F}", null); } -if (!(("" + compareLessThan("", 1.23)).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 553: should be < 1.23",}, b0, false, false, "Ga", null); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 554: should be = 1.23",}, b0, false, false, "Gc", null); } -if (!(("" + compareGreaterThan("", 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 555: should be > 1.23",}, b0, false, false, "Ge", null); } -if (!(("" + compareLessThan("", ".23")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 556: should be < .23",}, b0, false, false, "Gg", null); } -if (!(("" + compareEqual("", ".23")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 557: should be = .23",}, b0, false, false, "Gi", null); } -if (!(("" + compareGreaterThan("", ".23")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 558: should be > .23",}, b0, false, false, "Gk", null); } -if (!(("" + compareLessThan("", 0.123)).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 559: should be < 0.123",}, b0, false, false, "Gm", null); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 560: should be = 0.123",}, b0, false, false, "Go", null); } -if (!(("" + compareGreaterThan("", 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 561: should be > 0.123",}, b0, false, false, "Gq", null); } -if (!(("" + compareLessThan("", "-0")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 562: should be < -0",}, b0, false, false, "Gs", null); } -if (!(("" + compareEqual("", "-0")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 563: should be = -0",}, b0, false, false, "Gu", null); } -if (!(("" + compareGreaterThan("", "-0")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 564: should be > -0",}, b0, false, false, "Gw", null); } -if (!(("" + compareLessThan("", -1)).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 565: should be < -1",}, b0, false, false, "Gy", null); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 566: should be = -1",}, b0, false, false, "GA", null); } -if (!(("" + compareGreaterThan("", -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 567: should be > -1",}, b0, false, false, "GC", null); } if (!(("" + ("".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1734,13 +1734,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 575: should be = NaN",}, b0 if (!(("" + ("".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 576: should be > NaN",}, b0, false, false, "GU", null); } -if (!(("" + compareLessThan("", Infinity)).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 577: should be < Infinity",}, b0, false, false, "GW", null); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 578: should be = Infinity",}, b0, false, false, "GY", null); } -if (!(("" + compareGreaterThan("", Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 579: should be > Infinity",}, b0, false, false, "G0", null); } if (!(("" + ("".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1761,13 +1761,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail 584: should be = 🎉",}, b if (!(("" + ("".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 585: should be > 🎉",}, b0, false, false, "G%", null); } -if (!(("" + compareLessThan("", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 586: should be < ",}, b0, false, false, "G)", null); } -if (!(("" + compareEqual("", "")).toLowerCase() === "true".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 587: should be = ",}, b0, false, false, "G+", null); } -if (!(("" + compareGreaterThan("", "")).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() > "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail 588: should be > ",}, b0, false, false, "G.", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "G-", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot index 0808a3a2fab..40c61fa7448 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot @@ -11,7 +11,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "aZ", n retire(); return; }; }) -// Sprite1 Wrun test +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["mfV;yS}9e:%h5UZ)QyiY"]; const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; @@ -29,15 +29,15 @@ b3.value = 0; for (var a1 = b2.value.length; a1 >= 0.5; a1--) { b3.value = ((+b3.value || 0) + 1); b0.value = ((+b0.value || 0) + 1); -if (!compareEqual(compareGreaterThan(listGet(b2.value, b1.value), (b2.value[((b3.value || 0) | 0) - 1] ?? "")), (b4.value[((b0.value || 0) | 0) - 1] ?? ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be > " + ("" + listGet(b2.value, b3.value))))),}, b5, true, false, "]", null); +if (!compareEqual(compareGreaterThan(listGet(b2.value, b1.value), (b2.value[(b3.value | 0) - 1] ?? "")), (b4.value[(b0.value | 0) - 1] ?? ""))) { +yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be > " + ("" + (b2.value[(b3.value | 0) - 1] ?? ""))))),}, b5, true, false, "]", null); } b0.value = ((+b0.value || 0) + 1); -if (!compareEqual(compareEqual(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[((b0.value || 0) | 0) - 1] ?? ""))) { +if (!compareEqual(compareEqual(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be = " + ("" + listGet(b2.value, b3.value))))),}, b5, true, false, "|", null); } b0.value = ((+b0.value || 0) + 1); -if (!compareEqual(compareLessThan(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[((b0.value || 0) | 0) - 1] ?? ""))) { +if (!compareEqual(compareLessThan(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be < " + ("" + listGet(b2.value, b3.value))))),}, b5, true, true, "ab", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } @@ -48,7 +48,7 @@ if (isStuck()) yield; return ""; }; }) -// Sprite1 Wsetup values +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["n^wm8jw#b24sggt.S^tD"]; return function funXYZ_setup_values () { @@ -107,7 +107,7 @@ b0.value.push((-1 / 0)); b0._monitorUpToDate = false; b0.value.push((0 / 0)); b0._monitorUpToDate = false; -b0.value.push(NaN); +b0.value.push("NaN"); b0._monitorUpToDate = false; b0.value.push("nan"); b0._monitorUpToDate = false; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot index 060537d67aa..1442da79f1a 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot @@ -19,7 +19,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", nu retire(); return; }; }) -// Sprite1 Zblock name +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_block_name () { return 40; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot index a63ba8842c5..5f84b8b41da 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot @@ -12,10 +12,10 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "k", n if (compareLessThan(("something".toLowerCase() === "else".toLowerCase()), ("1" + ""))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "m", null); } -if (compareGreaterThan(("something".toLowerCase() === "something".toLowerCase()), (0 + 0))) { +if (((+("something".toLowerCase() === "something".toLowerCase())) > (0 + 0))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "n", null); } -if (compareLessThan(("something".toLowerCase() === "else".toLowerCase()), (1 + 0))) { +if (((+("something".toLowerCase() === "else".toLowerCase())) < (1 + 0))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "o", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot index 7c736d4333e..d52a998ab3e 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot @@ -9,13 +9,13 @@ const b2 = target.variables["zShM`!CD?d_|Z,]5X}N6"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "d", null); b1.value = 2; -if (((+b1.value || 0) === 2)) { +if ((b1.value === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass variable",}, b0, false, false, "k", null); } b2.value = []; b2.value.push(3); b2._monitorUpToDate = false; -if (((+(b2.value[(1 | 0) - 1] ?? "") || 0) === 3)) { +if (((+(b2.value[1 - 1] ?? "") || 0) === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass list",}, b0, false, false, "m", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot index a3d93933160..7a3bed7c7af 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot @@ -21,7 +21,7 @@ retire(); return; retire(); return; }; }) -// Sprite1 Wno refresh +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); @@ -42,14 +42,14 @@ if (isStuck()) yield; return ""; }; }) -// Sprite1 Wruns below with no refresh +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_runs_below_with_no_r () { yield* thread.procedures["Whas refresh"](); return ""; }; }) -// Sprite1 Whas refresh +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot index 07442f3cde8..1fc921d2408 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot @@ -11,14 +11,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", nu retire(); return; }; }) -// Sprite1 Zfoo %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_foo_ (p0) { return ""; return ""; }; }) -// Sprite1 Zno op +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_no_op () { return ""; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-list-any.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-list-any.sb3.tw-snapshot index cb39a249b24..d6988304d85 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-list-any.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-list-any.sb3.tw-snapshot @@ -30,7 +30,7 @@ listDelete(b1, "any"); if ((b1.value.length === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "C", null); } -if (compareEqual(listGet(b1.value, "*"), "")) { +if ((("" + listGet(b1.value, "*")).toLowerCase() === "".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "F", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "E", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-one-divide-negative-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-one-divide-negative-zero.sb3.tw-snapshot index 2557ac32e0b..d87b4b227fe 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-one-divide-negative-zero.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-one-divide-negative-zero.sb3.tw-snapshot @@ -6,7 +6,7 @@ const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "@|B*yJ0zKh!acN`7L-N5", null); -if ((((1 / -0) || 0) === -Infinity)) { +if (((1 / -0) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "=enYDFG11Nj/0BL:y56w", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",Cpv8W0RH0RgNky[1xb:", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot index 58b908a70ce..d6e18a37046 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot @@ -11,7 +11,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Q^(MKg retire(); return; }; }) -// Player ZSet Costume +// Player script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_Set_Costume () { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot index f2456f2e254..2555707ccc2 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot @@ -12,7 +12,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb retire(); return; }; }) -// Sprite1 Znumber or text %s %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_number_or_text__ (p0,p1) { @@ -22,7 +22,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "HH`yR return ""; }; }) -// Sprite1 Zboolean %b %b +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_boolean__ (p0,p1) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot index 548eb4b32c7..4c4667116e7 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot @@ -9,14 +9,14 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "qf{MD}-f+l?U+)KA#Vnm", null); b1.value = ""; thread.procedures["Zdo something"](); -if (!compareEqual(b1.value, "")) { +if (!(b1.value.toLowerCase() === "".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "Sgf_#7|GOpx!R]?Q3]$s", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",vD-ZG7f{]FoJ`,))JWh", null); retire(); return; }; }) -// Sprite1 Zdo something +// 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 funXYZ_do_something () { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot index 2aa9b207d24..4e435ae0fdb 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot @@ -39,14 +39,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "P", nu retire(); return; }; }) -// Sprite1 Zinvalid params - reporter +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_invalid_params___rep () { return 0; return ""; }; }) -// Sprite1 Zinvalid params - boolean +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_invalid_params___boo () { return 0; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existent.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existent.sb3.tw-snapshot index 8a2837c67b0..cea7ecccc17 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existent.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existent.sb3.tw-snapshot @@ -9,7 +9,7 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); b1.value = "discard me"; b1.value = ""; -if (compareEqual(b1.value, "")) { +if ((("" + b1.value).toLowerCase() === "".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent procedure returned empty string",}, b0, false, false, "h", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null); 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 6251bdac2ea..e1176792d95 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 (((+b1.value || 0) === 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"); @@ -30,7 +30,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "av", n retire(); return; }; }) -// Sprite1 Znon warp recursion should yield %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_non_warp_recursion_s (p0) { if (compareGreaterThan(p0, 0)) { @@ -39,7 +39,7 @@ return (yield* yieldThenCallGenerator(thread.procedures["Znon warp recursion sho return ""; }; }) -// Sprite1 Wwarp recursion should not yield %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_warp_recursion_shoul (p0) { if (compareGreaterThan(p0, 0)) { @@ -48,7 +48,7 @@ return thread.procedures["Wwarp recursion should not yield %s"](((+p0 || 0) - 1) return ""; }; }) -// Sprite1 Zfib %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { @@ -59,7 +59,7 @@ return ((+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], ((+p0 || return ""; }; }) -// Sprite1 Zrecursing yields between each %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; @@ -68,7 +68,7 @@ return function* genXYZ_recursing_yields_bet (p0) { if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = 0; b1.value = ((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0) + (+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0)) || 0)) || 0)) || 0)) || 0)); -if (((+b0.value || 0) === 3)) { +if ((b0.value === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recursing between calls yields final",}, b2, false, false, "aK", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":"fail recursing between calls yields final",}, b2, false, false, "aL", null); @@ -83,7 +83,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":("fail recursing between calls yie return ""; }; }) -// Sprite1 Zrecursing arguments eval order %s %s %s %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["4HH82mPlVMOONdl(Ot*7"]; const b1 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; @@ -94,25 +94,25 @@ if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = []; b1.value = 0; b2.value = (yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 1",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 2",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 3",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 4","","","")),(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 5","","","")),(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 6","","","")))),"","")),"",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 7","","","")))); -if ((("" + (b0.value[(1 | 0) - 1] ?? "")).toLowerCase() === "1/child 4".toLowerCase())) { +if ((("" + (b0.value[1 - 1] ?? "")).toLowerCase() === "1/child 4".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 1",}, b3, false, false, "aZ", null); } -if ((("" + (b0.value[(2 | 0) - 1] ?? "")).toLowerCase() === "1/child 5".toLowerCase())) { +if ((("" + (b0.value[2 - 1] ?? "")).toLowerCase() === "1/child 5".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 2",}, b3, false, false, "a#", null); } -if ((("" + (b0.value[(3 | 0) - 1] ?? "")).toLowerCase() === "2/child 6".toLowerCase())) { +if ((("" + (b0.value[3 - 1] ?? "")).toLowerCase() === "2/child 6".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 3",}, b3, false, false, "a(", null); } -if ((("" + (b0.value[(4 | 0) - 1] ?? "")).toLowerCase() === "2/child 3".toLowerCase())) { +if ((("" + (b0.value[4 - 1] ?? "")).toLowerCase() === "2/child 3".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 4",}, b3, false, false, "a*", null); } -if ((("" + (b0.value[(5 | 0) - 1] ?? "")).toLowerCase() === "3/child 2".toLowerCase())) { +if ((("" + (b0.value[5 - 1] ?? "")).toLowerCase() === "3/child 2".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 5",}, b3, false, false, "a,", null); } -if ((("" + (b0.value[(6 | 0) - 1] ?? "")).toLowerCase() === "3/child 7".toLowerCase())) { +if ((("" + (b0.value[6 - 1] ?? "")).toLowerCase() === "3/child 7".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 6",}, b3, false, false, "a.", null); } -if ((("" + (b0.value[(7 | 0) - 1] ?? "")).toLowerCase() === "4/child 1".toLowerCase())) { +if ((("" + (b0.value[7 - 1] ?? "")).toLowerCase() === "4/child 1".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 7",}, b3, false, false, "a:", null); } if ((b0.value.length === 7)) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot index b0ae54eb5bc..c37d030d128 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot @@ -20,21 +20,21 @@ if (((+thread.procedures["Wfactorial %s"](12) || 0) === 479001600)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass factorial 12",}, b0, false, false, "]", null); } b1.value = (yield* thread.procedures["Zno shadowing 1 %s %s"]("f","g")); -if (compareEqual(b1.value, "")) { +if ((("" + b1.value).toLowerCase() === "".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass default return value",}, b0, false, false, "|", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "`", null); retire(); return; }; }) -// Sprite1 Zsimplest +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_simplest () { return "It works!"; return ""; }; }) -// Sprite1 Znesting 1 +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_1 () { thread.procedures["Znesting 2"](); @@ -42,14 +42,14 @@ return (("" + thread.procedures["Znesting 3 %s %s"](6,7)) + ("" + thread.procedu return ""; }; }) -// Sprite1 Wwarp fib %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_warp_fib_ (p0) { return thread.procedures["Wfib %s"](p0); return ""; }; }) -// Sprite1 Wfactorial %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_factorial_ (p0) { if (compareGreaterThan(p0, 1)) { @@ -59,7 +59,7 @@ return 1; return ""; }; }) -// Sprite1 Zno shadowing 1 %s %s +// 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"]; @@ -78,21 +78,21 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass shadow check 3",}, b0, false return ""; }; }) -// Sprite1 Znesting 2 +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_2 () { return "discard nesting 2"; return ""; }; }) -// Sprite1 Znesting 3 %s %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_3__ (p0,p1) { return ((+p0 || 0) * (+p1 || 0)); return ""; }; }) -// Sprite1 Wfib %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { @@ -103,7 +103,7 @@ return ((+thread.procedures["Wfib %s"](((+p0 || 0) - 1)) || 0) + (+thread.proced return ""; }; }) -// Sprite1 Zno shadowing 2 %s %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_no_shadowing_2__ (p0,p1) { return "discard shadow 2"; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot index c0355f7aa47..7ea58c0cd93 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot @@ -19,7 +19,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "v", nu retire(); return; }; }) -// Sprite1 Wreturn stops the script immediately +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; const b1 = runtime.getOpcodeFunction("looks_say"); @@ -27,7 +27,7 @@ return function* genXYZ_return_stops_the_scr () { b0.value = 0; for (var a0 = 100; a0 >= 0.5; a0--) { b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 25)) { +if ((b0.value === 25)) { return "stopped!"; } if (isStuck()) yield; @@ -43,7 +43,7 @@ return function* genXYZ () { b0.value = 0; while (true) { b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 18)) { +if ((b0.value === 18)) { retire(); return; } yield; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot index d7afc882d25..edf65b39d91 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot @@ -32,7 +32,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "N", nu retire(); return; }; }) -// Sprite1 Znon warp +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); @@ -73,7 +73,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 2",}, b1, false, fa return ""; }; }) -// Sprite1 Wverify runs warp %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); @@ -96,7 +96,7 @@ return ("warp: " + ("" + p0)); return ""; }; }) -// Sprite1 Zverify runs non warp %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot index 88f7ab0b015..033cebf8ce1 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot @@ -18,7 +18,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb retire(); return; }; }) -// Sprite1 Zswitch %s +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_switch_ (p0) { runtime.ext_scratch3_looks._setCostume(target, p0); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot index ee91780681f..a370af3e46d 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot @@ -36,7 +36,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass direction",}, b0, false, fal if (((b2 ? b2.currentCostume + 1 : 0) === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass costume #",}, b0, false, false, "+zO[+f?c7F`ZGTbD.oqI", null); } -if ((("" + (b2 ? b2.getCostumes()[b2.currentCostume].name : 0)).toLowerCase() === "Costume name test".toLowerCase())) { +if (((b2 ? b2.getCostumes()[b2.currentCostume].name : 0).toLowerCase() === "Costume name test".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass costume name",}, b0, false, false, "Y6L|T0Pvwsct2gq+HGvv", null); } if (((b2 ? b2.size : 0) === 76.01)) { @@ -52,7 +52,7 @@ if (compareEqual((b4 ? b4.value : 0), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent variable",}, b0, false, false, ")nnN?*l+E)dC(fT5(_@q", null); } b5.value = (("" + randomInt(1, 9)) + ("" + randomInt(1, 9))); -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b5.value, PROPERTY: "backdrop #" }), 0)) { +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "backdrop #" }), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop #",}, b0, false, false, "UFr{fbR3@a.u_paq:r]F", null); } if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "backdrop name" }), 0)) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-tab-equals-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-tab-equals-zero.sb3.tw-snapshot index 0169ba16db3..119556a43f1 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-tab-equals-zero.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-tab-equals-zero.sb3.tw-snapshot @@ -29,7 +29,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t and other spaces = strin if (compareEqual(b0.value, (0 + 0))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t in a variable = number 0",}, b1, false, false, "z", null); } -if (compareEqual("\t", (0 + 0))) { +if ((0 === (0 + 0))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass literal \\t = number 0",}, b1, false, false, "B", null); } if (compareEqual((" " + ("" + b0.value)), (0 + 0))) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot index b2ccf9ce3a3..17992397285 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot @@ -6,31 +6,31 @@ const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b0, false, false, "p", null); -if (compareEqual(tan(0), 0)) { +if (((tan(0) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 0",}, b0, false, false, "O", null); } if (((tan(90) || 0) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 90",}, b0, false, false, "G", null); } -if (compareEqual(tan(180), 0)) { +if (((tan(180) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 180",}, b0, false, false, "I", null); } if (((tan(270) || 0) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 270",}, b0, false, false, "K", null); } -if (compareEqual(tan(360), 0)) { +if (((tan(360) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 360",}, b0, false, false, "M", null); } if (((tan(450) || 0) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 450",}, b0, false, false, "Q", null); } -if (compareEqual(tan(540), 0)) { +if (((tan(540) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 540",}, b0, false, false, "S", null); } if (((tan(630) || 0) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 630",}, b0, false, false, "U", null); } -if (compareEqual(tan(720), 0)) { +if (((tan(720) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 720",}, b0, false, false, "W", null); } if (((tan(810) || 0) === Infinity)) { @@ -39,13 +39,13 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass 810",}, b0, false, false, "Y if (((tan(-90) || 0) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -90",}, b0, false, false, "0", null); } -if (compareEqual(tan(-180), 0)) { +if (((tan(-180) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -180",}, b0, false, false, "2", null); } if (((tan(-270) || 0) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -270",}, b0, false, false, "4", null); } -if (compareEqual(tan(-360), 0)) { +if (((tan(-360) || 0) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -360",}, b0, false, false, "6", null); } if (((tan(-450) || 0) === -Infinity)) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot index 082b46ce62d..90a01cba05d 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot @@ -15,23 +15,23 @@ if ((10 === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 2",}, b0, false, false, "@A5}x{mm-Gk?CVz3o0Yn", null); } b1.value = 10; -if (((+b1.value || 0) === 10)) { +if ((b1.value === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 3",}, b0, false, false, "Ul:BCck-}Fvdux~x#$${", null); } -if (compareEqual(b1.value, "010")) { +if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 4",}, b0, false, false, "8]2$7P)o#+#Lo]mFSBbx", null); } -if (compareEqual(b1.value, "0000000010")) { +if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 5",}, b0, false, false, "ZU^{OfKTg|+Au$$q0[]u", null); } for (var a0 = 1; a0 >= 0.5; a0--) { if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 6",}, b0, false, false, "HB+_IN}6=K[*ksxKXH0`", null); } -if (compareEqual(b1.value, "010")) { +if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 7",}, b0, false, false, ";73ODiwcp8IthYURTX;S", null); } -if (compareEqual(b1.value, "0000000010")) { +if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 8",}, b0, false, true, "${[MFmBL-D*1rbas9Q89", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } @@ -41,20 +41,20 @@ b2.value = "010"; if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 9",}, b0, false, false, "#.`@SBj!g-c0:_q/tMZo", null); } -if (compareEqual(b2.value, "010")) { +if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 10",}, b0, false, false, "B`o?V6/q6g),/2w};a#y", null); } -if (compareEqual(b2.value, "0000000010")) { +if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 11",}, b0, false, false, "TJ:#TkYBys*!RYiKLXb)", null); } for (var a1 = 1; a1 >= 0.5; a1--) { if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 12",}, b0, false, false, ",Z,~10Qo~j;(+VL+I3q:", null); } -if (compareEqual(b2.value, "010")) { +if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 13",}, b0, false, false, "|Mqx([(26M%#ggW9)U0s", null); } -if (compareEqual(b2.value, "0000000010")) { +if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 14",}, b0, false, true, "YvtiKF231lU8p5Qd97RP", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } @@ -69,16 +69,16 @@ yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "XzQt! if ((0 === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "rxZqw7cv8g;PDM4B%{`?", null); } -if (compareEqual(" ", 0)) { +if ((" ".toLowerCase() === "0".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "3G|)eVw1mQm;O~cRy`}0", null); } -if (compareEqual(0, " ")) { +if (("0".toLowerCase() === " ".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "sd5xXX*tsW/~A_Q!0;^w", null); } -if (compareEqual("", 0)) { +if (("".toLowerCase() === "0".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "7**baE=].WD9OoY1+IEu", null); } -if (compareEqual(0, "")) { +if (("0".toLowerCase() === "".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "7!IB!=o/2H.Jqj-8Vwhz", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "df{tf!WhfRwXgQ?SN_dj", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot index bd4bdca8439..d986e3e81a9 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot @@ -11,14 +11,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "s", nu retire(); return; }; }) -// Sprite1 Wrun without screen refresh +// Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["F?*}X,`9XBpN_[piGRrz"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_run_without_screen_r () { -b0.value = (((daysSince2000() * 86400) || 0) + 3); +b0.value = ((daysSince2000() * 86400) + 3); runtime.ioDevices.clock.resetProjectTimer(); -while (!((runtime.ioDevices.clock.projectTimer() > 0.1) || compareGreaterThan((daysSince2000() * 86400), b0.value))) { +while (!((runtime.ioDevices.clock.projectTimer() > 0.1) || ((daysSince2000() * 86400) > b0.value))) { if (isStuck()) yield; } if (compareLessThan((daysSince2000() * 86400), b0.value)) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot index 2faaed414da..826f1e0058f 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot @@ -10,7 +10,7 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, ",a.euo_AgQTxR+D^x0M0", null); b1.value = 0; b2.value = ""; -while (!compareGreaterThan(b2.value, "")) { +while (!(b2.value.toLowerCase() > "".toLowerCase())) { startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "step" }); yield; } @@ -25,7 +25,7 @@ const b0 = stage.variables["7qur6!bGgvC9I(Nd5.HP"]; const b1 = stage.variables["sUOp@-6J4y0PqwiXit4!"]; return function* genXYZ () { b0.value = ((+b0.value || 0) + 1); -if (((b0.value || 0) === 5)) { +if ((b0.value === 5)) { b1.value = "end"; } retire(); return; From d3ed93cdfc5bdd1cf0ce85abe1d78a79a0b37f73 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:49:53 +1000 Subject: [PATCH 002/106] Make tests happy :3 --- src/compiler/compat-block-utility.js | 4 ++-- src/compiler/irgen.js | 12 +++++++----- src/compiler/iroptimizer.js | 8 ++++---- src/compiler/jsexecute.js | 6 ++++-- src/compiler/jsgen.js | 6 +++--- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/compiler/compat-block-utility.js b/src/compiler/compat-block-utility.js index b662867dc07..1afade0e27e 100644 --- a/src/compiler/compat-block-utility.js +++ b/src/compiler/compat-block-utility.js @@ -10,7 +10,7 @@ class CompatibilityLayerBlockUtility extends BlockUtility { } get stackFrame () { - return this._stackFrame; + return this.thread?.compatibilityStackFrame; } startBranch (branchNumber, isLoop) { @@ -35,9 +35,9 @@ class CompatibilityLayerBlockUtility extends BlockUtility { init (thread, fakeBlockId, stackFrame) { this.thread = thread; this.sequencer = thread.target.runtime.sequencer; - this._stackFrame = stackFrame; this._startedBranch = null; thread.stack[0] = fakeBlockId; + thread.compatibilityStackFrame = stackFrame; } } diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 91a576db301..c0e81344b27 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -1226,12 +1226,14 @@ class ScriptTreeGenerator { const blockInfo = this.getBlockInfo(block.opcode); const blockType = (blockInfo && blockInfo.info && blockInfo.info.blockType) || BlockType.COMMAND; - const substacks = []; + const substacks = {}; if (blockType === BlockType.CONDITIONAL || blockType === BlockType.LOOP) { - const branchCount = blockInfo.info.branchCount; - for (let i = 0; i < branchCount; i++) { - const inputName = i === 0 ? 'SUBSTACK' : `SUBSTACK${i + 1}`; - substacks.push(this.descendSubstack(block, inputName)); + for (const inputName in block.inputs) { + if (!inputName.startsWith('SUBSTACK')) continue; + const branchNum = inputName === 'SUBSTACK' ? 1 : +inputName.substring('SUBSTACK'.length); + if (!isNaN(branchNum)) { + substacks[branchNum] = this.descendSubstack(block, inputName); + } } } diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 4e4ce7a5f9d..de43312e1b5 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -138,14 +138,14 @@ class IROptimizer { return state.getVariableType(inputs.variable); case InputOpcode.ADDON_CALL: - + break; case InputOpcode.CAST_NUMBER: { const innerType = inputs.target.type; if (innerType & InputType.NUMBER) return innerType; return InputType.NUMBER; } case InputOpcode.CAST_NUMBER_OR_NAN: { - const innerType = inputs.target; + const innerType = inputs.target.type; if (innerType & InputType.NUMBER_OR_NAN) return innerType; return InputType.NUMBER_OR_NAN; } @@ -548,9 +548,9 @@ class IROptimizer { } case StackOpcode.COMPATIBILITY_LAYER: { this.analyzeInputs(inputs.inputs, state); - for (const substack of inputs.substacks) { + for (const substackName in inputs.substacks) { const newState = state.clone(); - modified = this.analyzeStack(substack, newState) || modified; + modified = this.analyzeStack(inputs.substacks[substackName], newState) || modified; modified = state.or(newState) || modified; } break; diff --git a/src/compiler/jsexecute.js b/src/compiler/jsexecute.js index a682f880913..e8139245512 100644 --- a/src/compiler/jsexecute.js +++ b/src/compiler/jsexecute.js @@ -123,6 +123,8 @@ const waitPromise = function*(promise) { }, error => { thread.status = 0; // STATUS_RUNNING globalState.log.warn('Promise rejected in compiled script:', error); + returnValue = '' + error; + thread.status = 0; // STATUS_RUNNING }); yield; @@ -164,7 +166,7 @@ const executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, use return returnValue; } - if (thread.status === 1 /* STATUS_PROMISE_WAIT */) { + if (thread.status === 1 /* STATUS_PROMISE_WAIT */ || thread.status === 4 /* STATUS_DONE */) { // Something external is forcing us to stop yield; // Make up a return value because whatever is forcing us to stop can't specify one @@ -191,7 +193,7 @@ const executeInCompatibilityLayer = function*(inputs, blockFunction, isWarp, use return returnValue; } - if (thread.status === 1 /* STATUS_PROMISE_WAIT */) { + if (thread.status === 1 /* STATUS_PROMISE_WAIT */ || thread.status === 4 /* STATUS_DONE */) { yield; return finish(''); } diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 9f060c59cca..31da1f0880d 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -502,9 +502,9 @@ class JSGenerator { this.source += `const ${branchVariable} = createBranchInfo(${blockType === BlockType.LOOP});\n`; this.source += `while (${branchVariable}.branch = +(${this.generateCompatibilityLayerCall(node, false, branchVariable)})) {\n`; this.source += `switch (${branchVariable}.branch) {\n`; - for (let i = 0; i < node.substacks.length; i++) { - this.source += `case ${i + 1}: {\n`; - this.descendStack(node.substacks[i], new Frame(false)); + for (const index in node.substacks) { + this.source += `case ${+index}: {\n`; + this.descendStack(node.substacks[index], new Frame(false)); this.source += `break;\n`; this.source += `}\n`; // close case } From 9d28fccb9955ebe272df0b71dffe6ebb0cbd26a5 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:50:30 +1000 Subject: [PATCH 003/106] Add operator type testing --- test/integration/tw_operator_type_matrix.js | 201 ++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 test/integration/tw_operator_type_matrix.js diff --git a/test/integration/tw_operator_type_matrix.js b/test/integration/tw_operator_type_matrix.js new file mode 100644 index 00000000000..4bb8499764a --- /dev/null +++ b/test/integration/tw_operator_type_matrix.js @@ -0,0 +1,201 @@ +const {test} = require('tap'); +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 nanolog = require('@turbowarp/nanolog'); + +const VALUES = [ + NaN, + + -Infinity, + -1e+308, + -1, + -0.5, + -1e-324, + -0, + 0, + 1e-324, + 0.5, + 1, + 1e+308, + Infinity +]; + +const createBinaryOperator = opcode => ({ + opcode, + inputNames: ['NUM1', 'NUM2'], + fields: {} +}); + +const createMathopOperator = name => ({ + opcode: 'operator_mathop', + inputNames: ['NUM'], + fields: { + OPERATOR: [ + name, + null + ] + } +}); + +const OPERATORS = [ + createBinaryOperator('operator_add'), + createBinaryOperator('operator_subtract'), + createBinaryOperator('operator_divide'), + createBinaryOperator('operator_multiply'), + createBinaryOperator('operator_mod'), + + createMathopOperator('abs'), + createMathopOperator('floor'), + createMathopOperator('ceiling'), + createMathopOperator('sqrt'), + createMathopOperator('sin'), + createMathopOperator('cos'), + createMathopOperator('tan'), + createMathopOperator('asin'), + createMathopOperator('acos'), + createMathopOperator('atan'), + createMathopOperator('ln'), + createMathopOperator('log'), + createMathopOperator('e ^'), + createMathopOperator('10 ^') +]; + +const str = number => (Object.is(number, -0) ? '-0' : number.toString()); + +test('operator type matrix', async t => { + + const vm = new VM(); + nanolog.disable(); + + let reportedValue; + + class TestExtension { + getInfo () { + return { + id: 'test', + name: 'Test', + blocks: [ + { + opcode: 'report', + blockType: BlockType.COMMAND, + text: 'report [INPUT]', + isEdgeActivated: false, + arguments: { + INPUT: { + type: ArgumentType.NUMBER, + defaultValue: 0 + } + } + } + ] + }; + } + report (args) { + reportedValue = args.INPUT; + } + } + + vm.extensionManager.addBuiltinExtension('test', TestExtension); + vm.setCompilerOptions({enabled: true}); + + vm.on('COMPILE_ERROR', () => { + t.fail('Compile error'); + }); + + const testOperator = async (operator, inputs) => { + + const inputsSB3 = {}; + for (let i = 0; i < inputs.length; i++) { + inputsSB3[operator.inputNames[i]] = [ + 1, + [ + 4, + `${inputs[i]}` + ] + ]; + } + + await vm.loadProject({ + targets: [ + { + isStage: true, + name: 'Stage', + variables: {}, + lists: {}, + costumes: [ + { + name: 'dummy', + dataFormat: 'svg', + assetId: 'cd21514d0531fdffb22204e0ec5ed84a', + md5ext: 'cd21514d0531fdffb22204e0ec5ed84a.svg' + } + ], + sounds: [], + + blocks: { + report: { + opcode: 'test_report', + inputs: { + INPUT: [ + 3, + 'operator' + ] + } + }, + operator: { + opcode: operator.opcode, + inputs: inputsSB3, + fields: operator.fields + } + } + } + ], + meta: { + semver: '3.0.0', + vm: '0.2.0', + agent: '' + } + }); + + const thread = vm.runtime._pushThread('report', vm.runtime.targets[0]); + + const irGenerator = new IRGenerator(thread); + const ir = irGenerator.generate(); + const irOptimizer = new IROptimizer(ir); + irOptimizer.optimize(); + + + while (vm.runtime.threads.length !== 0) { + vm.runtime._step(); + } + + // The ir input representing our operator + const irOperator = ir.entry.stack.blocks[0].inputs.inputs.INPUT; + + const expectedType = IntermediateInput.getNumberInputType(reportedValue); + + 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}.` + ); + }; + + for (const operator of OPERATORS) { + if (operator.inputNames.length == 2) { + for (const left of VALUES) { + for (const right of VALUES) { + await testOperator(operator, [left, right]); + } + } + } else { + for (const value of VALUES) { + await testOperator(operator, [value]); + } + } + } + + t.end(); +}); From 71b75aad51fe9a2e6810cb5b3b96f3f9a529bab9 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:50:39 +1000 Subject: [PATCH 004/106] Add type assertion checking --- test/fixtures/tw-type-assertions.sb3 | Bin 0 -> 4947 bytes test/integration/tw_type_assertions.js | 184 +++++++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 test/fixtures/tw-type-assertions.sb3 create mode 100644 test/integration/tw_type_assertions.js diff --git a/test/fixtures/tw-type-assertions.sb3 b/test/fixtures/tw-type-assertions.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..406d204a94e856ea9271bda0bad10ec6eda0c911 GIT binary patch literal 4947 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 UiH-9w6z1Qz_P4$!|JUz-0IX9sk^lez literal 0 HcmV?d00001 diff --git a/test/integration/tw_type_assertions.js b/test/integration/tw_type_assertions.js new file mode 100644 index 00000000000..4f8cc9e6f40 --- /dev/null +++ b/test/integration/tw_type_assertions.js @@ -0,0 +1,184 @@ +const fs = require('fs'); +const path = require('path'); +const {test} = require('tap'); +const VM = require('../../src/virtual-machine'); +const BlockType = require('../../src/extension-support/block-type'); +const ArgumentType = require('../../src/extension-support/argument-type'); +const IRGenerator = require('../../src/compiler/irgen'); +const {IROptimizer} = require('../../src/compiler/iroptimizer'); +const {StackOpcode, InputType, InputOpcode} = require('../../src/compiler/enums'); +const {IntermediateStack} = require('../../src/compiler/intermediate'); + +const fixture = fs.readFileSync(path.join(__dirname, '..', 'fixtures', 'tw-type-assertions.sb3')); + +test('type assertions', async t => { + const vm = new VM(); + vm.setCompilerOptions({enabled: true, warpTimer: false}); + + class TestExtension { + getInfo () { + return { + id: 'typeassert', + name: 'Type Assertions', + blocks: [ + { + opcode: 'assert', + blockType: BlockType.COMMAND, + text: 'assert [VALUE] is [ADVERB] [NOUN]', + arguments: { + VALUE: { + type: ArgumentType.STRING + }, + ADVERB: { + type: ArgumentType.STRING, + menu: 'ADVERB_MENU' + }, + NOUN: { + type: ArgumentType.STRING, + menu: 'NOUN_MENU' + } + } + }, + { + opcode: 'region', + blockType: BlockType.CONDITIONAL, + text: 'region [NAME]', + arguments: { + NAME: { + type: ArgumentType.STRING + } + } + } + ], + menus: { + ADVERB_MENU: { + acceptReporters: false, + items: ['never', 'always', 'sometimes', 'exactly'] + }, + NOUN_MENU: { + acceptReporters: false, + items: ['zero', 'infinity', 'NaN', 'a number', 'a string', 'number interpretable', 'anything'] + } + } + }; + } + assert () { } + region () { + return true; + } + } + + vm.extensionManager.addBuiltinExtension('typeassert', TestExtension); + + vm.on('COMPILE_ERROR', () => { + t.fail('Compile error'); + }); + + await vm.loadProject(fixture); + + const thread = vm.runtime.startHats('event_whenflagclicked')[0]; + + function* enumerateAssertions (blocks, region) { + for (const block of blocks) { + if (block.opcode === StackOpcode.COMPATIBILITY_LAYER) { + switch (block.inputs.opcode) { + case 'typeassert_assert': + yield {block, region}; + break; + case 'typeassert_region': + const newRegionNameInput = block.inputs.inputs.NAME; + if (newRegionNameInput.opcode !== InputOpcode.CONSTANT) { + throw new Error('Region block inputs must be a constant.'); + } + yield* enumerateAssertions(block.inputs.substacks["1"].blocks, (region ? `${region}, ` : '') + newRegionNameInput.inputs.value); + break; + } + } else { + for (const inputName in block.inputs) { + const input = block.inputs[inputName]; + if (input instanceof IntermediateStack) { + yield* enumerateAssertions(input.blocks, region); + } + } + } + } + } + + const irGenerator = new IRGenerator(thread); + const ir = irGenerator.generate(); + + runTests('run tests with yields', false); + runTests('run tests without yields', true); + + function runTests (proccode, ignoreYields) { + + const assertions = [...enumerateAssertions(ir.getProcedure(proccode).stack.blocks)]; + + for (const {block} of assertions) { + block.ignoreState = true; + } + + const irOptimizer = new IROptimizer(ir); + irOptimizer.ignoreYields = ignoreYields; + irOptimizer.optimize(); + + for (const {block, region} of assertions) { + const valueInput = block.inputs.inputs.VALUE; + const adverb = block.inputs.fields.ADVERB; + const noun = block.inputs.fields.NOUN; + + let nounType; + + switch (noun) { + case 'zero': + nounType = InputType.NUMBER_ZERO; + break; + case 'infinity': + nounType = InputType.NUMBER_POS_INF; + break; + case 'NaN': + nounType = InputType.NUMBER_NAN; + break; + case 'a number': + nounType = InputType.NUMBER; + break; + case 'a string': + nounType = InputType.STRING; + break; + case 'number interpretable': + nounType = InputType.NUMBER_INTERPRETABLE; + break; + case 'anything': + nounType = InputType.ANY; + break; + default: throw new Error(`$Invalid noun menu option ${noun}`); + } + + let message; + + if (valueInput.opcode == InputOpcode.VAR_GET) { + message = `(${region}) assert variable '${valueInput.inputs.variable.name}' (type ${valueInput.type}) is ${adverb} ${noun}`; + } else { + message = `(${region}) assert ${valueInput.opcode} (type ${valueInput.type}) is ${adverb} ${noun}`; + } + + switch (adverb) { + case 'never': + t.ok(!valueInput.isSometimesType(nounType), message); + break; + case 'always': + t.ok(valueInput.isAlwaysType(nounType), message); + break; + case 'sometimes': + t.ok(valueInput.isSometimesType(nounType), message); + break; + case 'exactly': + t.equal(valueInput.type, nounType, message); + break; + default: throw new Error(`$Invalid adverb menu option ${adverb}`); + } + } + } + + t.end(); +}); From 41e816757305c2d3546f3a37d2244a99445c8542 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:06:33 +1000 Subject: [PATCH 005/106] Fix snapshot tests falling back to "script" instead of the procedure variant --- src/compiler/intermediate.js | 6 ++++++ src/compiler/irgen.js | 1 + ...w-comparison-matrix-runtime.sb3.tw-snapshot | 4 ++-- .../tw-custom-report-repeat.sb3.tw-snapshot | 2 +- ...t-zero-seconds-in-warp-mode.sb3.tw-snapshot | 6 +++--- ...es-not-reevaluate-arguments.sb3.tw-snapshot | 4 ++-- ...ence-of-procedure-387608267.sb3.tw-snapshot | 2 +- ...re-arguments-with-same-name.sb3.tw-snapshot | 4 ++-- ...iable-input-types-430811055.sb3.tw-snapshot | 2 +- ...ocedure-return-non-existant.sb3.tw-snapshot | 4 ++-- ...-procedure-return-recursion.sb3.tw-snapshot | 10 +++++----- .../tw-procedure-return-simple.sb3.tw-snapshot | 18 +++++++++--------- ...cedure-return-stops-scripts.sb3.tw-snapshot | 2 +- .../tw-procedure-return-warp.sb3.tw-snapshot | 6 +++--- ...-procedure-argument-casting.sb3.tw-snapshot | 2 +- ...at-until-timer-greater-than.sb3.tw-snapshot | 2 +- ...w-comparison-matrix-runtime.sb3.tw-snapshot | 4 ++-- .../tw-custom-report-repeat.sb3.tw-snapshot | 2 +- ...t-zero-seconds-in-warp-mode.sb3.tw-snapshot | 6 +++--- ...es-not-reevaluate-arguments.sb3.tw-snapshot | 4 ++-- ...ence-of-procedure-387608267.sb3.tw-snapshot | 2 +- ...re-arguments-with-same-name.sb3.tw-snapshot | 4 ++-- ...iable-input-types-430811055.sb3.tw-snapshot | 2 +- ...ocedure-return-non-existant.sb3.tw-snapshot | 4 ++-- ...-procedure-return-recursion.sb3.tw-snapshot | 10 +++++----- .../tw-procedure-return-simple.sb3.tw-snapshot | 18 +++++++++--------- ...cedure-return-stops-scripts.sb3.tw-snapshot | 2 +- .../tw-procedure-return-warp.sb3.tw-snapshot | 6 +++--- ...-procedure-argument-casting.sb3.tw-snapshot | 2 +- ...at-until-timer-greater-than.sb3.tw-snapshot | 2 +- test/snapshot/lib.js | 1 + 31 files changed, 76 insertions(+), 68 deletions(-) diff --git a/src/compiler/intermediate.js b/src/compiler/intermediate.js index dc5f4ea36d4..6e47d379ccb 100644 --- a/src/compiler/intermediate.js +++ b/src/compiler/intermediate.js @@ -239,6 +239,12 @@ class IntermediateScript { */ this.isProcedure = false; + /** + * This procedure's variant, if any. + * @type {string} + */ + this.procedureVariant = ''; + /** * This procedure's code, if any. * @type {string} diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index c0e81344b27..c959c5cc3a5 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -98,6 +98,7 @@ class ScriptTreeGenerator { setProcedureVariant (procedureVariant) { const procedureCode = parseProcedureCode(procedureVariant); + this.script.procedureVariant = procedureVariant; this.script.procedureCode = procedureCode; this.script.isProcedure = true; this.script.yields = false; diff --git a/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot index 69c59c95f94..686c36b9e13 100644 --- a/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot @@ -11,7 +11,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "aZ", n retire(); return; }; }) -// Sprite1 script +// Sprite1 Wrun test (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["mfV;yS}9e:%h5UZ)QyiY"]; const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; @@ -46,7 +46,7 @@ if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} return ""; }; }) -// Sprite1 script +// Sprite1 Wsetup values (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["n^wm8jw#b24sggt.S^tD"]; return function funXYZ_setup_values () { diff --git a/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot index 1442da79f1a..060537d67aa 100644 --- a/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot @@ -19,7 +19,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Zblock name (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_block_name () { return 40; diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot index 27d2ced7847..704116bfee2 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot @@ -21,7 +21,7 @@ retire(); return; retire(); return; }; }) -// Sprite1 script +// Sprite1 Wno refresh (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); @@ -41,14 +41,14 @@ runtime.ext_scratch3_motion._moveSteps(0, target); return ""; }; }) -// Sprite1 script +// Sprite1 Wruns below with no refresh (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_runs_below_with_no_r () { yield* thread.procedures["Whas refresh"](); return ""; }; }) -// Sprite1 script +// Sprite1 Whas refresh (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); diff --git a/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot index 1fc921d2408..07442f3cde8 100644 --- a/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot @@ -11,14 +11,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Zfoo %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_foo_ (p0) { return ""; return ""; }; }) -// Sprite1 script +// Sprite1 Zno op (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_no_op () { return ""; diff --git a/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot index d6e18a37046..58b908a70ce 100644 --- a/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot @@ -11,7 +11,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Q^(MKg retire(); return; }; }) -// Player script +// Player ZSet Costume (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_Set_Costume () { diff --git a/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot index 2555707ccc2..f2456f2e254 100644 --- a/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot @@ -12,7 +12,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb retire(); return; }; }) -// Sprite1 script +// Sprite1 Znumber or text %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_number_or_text__ (p0,p1) { @@ -22,7 +22,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "HH`yR return ""; }; }) -// Sprite1 script +// Sprite1 Zboolean %b %b (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_boolean__ (p0,p1) { diff --git a/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot index 4c4667116e7..f80c51477bd 100644 --- a/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot @@ -16,7 +16,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",vD-ZG retire(); return; }; }) -// Sprite1 script +// Sprite1 Zdo something (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 funXYZ_do_something () { diff --git a/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot index 4e435ae0fdb..2aa9b207d24 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot @@ -39,14 +39,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "P", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Zinvalid params - reporter (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_invalid_params___rep () { return 0; return ""; }; }) -// Sprite1 script +// Sprite1 Zinvalid params - boolean (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_invalid_params___boo () { return 0; 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 e1176792d95..ee666ba30fc 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot @@ -30,7 +30,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "av", n retire(); return; }; }) -// Sprite1 script +// Sprite1 Znon warp recursion should yield %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_non_warp_recursion_s (p0) { if (compareGreaterThan(p0, 0)) { @@ -39,7 +39,7 @@ return (yield* yieldThenCallGenerator(thread.procedures["Znon warp recursion sho return ""; }; }) -// Sprite1 script +// Sprite1 Wwarp recursion should not yield %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_warp_recursion_shoul (p0) { if (compareGreaterThan(p0, 0)) { @@ -48,7 +48,7 @@ return thread.procedures["Wwarp recursion should not yield %s"](((+p0 || 0) - 1) return ""; }; }) -// Sprite1 script +// Sprite1 Zfib %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { @@ -59,7 +59,7 @@ return ((+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], ((+p0 || return ""; }; }) -// Sprite1 script +// Sprite1 Zrecursing yields between each %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; @@ -83,7 +83,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":("fail recursing between calls yie return ""; }; }) -// Sprite1 script +// Sprite1 Zrecursing arguments eval order %s %s %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["4HH82mPlVMOONdl(Ot*7"]; const b1 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; diff --git a/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot index c37d030d128..3b4a34ac8e8 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot @@ -27,14 +27,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "`", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Zsimplest (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_simplest () { return "It works!"; return ""; }; }) -// Sprite1 script +// Sprite1 Znesting 1 (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_1 () { thread.procedures["Znesting 2"](); @@ -42,14 +42,14 @@ return (("" + thread.procedures["Znesting 3 %s %s"](6,7)) + ("" + thread.procedu return ""; }; }) -// Sprite1 script +// Sprite1 Wwarp fib %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_warp_fib_ (p0) { return thread.procedures["Wfib %s"](p0); return ""; }; }) -// Sprite1 script +// Sprite1 Wfactorial %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_factorial_ (p0) { if (compareGreaterThan(p0, 1)) { @@ -59,7 +59,7 @@ return 1; return ""; }; }) -// Sprite1 script +// Sprite1 Zno shadowing 1 %s %s (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"]; @@ -78,21 +78,21 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass shadow check 3",}, b0, false return ""; }; }) -// Sprite1 script +// Sprite1 Znesting 2 (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_2 () { return "discard nesting 2"; return ""; }; }) -// Sprite1 script +// Sprite1 Znesting 3 %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_3__ (p0,p1) { return ((+p0 || 0) * (+p1 || 0)); return ""; }; }) -// Sprite1 script +// Sprite1 Wfib %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { @@ -103,7 +103,7 @@ return ((+thread.procedures["Wfib %s"](((+p0 || 0) - 1)) || 0) + (+thread.proced return ""; }; }) -// Sprite1 script +// Sprite1 Zno shadowing 2 %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_no_shadowing_2__ (p0,p1) { return "discard shadow 2"; diff --git a/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot index 4980c3d3459..21e08e6c87b 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot @@ -19,7 +19,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "v", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Wreturn stops the script immediately (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; const b1 = runtime.getOpcodeFunction("looks_say"); diff --git a/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot index cc9735dfe4b..fde5f016583 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot @@ -32,7 +32,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "N", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Znon warp (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); @@ -73,7 +73,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 2",}, b1, false, fa return ""; }; }) -// Sprite1 script +// Sprite1 Wverify runs warp %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); @@ -95,7 +95,7 @@ return ("warp: " + ("" + p0)); return ""; }; }) -// Sprite1 script +// Sprite1 Zverify runs non warp %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); diff --git a/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot index 033cebf8ce1..88f7ab0b015 100644 --- a/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot @@ -18,7 +18,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb retire(); return; }; }) -// Sprite1 script +// Sprite1 Zswitch %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_switch_ (p0) { runtime.ext_scratch3_looks._setCostume(target, p0); diff --git a/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot index d986e3e81a9..e5108d03f52 100644 --- a/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot @@ -11,7 +11,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "s", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Wrun without screen refresh (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["F?*}X,`9XBpN_[piGRrz"]; const b1 = runtime.getOpcodeFunction("looks_say"); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot index 40c61fa7448..f274502d07a 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot @@ -11,7 +11,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "aZ", n retire(); return; }; }) -// Sprite1 script +// Sprite1 Wrun test (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["mfV;yS}9e:%h5UZ)QyiY"]; const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; @@ -48,7 +48,7 @@ if (isStuck()) yield; return ""; }; }) -// Sprite1 script +// Sprite1 Wsetup values (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["n^wm8jw#b24sggt.S^tD"]; return function funXYZ_setup_values () { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot index 1442da79f1a..060537d67aa 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot @@ -19,7 +19,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Zblock name (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_block_name () { return 40; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot index 7a3bed7c7af..a3d93933160 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot @@ -21,7 +21,7 @@ retire(); return; retire(); return; }; }) -// Sprite1 script +// Sprite1 Wno refresh (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); @@ -42,14 +42,14 @@ if (isStuck()) yield; return ""; }; }) -// Sprite1 script +// Sprite1 Wruns below with no refresh (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_runs_below_with_no_r () { yield* thread.procedures["Whas refresh"](); return ""; }; }) -// Sprite1 script +// Sprite1 Whas refresh (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot index 1fc921d2408..07442f3cde8 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot @@ -11,14 +11,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Zfoo %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_foo_ (p0) { return ""; return ""; }; }) -// Sprite1 script +// Sprite1 Zno op (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_no_op () { return ""; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot index d6e18a37046..58b908a70ce 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot @@ -11,7 +11,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Q^(MKg retire(); return; }; }) -// Player script +// Player ZSet Costume (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_Set_Costume () { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot index 2555707ccc2..f2456f2e254 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot @@ -12,7 +12,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb retire(); return; }; }) -// Sprite1 script +// Sprite1 Znumber or text %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_number_or_text__ (p0,p1) { @@ -22,7 +22,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "HH`yR return ""; }; }) -// Sprite1 script +// Sprite1 Zboolean %b %b (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_boolean__ (p0,p1) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot index 4c4667116e7..f80c51477bd 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot @@ -16,7 +16,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",vD-ZG retire(); return; }; }) -// Sprite1 script +// Sprite1 Zdo something (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 funXYZ_do_something () { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot index 4e435ae0fdb..2aa9b207d24 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot @@ -39,14 +39,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "P", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Zinvalid params - reporter (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_invalid_params___rep () { return 0; return ""; }; }) -// Sprite1 script +// Sprite1 Zinvalid params - boolean (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_invalid_params___boo () { return 0; 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 e1176792d95..ee666ba30fc 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 @@ -30,7 +30,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "av", n retire(); return; }; }) -// Sprite1 script +// Sprite1 Znon warp recursion should yield %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_non_warp_recursion_s (p0) { if (compareGreaterThan(p0, 0)) { @@ -39,7 +39,7 @@ return (yield* yieldThenCallGenerator(thread.procedures["Znon warp recursion sho return ""; }; }) -// Sprite1 script +// Sprite1 Wwarp recursion should not yield %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_warp_recursion_shoul (p0) { if (compareGreaterThan(p0, 0)) { @@ -48,7 +48,7 @@ return thread.procedures["Wwarp recursion should not yield %s"](((+p0 || 0) - 1) return ""; }; }) -// Sprite1 script +// Sprite1 Zfib %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { @@ -59,7 +59,7 @@ return ((+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], ((+p0 || return ""; }; }) -// Sprite1 script +// Sprite1 Zrecursing yields between each %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; @@ -83,7 +83,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":("fail recursing between calls yie return ""; }; }) -// Sprite1 script +// Sprite1 Zrecursing arguments eval order %s %s %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["4HH82mPlVMOONdl(Ot*7"]; const b1 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot index c37d030d128..3b4a34ac8e8 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot @@ -27,14 +27,14 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "`", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Zsimplest (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_simplest () { return "It works!"; return ""; }; }) -// Sprite1 script +// Sprite1 Znesting 1 (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_1 () { thread.procedures["Znesting 2"](); @@ -42,14 +42,14 @@ return (("" + thread.procedures["Znesting 3 %s %s"](6,7)) + ("" + thread.procedu return ""; }; }) -// Sprite1 script +// Sprite1 Wwarp fib %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_warp_fib_ (p0) { return thread.procedures["Wfib %s"](p0); return ""; }; }) -// Sprite1 script +// Sprite1 Wfactorial %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_factorial_ (p0) { if (compareGreaterThan(p0, 1)) { @@ -59,7 +59,7 @@ return 1; return ""; }; }) -// Sprite1 script +// Sprite1 Zno shadowing 1 %s %s (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"]; @@ -78,21 +78,21 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass shadow check 3",}, b0, false return ""; }; }) -// Sprite1 script +// Sprite1 Znesting 2 (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_2 () { return "discard nesting 2"; return ""; }; }) -// Sprite1 script +// Sprite1 Znesting 3 %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_3__ (p0,p1) { return ((+p0 || 0) * (+p1 || 0)); return ""; }; }) -// Sprite1 script +// Sprite1 Wfib %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { @@ -103,7 +103,7 @@ return ((+thread.procedures["Wfib %s"](((+p0 || 0) - 1)) || 0) + (+thread.proced return ""; }; }) -// Sprite1 script +// Sprite1 Zno shadowing 2 %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_no_shadowing_2__ (p0,p1) { return "discard shadow 2"; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot index 7ea58c0cd93..6f96f52693d 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot @@ -19,7 +19,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "v", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Wreturn stops the script immediately (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; const b1 = runtime.getOpcodeFunction("looks_say"); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot index edf65b39d91..d7afc882d25 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot @@ -32,7 +32,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "N", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Znon warp (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); @@ -73,7 +73,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 2",}, b1, false, fa return ""; }; }) -// Sprite1 script +// Sprite1 Wverify runs warp %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); @@ -96,7 +96,7 @@ return ("warp: " + ("" + p0)); return ""; }; }) -// Sprite1 script +// Sprite1 Zverify runs non warp %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot index 033cebf8ce1..88f7ab0b015 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot @@ -18,7 +18,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb retire(); return; }; }) -// Sprite1 script +// Sprite1 Zswitch %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_switch_ (p0) { runtime.ext_scratch3_looks._setCostume(target, p0); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot index d986e3e81a9..e5108d03f52 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot @@ -11,7 +11,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "s", nu retire(); return; }; }) -// Sprite1 script +// Sprite1 Wrun without screen refresh (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["F?*}X,`9XBpN_[piGRrz"]; const b1 = runtime.getOpcodeFunction("looks_say"); diff --git a/test/snapshot/lib.js b/test/snapshot/lib.js index b49033ffa02..7c817a85828 100644 --- a/test/snapshot/lib.js +++ b/test/snapshot/lib.js @@ -95,6 +95,7 @@ const generateActualSnapshot = async testCase => { const generatedJS = []; JSGenerator.testingApparatus = { report: (jsgen, factorySource) => { + console.log(jsgen.script); const targetName = jsgen.target.getName(); const scriptName = jsgen.script.procedureVariant || 'script'; const js = normalizeJS(factorySource); From 02806b654ac2a7ad39f22cdf42b7ecfc40578217 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:37:37 +1000 Subject: [PATCH 006/106] Linty linty code --- src/compiler/intermediate.js | 11 +- src/compiler/irgen.js | 31 ++++-- src/compiler/iroptimizer.js | 117 +++++++++++--------- src/compiler/jsgen.js | 21 +++- test/integration/tw_operator_type_matrix.js | 5 +- test/integration/tw_type_assertions.js | 27 +++-- test/snapshot/lib.js | 1 - 7 files changed, 124 insertions(+), 89 deletions(-) diff --git a/src/compiler/intermediate.js b/src/compiler/intermediate.js index 6e47d379ccb..581ddb7e817 100644 --- a/src/compiler/intermediate.js +++ b/src/compiler/intermediate.js @@ -170,18 +170,18 @@ class IntermediateInput { break; case InputOpcode.CAST_NUMBER: case InputOpcode.CAST_NUMBER_INDEX: - case InputOpcode.CAST_NUMBER_OR_NAN: + case InputOpcode.CAST_NUMBER_OR_NAN: { if (this.isAlwaysType(InputType.BOOLEAN_INTERPRETABLE)) { this.type = InputType.NUMBER; this.inputs.value = +Cast.toBoolean(this.inputs.value); } - var numberValue = +this.inputs.value; + let numberValue = +this.inputs.value; if (numberValue) { this.inputs.value = numberValue; + } else /* numberValue is one of 0, -0, or NaN */ if (Object.is(numberValue, -0)) { + this.inputs.value = -0; } else { - // numberValue is one of 0, -0, or NaN - if (Object.is(numberValue, -0)) this.inputs.value = -0; - else this.inputs.value = 0; // Convert NaN to 0 + this.inputs.value = 0; // Convert NaN to 0 } if (castOpcode === InputOpcode.CAST_NUMBER_INDEX) { // Round numberValue to an integer @@ -189,6 +189,7 @@ class IntermediateInput { } this.type = IntermediateInput.getNumberInputType(this.inputs.value); break; + } case InputOpcode.CAST_STRING: this.inputs.value += ''; this.type = InputType.STRING; diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index c959c5cc3a5..7c75b3a32a4 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -5,14 +5,22 @@ const StringUtil = require('../util/string-util'); const BlockType = require('../extension-support/block-type'); const Variable = require('../engine/variable'); const log = require('../util/log'); -const {IntermediateStackBlock, IntermediateInput, IntermediateStack, IntermediateScript, IntermediateRepresentation} = require('./intermediate'); const compatBlocks = require('./compat-blocks'); const {StackOpcode, InputOpcode, InputType} = require('./enums.js'); +const { + IntermediateStackBlock, + IntermediateInput, + IntermediateStack, + IntermediateScript, + IntermediateRepresentation +} = require('./intermediate'); /** * @fileoverview Generate intermediate representations from Scratch blocks. */ +/* eslint-disable max-len */ + const SCALAR_TYPE = ''; const LIST_TYPE = 'list'; @@ -138,7 +146,7 @@ class ScriptTreeGenerator { } createConstantInput (constant, preserveStrings = false) { - if (constant == null) throw new Error('IR: Constant cannot have a null value.'); + if (constant === null) throw new Error('IR: Constant cannot have a null value.'); constant += ''; const numConstant = +constant; @@ -358,7 +366,7 @@ class ScriptTreeGenerator { case 'log': return new IntermediateInput(InputOpcode.OP_LOG_10, InputType.NUMBER_OR_NAN, {value}); case 'e ^': return new IntermediateInput(InputOpcode.OP_POW_E, InputType.NUMBER, {value}); case '10 ^': return new IntermediateInput(InputOpcode.OP_POW_10, InputType.NUMBER, {value}); - default: this.createConstantInput(0); + default: return this.createConstantInput(0); } } case 'operator_mod': @@ -490,7 +498,7 @@ class ScriptTreeGenerator { return new IntermediateInput(InputOpcode.SENSING_MOUSE_X, InputType.NUMBER); case 'sensing_mousey': return new IntermediateInput(InputOpcode.SENSING_MOUSE_Y, InputType.NUMBER); - case 'sensing_of': + case 'sensing_of': { const property = block.fields.PROPERTY.value; const object = this.descendInputOfBlock(block, 'OBJECT').toType(InputType.STRING); @@ -528,6 +536,7 @@ class ScriptTreeGenerator { } return new IntermediateInput(InputOpcode.SENSING_OF_VAR, InputType.ANY, {object, property}); + } case 'sensing_timer': this.usesTimer = true; return new IntermediateInput(InputOpcode.SENSING_TIMER_GET, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); @@ -1111,7 +1120,7 @@ class ScriptTreeGenerator { const variable = block.fields[fieldName]; const id = variable.id; - if (this.variableCache.hasOwnProperty(id)) { + if (Object.prototype.hasOwnProperty.call(this.variableCache, id)) { return this.variableCache[id]; } @@ -1132,20 +1141,20 @@ class ScriptTreeGenerator { const stage = this.stage; // Look for by ID in target... - if (target.variables.hasOwnProperty(id)) { + if (Object.prototype.hasOwnProperty.call(target.variables, id)) { return createVariableData('target', target.variables[id]); } // Look for by ID in stage... if (!target.isStage) { - if (stage && stage.variables.hasOwnProperty(id)) { + if (stage && Object.prototype.hasOwnProperty.call(stage.variables, id)) { return createVariableData('stage', stage.variables[id]); } } // Look for by name and type in target... for (const varId in target.variables) { - if (target.variables.hasOwnProperty(varId)) { + if (Object.prototype.hasOwnProperty.call(target.variables, varId)) { const currVar = target.variables[varId]; if (currVar.name === name && currVar.type === type) { return createVariableData('target', currVar); @@ -1156,7 +1165,7 @@ class ScriptTreeGenerator { // Look for by name and type in stage... if (!target.isStage && stage) { for (const varId in stage.variables) { - if (stage.variables.hasOwnProperty(varId)) { + if (Object.prototype.hasOwnProperty.call(stage.variables, varId)) { const currVar = stage.variables[varId]; if (currVar.name === name && currVar.type === type) { return createVariableData('stage', currVar); @@ -1174,7 +1183,7 @@ class ScriptTreeGenerator { // This is necessary because the script cache is shared between clones. // sprite.clones has all instances of this sprite including the original and all clones for (const clone of target.sprite.clones) { - if (!clone.variables.hasOwnProperty(id)) { + if (!Object.prototype.hasOwnProperty.call(clone.variables, id)) { clone.variables[id] = new Variable(id, name, type, false); } } @@ -1395,7 +1404,7 @@ class IRGenerator { addProcedureDependencies (dependencies) { for (const procedureVariant of dependencies) { - if (this.procedures.hasOwnProperty(procedureVariant)) { + if (Object.prototype.hasOwnProperty.call(this.procedures, procedureVariant)) { continue; } if (this.compilingProcedures.has(procedureVariant)) { diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index de43312e1b5..c161f3c8a4f 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -1,8 +1,18 @@ // @ts-check -const {IntermediateStack, IntermediateInput, IntermediateScript, IntermediateRepresentation, IntermediateStackBlock} = require('./intermediate'); const {StackOpcode, InputOpcode, InputType} = require('./enums.js'); +// These imports are used by jsdoc comments but eslint doesn't know that +/* eslint-disable no-unused-vars */ +const { + IntermediateStack, + IntermediateInput, + IntermediateScript, + IntermediateRepresentation, + IntermediateStackBlock +} = require('./intermediate'); +/* eslint-enable no-unused-vars */ + class TypeState { constructor () { /** @type {Object.}*/ @@ -156,41 +166,41 @@ class IROptimizer { let resultType = 0; - function canBeNaN () { + const canBeNaN = function () { // Infinity + (-Infinity) = NaN if ((leftType & InputType.NUMBER_POS_INF) && (rightType & InputType.NUMBER_NEG_INF)) return true; // (-Infinity) + Infinity = NaN if ((leftType & InputType.NUMBER_NEG_INF) && (rightType & InputType.NUMBER_POS_INF)) return true; - } + }; if (canBeNaN()) resultType |= InputType.NUMBER_NAN; - function canBeFractional () { + const canBeFractional = function () { // For the plus operation to return a non-whole number one of it's // inputs has to be a non-whole number if (leftType & InputType.NUMBER_FRACT) return true; if (rightType & InputType.NUMBER_FRACT) return true; - } + }; const canBeFract = canBeFractional(); - function canBePos () { + const canBePos = function () { if (leftType & InputType.NUMBER_POS) return true; // POS + ANY ~= POS if (rightType & InputType.NUMBER_POS) return true; // ANY + POS ~= POS - } + }; if (canBePos()) { resultType |= InputType.NUMBER_POS_INT | InputType.NUMBER_POS_INF; if (canBeFract) resultType |= InputType.NUMBER_POS_FRACT; } - function canBeNeg () { + const canBeNeg = function () { if (leftType & InputType.NUMBER_NEG) return true; // NEG + ANY ~= NEG if (rightType & InputType.NUMBER_NEG) return true; // ANY + NEG ~= NEG - } + }; if (canBeNeg()) { resultType |= InputType.NUMBER_NEG_INT | InputType.NUMBER_NEG_INF; if (canBeFract) resultType |= InputType.NUMBER_NEG_FRACT; } - function canBeZero () { + const canBeZero = function () { // POS_REAL + NEG_REAL ~= 0 if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_NEG_REAL)) return true; // NEG_REAL + POS_REAL ~= 0 @@ -201,13 +211,13 @@ class IROptimizer { if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; // -0 + 0 = 0 if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_ZERO)) return true; - } + }; if (canBeZero()) resultType |= InputType.NUMBER_ZERO; - function canBeNegZero () { + const canBeNegZero = function () { // -0 + -0 = -0 if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; - } + }; if (canBeNegZero()) resultType |= InputType.NUMBER_NEG_ZERO; return resultType; @@ -219,41 +229,41 @@ class IROptimizer { let resultType = 0; - function canBeNaN () { + const canBeNaN = function () { // Infinity - Infinity = NaN if ((leftType & InputType.NUMBER_POS_INF) && (rightType & InputType.NUMBER_POS_INF)) return true; // (-Infinity) - (-Infinity) = NaN if ((leftType & InputType.NUMBER_NEG_INF) && (rightType & InputType.NUMBER_NEG_INF)) return true; - } + }; if (canBeNaN()) resultType |= InputType.NUMBER_NAN; - function canBeFractional () { + const canBeFractional = function () { // For the subtract operation to return a non-whole number one of it's // inputs has to be a non-whole number if (leftType & InputType.NUMBER_FRACT) return true; if (rightType & InputType.NUMBER_FRACT) return true; - } + }; const canBeFract = canBeFractional(); - function canBePos () { + const canBePos = function () { if (leftType & InputType.NUMBER_POS) return true; // POS - ANY ~= POS if (rightType & InputType.NUMBER_NEG) return true; // ANY - NEG ~= POS - } + }; if (canBePos()) { resultType |= InputType.NUMBER_POS_INT | InputType.NUMBER_POS_INF; if (canBeFract) resultType |= InputType.NUMBER_POS_FRACT; } - function canBeNeg () { + const canBeNeg = function () { if (leftType & InputType.NUMBER_NEG) return true; // NEG - ANY ~= NEG if (rightType & InputType.NUMBER_POS) return true; // ANY - POS ~= NEG - } + }; if (canBeNeg()) { resultType |= InputType.NUMBER_NEG_INT | InputType.NUMBER_NEG_INF; if (canBeFract) resultType |= InputType.NUMBER_NEG_FRACT; } - function canBeZero () { + const canBeZero = function () { // POS_REAL - POS_REAL ~= 0 if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_POS_REAL)) return true; // NEG_REAL - NEG_REAL ~= 0 @@ -264,13 +274,13 @@ class IROptimizer { if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; // (-0) - (-0) = 0 if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; - } + }; if (canBeZero()) resultType |= InputType.NUMBER_ZERO; - function canBeNegZero () { + const canBeNegZero = function () { // (-0) - 0 = -0 if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_ZERO)) return true; - } + }; if (canBeNegZero()) resultType |= InputType.NUMBER_NEG_ZERO; return resultType; @@ -282,45 +292,45 @@ class IROptimizer { let resultType = 0; - function canBeNaN () { + const canBeNaN = function () { // (-)Infinity * 0 = NaN if ((leftType & InputType.NUMBER_INF) && (rightType & InputType.NUMBER_ANY_ZERO)) return true; // 0 * (-)Infinity = NaN if ((leftType & InputType.NUMBER_ANY_ZERO) && (rightType & InputType.NUMBER_INF)) return true; - } + }; if (canBeNaN()) resultType |= InputType.NUMBER_NAN; - function canBeFractional () { + const canBeFractional = function () { // For the subtract operation to return a non-whole number one of it's // inputs has to be a non-whole number if (leftType & InputType.NUMBER_FRACT) return true; if (rightType & InputType.NUMBER_FRACT) return true; - } + }; const canBeFract = canBeFractional(); - function canBePos () { + const canBePos = function () { // POS * POS = POS if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_POS)) return true; // NEG * NEG = POS if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_NEG)) return true; - } + }; if (canBePos()) { resultType |= InputType.NUMBER_POS_INT | InputType.NUMBER_POS_INF; if (canBeFract) resultType |= InputType.NUMBER_POS_FRACT; } - function canBeNeg () { + const canBeNeg = function () { // POS * NEG = NEG if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_NEG)) return true; // NEG * POS = NEG if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_POS)) return true; - } + }; if (canBeNeg()) { resultType |= InputType.NUMBER_NEG_INT | InputType.NUMBER_NEG_INF; if (canBeFract) resultType |= InputType.NUMBER_NEG_FRACT; } - function canBeZero () { + const canBeZero = function () { // 0 * 0 = 0 if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_ZERO)) return true; // -0 * -0 = 0 @@ -335,10 +345,10 @@ class IROptimizer { if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; // Rounding errors like 1e-323 * 0.1 = 0 if ((leftType & InputType.NUMBER_FRACT) && (rightType & InputType.NUMBER_FRACT)) return true; - } + }; if (canBeZero()) resultType |= InputType.NUMBER_ZERO; - function canBeNegZero () { + const canBeNegZero = function () { // 0 * -0 = 0 if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_NEG_ZERO)) return true; // -0 * 0 = 0 @@ -355,7 +365,7 @@ class IROptimizer { if ((leftType & InputType.NUMBER_NEG_REAL) && (rightType & InputType.NUMBER_POS_REAL)) return true; // Rounding errors like 1e-323 / -10 = -0 if ((leftType & InputType.NUMBER_POS_REAL) && (rightType & InputType.NUMBER_NEG_REAL)) return true; - } + }; if (canBeNegZero()) resultType |= InputType.NUMBER_NEG_ZERO; return resultType; @@ -367,25 +377,25 @@ class IROptimizer { let resultType = 0; - function canBeNaN () { + const canBeNaN = function () { // REAL / 0 = NaN if ((leftType & InputType.NUMBER_REAL) && (rightType & InputType.NUMBER_ZERO)) return true; // (-)Infinity / (-)Infinity = NaN if ((leftType & InputType.NUMBER_INF) && (rightType & InputType.NUMBER_INF)) return true; // (-)0 / NaN = NaN if ((leftType & InputType.NUMBER_ANY_ZERO) && (rightType & InputType.NUMBER_NAN)) return true; - } + }; if (canBeNaN()) resultType |= InputType.NUMBER_NAN; - function canBePos () { + const canBePos = function () { // POS / POS = POS if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_POS)) return true; // NEG / NEG = POS if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_NEG)) return true; - } + }; if (canBePos()) resultType |= InputType.NUMBER_POS; - function canBeNegInfinity () { + const canBeNegInfinity = function () { // -Infinity / 0 = -Infinity if ((leftType & InputType.NUMBER_NEG_INF) && (rightType & InputType.NUMBER_ZERO)) return true; // Infinity / -0 = -Infinity @@ -394,28 +404,28 @@ class IROptimizer { 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; - } + }; if (canBeNegInfinity()) resultType |= InputType.NUMBER_NEG_INF; - function canBeInfinity () { + 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; - } + }; if (canBeInfinity()) resultType |= InputType.NUMBER_POS_INF; - function canBeNeg () { + const canBeNeg = function () { // POS / NEG = NEG if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_NEG)) return true; // NEG / POS = NEG if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_POS)) return true; - } + }; if (canBeNeg()) resultType |= InputType.NUMBER_NEG; - function canBeZero () { + const canBeZero = function () { // 0 / POS = 0 if ((leftType & InputType.NUMBER_ZERO) && (rightType & InputType.NUMBER_POS)) return true; // -0 / NEG = 0 @@ -428,10 +438,10 @@ class IROptimizer { if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_POS_INF)) return true; // NUMBER_NEG / -Infinity = 0 if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_NEG_INF)) return true; - } + }; if (canBeZero()) resultType |= InputType.NUMBER_ZERO; - function canBeNegZero () { + const canBeNegZero = function () { // -0 / POS = -0 if ((leftType & InputType.NUMBER_NEG_ZERO) && (rightType & InputType.NUMBER_POS)) return true; // 0 / NEG = -0 @@ -444,7 +454,7 @@ class IROptimizer { if ((leftType & InputType.NUMBER_POS) && (rightType & InputType.NUMBER_NEG_INF)) return true; // NUMBER_NEG / Infinity = -0 if ((leftType & InputType.NUMBER_NEG) && (rightType & InputType.NUMBER_POS_INF)) return true; - } + }; if (canBeNegZero()) resultType |= InputType.NUMBER_NEG_ZERO; return resultType; @@ -472,7 +482,7 @@ class IROptimizer { case InputOpcode.ADDON_CALL: modified = state.clear() || modified; break; - case InputOpcode.PROCEDURE_CALL: + case InputOpcode.PROCEDURE_CALL: { modified = this.analyzeInputs(inputs.inputs, state) || modified; const script = this.ir.procedures[inputs.variant]; @@ -483,6 +493,7 @@ class IROptimizer { } break; } + } return modified; } @@ -557,8 +568,6 @@ class IROptimizer { } } - // if (stackBlock.ignoreState) return false; - return modified; } diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 31da1f0880d..152d0dafa9b 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -6,7 +6,17 @@ const VariablePool = require('./variable-pool'); const jsexecute = require('./jsexecute'); const environment = require('./environment'); const {StackOpcode, InputOpcode, InputType} = require('./enums.js'); -const {IntermediateStackBlock, IntermediateInput, IntermediateStack, IntermediateScript, IntermediateRepresentation} = require('./intermediate'); + +// These imports are used by jsdoc comments but eslint doesn't know that +/* eslint-disable no-unused-vars */ +const { + IntermediateStackBlock, + IntermediateInput, + IntermediateStack, + IntermediateScript, + IntermediateRepresentation +} = require('./intermediate'); +/* eslint-enable no-unused-vars */ /** * @fileoverview Convert intermediate representations to JavaScript functions. @@ -559,7 +569,7 @@ class JSGenerator { this.retire(); this.source += '}\n'; break; - case StackOpcode.CONTROL_FOR: + case StackOpcode.CONTROL_FOR: { const index = this.localVariables.next(); this.source += `var ${index} = 0; `; this.source += `while (${index} < ${this.descendInput(node.count)}) { `; @@ -569,6 +579,7 @@ class JSGenerator { this.yieldLoop(); this.source += '}\n'; break; + } case StackOpcode.CONTROL_IF_ELSE: this.source += `if (${this.descendInput(node.condition)}) {\n`; this.descendStack(node.whenTrue, new Frame(false)); @@ -697,7 +708,7 @@ class JSGenerator { this.source += 'target.clearEffects();\n'; break; case StackOpcode.LOOKS_EFFECT_CHANGE: - if (this.target.effects.hasOwnProperty(node.effect)) { + if (Object.prototype.hasOwnProperty.call(this.target.effects, node.effect)) { this.source += `target.setEffect("${sanitize(node.effect)}", runtime.ext_scratch3_looks.clampEffect("${sanitize(node.effect)}", ${this.descendInput(node.value)} + target.effects["${sanitize(node.effect)}"]));\n`; } break; @@ -730,7 +741,7 @@ class JSGenerator { this.source += 'target.setCostume(target.currentCostume + 1);\n'; break; case StackOpcode.LOOKS_EFFECT_SET: - if (this.target.effects.hasOwnProperty(node.effect)) { + if (Object.prototype.hasOwnProperty.call(this.target.effects, node.effect)) { this.source += `target.setEffect("${sanitize(node.effect)}", runtime.ext_scratch3_looks.clampEffect("${sanitize(node.effect)}", ${this.descendInput(node.value)}));\n`; } break; @@ -965,7 +976,7 @@ class JSGenerator { * @returns {string} */ evaluateOnce (source) { - if (this._setupVariables.hasOwnProperty(source)) { + if (Object.prototype.hasOwnProperty.call(this._setupVariables, source)) { return this._setupVariables[source]; } const variable = this._setupVariablesPool.next(); diff --git a/test/integration/tw_operator_type_matrix.js b/test/integration/tw_operator_type_matrix.js index 4bb8499764a..3cba07213c0 100644 --- a/test/integration/tw_operator_type_matrix.js +++ b/test/integration/tw_operator_type_matrix.js @@ -179,12 +179,13 @@ 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}.` + `${operator.opcode}${JSON.stringify(operator.fields)}[${inputs.map(str)}] ` + + `outputted value ${str(reportedValue)} is of the expected type ${irOperator.type}.` ); }; for (const operator of OPERATORS) { - if (operator.inputNames.length == 2) { + if (operator.inputNames.length === 2) { for (const left of VALUES) { for (const right of VALUES) { await testOperator(operator, [left, right]); diff --git a/test/integration/tw_type_assertions.js b/test/integration/tw_type_assertions.js index 4f8cc9e6f40..c2958ccf1b4 100644 --- a/test/integration/tw_type_assertions.js +++ b/test/integration/tw_type_assertions.js @@ -78,21 +78,25 @@ test('type assertions', async t => { const thread = vm.runtime.startHats('event_whenflagclicked')[0]; - function* enumerateAssertions (blocks, region) { + const enumerateAssertions = function* (blocks, region) { for (const block of blocks) { if (block.opcode === StackOpcode.COMPATIBILITY_LAYER) { switch (block.inputs.opcode) { case 'typeassert_assert': yield {block, region}; break; - case 'typeassert_region': + case 'typeassert_region': { const newRegionNameInput = block.inputs.inputs.NAME; if (newRegionNameInput.opcode !== InputOpcode.CONSTANT) { throw new Error('Region block inputs must be a constant.'); } - yield* enumerateAssertions(block.inputs.substacks["1"].blocks, (region ? `${region}, ` : '') + newRegionNameInput.inputs.value); + yield* enumerateAssertions( + block.inputs.substacks['1'].blocks, + (region ? `${region}, ` : '') + newRegionNameInput.inputs.value + ); break; } + } } else { for (const inputName in block.inputs) { const input = block.inputs[inputName]; @@ -102,15 +106,12 @@ test('type assertions', async t => { } } } - } + }; const irGenerator = new IRGenerator(thread); const ir = irGenerator.generate(); - runTests('run tests with yields', false); - runTests('run tests without yields', true); - - function runTests (proccode, ignoreYields) { + const runTests = function (proccode, ignoreYields) { const assertions = [...enumerateAssertions(ir.getProcedure(proccode).stack.blocks)]; @@ -156,8 +157,9 @@ test('type assertions', async t => { let message; - if (valueInput.opcode == InputOpcode.VAR_GET) { - message = `(${region}) assert variable '${valueInput.inputs.variable.name}' (type ${valueInput.type}) is ${adverb} ${noun}`; + if (valueInput.opcode === InputOpcode.VAR_GET) { + message = `(${region}) assert variable '${valueInput.inputs.variable.name}' ` + + `(type ${valueInput.type}) is ${adverb} ${noun}`; } else { message = `(${region}) assert ${valueInput.opcode} (type ${valueInput.type}) is ${adverb} ${noun}`; } @@ -178,7 +180,10 @@ test('type assertions', async t => { default: throw new Error(`$Invalid adverb menu option ${adverb}`); } } - } + }; + + runTests('run tests with yields', false); + runTests('run tests without yields', true); t.end(); }); diff --git a/test/snapshot/lib.js b/test/snapshot/lib.js index 7c817a85828..b49033ffa02 100644 --- a/test/snapshot/lib.js +++ b/test/snapshot/lib.js @@ -95,7 +95,6 @@ const generateActualSnapshot = async testCase => { const generatedJS = []; JSGenerator.testingApparatus = { report: (jsgen, factorySource) => { - console.log(jsgen.script); const targetName = jsgen.target.getName(); const scriptName = jsgen.script.procedureVariant || 'script'; const js = normalizeJS(factorySource); From 1dc9aadf3fab9d0970576dfe4ff46d7017fa19ab Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Tue, 25 Jun 2024 18:25:47 +1000 Subject: [PATCH 007/106] Fix issue when setting variables to InputType.ANY and add test --- src/compiler/iroptimizer.js | 18 +++++++----------- test/fixtures/tw-type-assertions.sb3 | Bin 4947 -> 5400 bytes ...procedure-return-recursion.sb3.tw-snapshot | 8 ++++---- ...procedure-return-recursion.sb3.tw-snapshot | 8 ++++---- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index c161f3c8a4f..15424a7263e 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -17,8 +17,6 @@ class TypeState { constructor () { /** @type {Object.}*/ this.variables = {}; - /** @type {InputType | 0} */ - this.defaultType = 0; } /** @@ -33,7 +31,6 @@ class TypeState { } } this.variables = {}; - this.defaultType = InputType.ANY; return modified; } @@ -46,7 +43,6 @@ class TypeState { for (const varId in this.variables) { clone.variables[varId] = this.variables[varId]; } - clone.defaultType = this.defaultType; return clone; } @@ -84,8 +80,8 @@ class TypeState { */ or (other) { return this.mutate(other, varId => { - const thisType = this.variables[varId] ?? this.defaultType; - const otherType = other.variables[varId] ?? other.defaultType; + const thisType = this.variables[varId] ?? InputType.ANY; + const otherType = other.variables[varId] ?? InputType.ANY; return thisType | otherType; }); } @@ -96,9 +92,9 @@ class TypeState { */ after (other) { return this.mutate(other, varId => { - const otherType = other.variables[varId] ?? other.defaultType; + const otherType = other.variables[varId]; if (otherType !== 0) return otherType; - return this.variables[varId] ?? this.defaultType; + return this.variables[varId] ?? InputType.ANY; }); } @@ -108,7 +104,7 @@ class TypeState { * @returns {boolean} */ setVariableType (variable, type) { - if (this.getVariableType(variable) === type) return false; + if (this.variables[variable.id] === type) return false; this.variables[variable.id] = type; return true; } @@ -119,7 +115,7 @@ class TypeState { * @returns {InputType} */ getVariableType (variable) { - return this.variables[variable.id] ?? (this.defaultType === 0 ? InputType.ANY : this.defaultType); + return this.variables[variable.id] ?? InputType.ANY; } } @@ -528,7 +524,7 @@ class IROptimizer { state = state.clone(); } - modified = modified || this.analyzeInputs(inputs, state); + modified = this.analyzeInputs(inputs, state) || modified; switch (stackBlock.opcode) { case StackOpcode.VAR_SET: diff --git a/test/fixtures/tw-type-assertions.sb3 b/test/fixtures/tw-type-assertions.sb3 index 406d204a94e856ea9271bda0bad10ec6eda0c911..29392ebe18ebd7d02e3b51aef8f8101cb342b93e 100644 GIT binary patch delta 4206 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 F004rQF>?R_ 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 ee666ba30fc..b7824ee767a 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 === 4)) { +if (((+b1.value || 0) === 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 ((b1.value === 0)) { +if (compareEqual(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 === 20)) { +if (((+b1.value || 0) === 20)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp fib yielded",}, b0, false, false, "au", null); } yield* thread.procedures["Zrecursing yields between each %s"]("initial"); @@ -68,7 +68,7 @@ return function* genXYZ_recursing_yields_bet (p0) { if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = 0; b1.value = ((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0) + (+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0)) || 0)) || 0)) || 0)) || 0)); -if ((b0.value === 3)) { +if (((+b0.value || 0) === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recursing between calls yields final",}, b2, false, false, "aK", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":"fail recursing between calls yields final",}, b2, false, false, "aL", null); 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 ee666ba30fc..b7824ee767a 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 === 4)) { +if (((+b1.value || 0) === 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 ((b1.value === 0)) { +if (compareEqual(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 === 20)) { +if (((+b1.value || 0) === 20)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp fib yielded",}, b0, false, false, "au", null); } yield* thread.procedures["Zrecursing yields between each %s"]("initial"); @@ -68,7 +68,7 @@ return function* genXYZ_recursing_yields_bet (p0) { if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = 0; b1.value = ((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0) + (+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0)) || 0)) || 0)) || 0)) || 0)); -if ((b0.value === 3)) { +if (((+b0.value || 0) === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recursing between calls yields final",}, b2, false, false, "aK", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":"fail recursing between calls yields final",}, b2, false, false, "aL", null); From 1dd7744525b4be05674b766dcdc93253abefeddd Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Wed, 3 Jul 2024 12:45:49 +1000 Subject: [PATCH 008/106] Handle colors correctly + more smartly --- src/compiler/enums.js | 8 ++++++-- src/compiler/intermediate.js | 11 +++++++++-- src/compiler/irgen.js | 6 +++--- src/compiler/jsgen.js | 15 +++++++++++++-- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/compiler/enums.js b/src/compiler/enums.js index c1a4e90fc24..9a68a186f78 100644 --- a/src/compiler/enums.js +++ b/src/compiler/enums.js @@ -84,8 +84,11 @@ const InputType = { /** Any input that can be interperated as a boolean. Equal to BOOLEAN | STRING_BOOLEAN */ BOOLEAN_INTERPRETABLE: 0x1800, - /** Any type. Equal to NUMBER_OR_NAN | STRING | BOOLEAN */ - ANY: 0x1FFF + /** Any value type (a type a scratch variable can hold). Equal to NUMBER_OR_NAN | STRING | BOOLEAN */ + ANY: 0x1FFF, + + /** An array of values in the form [R, G, B] */ + COLOR: 0x2000 }; /** @@ -195,6 +198,7 @@ const InputOpcode = { CAST_NUMBER_OR_NAN: 'cast.toNumberOrNaN', CAST_STRING: 'cast.toString', CAST_BOOLEAN: 'cast.toBoolean', + CAST_COLOR: 'cast.toColor', COMPATIBILITY_LAYER: 'compat', diff --git a/src/compiler/intermediate.js b/src/compiler/intermediate.js index 581ddb7e817..23c82cc8fe8 100644 --- a/src/compiler/intermediate.js +++ b/src/compiler/intermediate.js @@ -154,6 +154,9 @@ class IntermediateInput { case InputType.STRING: castOpcode = InputOpcode.CAST_STRING; break; + case InputType.COLOR: + castOpcode = InputOpcode.CAST_COLOR; + break; default: log.warn(`Cannot cast to type: ${targetType}`, this); throw new Error(`Cannot cast to type: ${targetType}`); @@ -175,7 +178,7 @@ class IntermediateInput { this.type = InputType.NUMBER; this.inputs.value = +Cast.toBoolean(this.inputs.value); } - let numberValue = +this.inputs.value; + const numberValue = +this.inputs.value; if (numberValue) { this.inputs.value = numberValue; } else /* numberValue is one of 0, -0, or NaN */ if (Object.is(numberValue, -0)) { @@ -185,7 +188,7 @@ class IntermediateInput { } if (castOpcode === InputOpcode.CAST_NUMBER_INDEX) { // Round numberValue to an integer - numberValue |= 0; + this.inputs.value |= 0; } this.type = IntermediateInput.getNumberInputType(this.inputs.value); break; @@ -194,6 +197,10 @@ class IntermediateInput { this.inputs.value += ''; this.type = InputType.STRING; break; + case InputOpcode.CAST_COLOR: + this.inputs.value = Cast.toRgbColorList(this.inputs.value); + this.type = InputType.COLOR; + break; } return this; } diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 7c75b3a32a4..47a0e070d4e 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -468,8 +468,8 @@ class ScriptTreeGenerator { case 'sensing_coloristouchingcolor': return new IntermediateInput(InputOpcode.SENSING_COLOR_TOUCHING_COLOR, InputType.BOOLEAN, { - target: this.descendInputOfBlock(block, 'COLOR2'), - mask: this.descendInputOfBlock(block, 'COLOR') + target: this.descendInputOfBlock(block, 'COLOR2').toType(InputType.COLOR), + mask: this.descendInputOfBlock(block, 'COLOR').toType(InputType.COLOR) }); case 'sensing_current': switch (block.fields.CURRENTMENU.value.toLowerCase()) { @@ -542,7 +542,7 @@ class ScriptTreeGenerator { return new IntermediateInput(InputOpcode.SENSING_TIMER_GET, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); case 'sensing_touchingcolor': return new IntermediateInput(InputOpcode.SENSING_TOUCHING_COLOR, InputType.BOOLEAN, { - color: this.descendInputOfBlock(block, 'COLOR').toType(InputType.NUMBER) + color: this.descendInputOfBlock(block, 'COLOR').toType(InputType.COLOR) }); case 'sensing_touchingobject': return new IntermediateInput(InputOpcode.SENSING_TOUCHING_OBJECT, InputType.BOOLEAN, { diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 152d0dafa9b..2f3c88e7327 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -193,6 +193,8 @@ class JSGenerator { return `(${this.descendInput(node.target.toType(InputType.NUMBER_OR_NAN))} | 0)`; case InputOpcode.CAST_STRING: return `("" + ${this.descendInput(node.target)})`; + case InputOpcode.CAST_COLOR: + return `colorToList(${this.descendInput(node.target)})`; case InputOpcode.COMPATIBILITY_LAYER: // Compatibility layer inputs never use flags. @@ -206,6 +208,15 @@ class JSGenerator { } else if (block.isAlwaysType(InputType.BOOLEAN)) { if (typeof node.value !== 'boolean') throw new Error(`JS: '${block.type}' type constant had ${typeof node.value} type value. Expected boolean.`); return node.value.toString(); + } else if (block.isAlwaysType(InputType.COLOR)) { + if (!Array.isArray(node.value)) throw new Error(`JS: '${block.type}' type constant was not an array.`); + if (node.value.length !== 3) throw new Error(`JS: '${block.type}' type constant had an array of length '${node.value.length}'. Expected 3.`); + for (let i = 0; i < 3; i++) { + if (typeof node.value[i] !== 'number') { + throw new Error(`JS: '${block.type}' type constant element ${i} had a value of type '${node.value[i]}'. Expected number.`); + } + } + return `[${node.value[0]},${node.value[1]},${node.value[2]}]`; } else if (block.isSometimesType(InputType.STRING)) { return `"${sanitize(node.value.toString())}"`; } throw new Error(`JS: Unknown constant input type '${block.type}'.`); @@ -412,7 +423,7 @@ class JSGenerator { case InputOpcode.SENSING_ANSWER: return `runtime.ext_scratch3_sensing._answer`; case InputOpcode.SENSING_COLOR_TOUCHING_COLOR: - return `target.colorIsTouchingColor(colorToList(${this.descendInput(node.target)}), colorToList(${this.descendInput(node.mask)}))`; + return `target.colorIsTouchingColor(${this.descendInput(node.target)}, ${this.descendInput(node.mask)})`; case InputOpcode.SENSING_TIME_DATE: return `(new Date().getDate())`; case InputOpcode.SENSING_TIME_WEEKDAY: @@ -464,7 +475,7 @@ class JSGenerator { case InputOpcode.SENSING_TOUCHING_OBJECT: return `target.isTouchingObject(${this.descendInput(node.object)})`; case InputOpcode.SENSING_TOUCHING_COLOR: - return `target.isTouchingColor(colorToList(${this.descendInput(node.color)}))`; + return `target.isTouchingColor(${this.descendInput(node.color)})`; case InputOpcode.SENSING_USERNAME: return 'runtime.ioDevices.userData.getUsername()'; case InputOpcode.SENSING_TIME_YEAR: From 177b8991389726a51cd5c12fa1d3775cbcdfad60 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Wed, 3 Jul 2024 12:58:07 +1000 Subject: [PATCH 009/106] Fix issue when switching to costume with a number name --- src/compiler/irgen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 47a0e070d4e..bfbcb613f26 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -582,7 +582,7 @@ class ScriptTreeGenerator { const inputs = Object.keys(block.inputs); const fields = Object.keys(block.fields); if (inputs.length === 0 && fields.length === 1) { - return this.createConstantInput(block.fields[fields[0]].value); + return this.createConstantInput(block.fields[fields[0]].value, preserveStrings); } log.warn(`IR: Unknown input: ${block.opcode}`, block); From a589e57d9edc6008bd9b140034c74d53fafb177c Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 28 Jul 2024 20:14:05 +1000 Subject: [PATCH 010/106] Fix old and add new unsupported APIs. --- src/compiler/irgen.js | 5 ++++- src/virtual-machine.js | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index bfbcb613f26..63c22d018ab 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -1494,4 +1494,7 @@ class IRGenerator { } } -module.exports = IRGenerator; +module.exports = { + ScriptTreeGenerator, + IRGenerator +}; diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 09e9593353d..2dcc9b6612c 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -228,6 +228,11 @@ class VirtualMachine extends EventEmitter { JSGenerator: require('./compiler/jsgen.js'), IRGenerator: require('./compiler/irgen.js').IRGenerator, ScriptTreeGenerator: require('./compiler/irgen.js').ScriptTreeGenerator, + IntermediateStackBlock: require("./compiler/intermediate.js").IntermediateStackBlock, + IntermediateInput: require("./compiler/intermediate.js").IntermediateInput, + IntermediateStack: require("./compiler/intermediate.js").IntermediateStack, + IntermediateScript: require("./compiler/intermediate.js").IntermediateScript, + IntermediateRepresentation: require("./compiler/intermediate.js").IntermediateRepresentation, Thread: require('./engine/thread.js'), execute: require('./engine/execute.js') }); From 34491603f88bfc5c29aa31a9e9c47c28254e9d30 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 28 Jul 2024 20:22:30 +1000 Subject: [PATCH 011/106] Linty linty code --- src/virtual-machine.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 2dcc9b6612c..4ed5ebf09fc 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -228,11 +228,11 @@ class VirtualMachine extends EventEmitter { JSGenerator: require('./compiler/jsgen.js'), IRGenerator: require('./compiler/irgen.js').IRGenerator, ScriptTreeGenerator: require('./compiler/irgen.js').ScriptTreeGenerator, - IntermediateStackBlock: require("./compiler/intermediate.js").IntermediateStackBlock, - IntermediateInput: require("./compiler/intermediate.js").IntermediateInput, - IntermediateStack: require("./compiler/intermediate.js").IntermediateStack, - IntermediateScript: require("./compiler/intermediate.js").IntermediateScript, - IntermediateRepresentation: require("./compiler/intermediate.js").IntermediateRepresentation, + IntermediateStackBlock: require('./compiler/intermediate.js').IntermediateStackBlock, + IntermediateInput: require('./compiler/intermediate.js').IntermediateInput, + IntermediateStack: require('./compiler/intermediate.js').IntermediateStack, + IntermediateScript: require('./compiler/intermediate.js').IntermediateScript, + IntermediateRepresentation: require('./compiler/intermediate.js').IntermediateRepresentation, Thread: require('./engine/thread.js'), execute: require('./engine/execute.js') }); From 59cc74c10b932352e04224ac5f6d7048ed89483c Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 28 Jul 2024 20:31:07 +1000 Subject: [PATCH 012/106] Fix imports :c --- src/compiler/compile.js | 2 +- test/integration/tw_operator_type_matrix.js | 2 +- test/integration/tw_type_assertions.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/compile.js b/src/compiler/compile.js index 4a5c5029636..3b5125f5efe 100644 --- a/src/compiler/compile.js +++ b/src/compiler/compile.js @@ -1,6 +1,6 @@ // @ts-check -const IRGenerator = require('./irgen'); +const {IRGenerator} = require('./irgen'); const {IROptimizer} = require('./iroptimizer'); const JSGenerator = require('./jsgen'); diff --git a/test/integration/tw_operator_type_matrix.js b/test/integration/tw_operator_type_matrix.js index 3cba07213c0..2402067302c 100644 --- a/test/integration/tw_operator_type_matrix.js +++ b/test/integration/tw_operator_type_matrix.js @@ -1,7 +1,7 @@ const {test} = require('tap'); const VM = require('../../src/virtual-machine'); const {BlockType, ArgumentType} = require('../../src/extension-support/tw-extension-api-common'); -const IRGenerator = require('../../src/compiler/irgen'); +const {IRGenerator} = require('../../src/compiler/irgen'); const {IROptimizer} = require('../../src/compiler/iroptimizer'); const {IntermediateInput} = require('../../src/compiler/intermediate'); const nanolog = require('@turbowarp/nanolog'); diff --git a/test/integration/tw_type_assertions.js b/test/integration/tw_type_assertions.js index c2958ccf1b4..745ffac7014 100644 --- a/test/integration/tw_type_assertions.js +++ b/test/integration/tw_type_assertions.js @@ -4,7 +4,7 @@ const {test} = require('tap'); const VM = require('../../src/virtual-machine'); const BlockType = require('../../src/extension-support/block-type'); const ArgumentType = require('../../src/extension-support/argument-type'); -const IRGenerator = require('../../src/compiler/irgen'); +const {IRGenerator} = require('../../src/compiler/irgen'); const {IROptimizer} = require('../../src/compiler/iroptimizer'); const {StackOpcode, InputType, InputOpcode} = require('../../src/compiler/enums'); const {IntermediateStack} = require('../../src/compiler/intermediate'); From 430353b1e36c62a867415d46e3470c54b3920e20 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 28 Jul 2024 20:36:24 +1000 Subject: [PATCH 013/106] Re-add JSGenerator.unstable_exports and expose enums as unsupported APIs --- src/compiler/jsgen.js | 12 ++++++++++++ src/virtual-machine.js | 3 +++ 2 files changed, 15 insertions(+) diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 2f3c88e7327..03cd375bdf1 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -1179,6 +1179,18 @@ class JSGenerator { } } +// For extensions. +JSGenerator.unstable_exports = { + factoryNameVariablePool, + functionNameVariablePool, + generatorNameVariablePool, + VariablePool, + PEN_EXT, + PEN_STATE, + Frame, + sanitize +}; + // Test hook used by automated snapshot testing. JSGenerator.testingApparatus = null; diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 4ed5ebf09fc..419bf3bd855 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -233,6 +233,9 @@ class VirtualMachine extends EventEmitter { IntermediateStack: require('./compiler/intermediate.js').IntermediateStack, IntermediateScript: require('./compiler/intermediate.js').IntermediateScript, IntermediateRepresentation: require('./compiler/intermediate.js').IntermediateRepresentation, + StackOpcode: require('./compiler/enums.js').StackOpcode, + InputOpcode: require('./compiler/enums.js').InputOpcode, + InputType: require('./compiler/enums.js').InputType, Thread: require('./engine/thread.js'), execute: require('./engine/execute.js') }); From 56825e3744e40d51efc01d5b2ae82a7a8d748acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=86=8A=E8=B0=B7=20=E5=87=8C?= Date: Thu, 26 Dec 2024 12:56:30 +0800 Subject: [PATCH 014/106] Allow `refreshBlocks()` to specify extension (#228) --- src/extension-support/extension-manager.js | 28 +++++++++++++--------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/extension-support/extension-manager.js b/src/extension-support/extension-manager.js index a092af35482..5268ad938e8 100644 --- a/src/extension-support/extension-manager.js +++ b/src/extension-support/extension-manager.js @@ -277,19 +277,25 @@ class ExtensionManager { /** * Regenerate blockinfo for any loaded extensions + * @param {string} [optExtensionId] Optional extension ID for refreshing * @returns {Promise} resolved once all the extensions have been reinitialized */ - refreshBlocks () { - const allPromises = Array.from(this._loadedExtensions.values()).map(serviceName => - dispatch.call(serviceName, 'getInfo') - .then(info => { - info = this._prepareExtensionInfo(serviceName, info); - dispatch.call('runtime', '_refreshExtensionPrimitives', info); - }) - .catch(e => { - log.error('Failed to refresh built-in extension primitives', e); - }) - ); + refreshBlocks (optExtensionId) { + const refresh = serviceName => dispatch.call(serviceName, 'getInfo') + .then(info => { + info = this._prepareExtensionInfo(serviceName, info); + dispatch.call('runtime', '_refreshExtensionPrimitives', info); + }) + .catch(e => { + log.error('Failed to refresh built-in extension primitives', e); + }); + if (optExtensionId) { + if (!this._loadedExtensions.has(optExtensionId)) { + return Promise.reject(new Error(`Unknown extension: ${optExtensionId}`)); + } + return refresh(this._loadedExtensions.get(optExtensionId)); + } + const allPromises = Array.from(this._loadedExtensions.values()).map(refresh); return Promise.all(allPromises); } From 36c02f3fece80d78c0895f59af45061898411775 Mon Sep 17 00:00:00 2001 From: Miyo Sho <135030944+yuri-kiss@users.noreply.github.com> Date: Fri, 27 Dec 2024 17:45:09 -0500 Subject: [PATCH 015/106] Expose `Variable` on the VM exports (#237) --- src/virtual-machine.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 63872094c2c..e02d87222a2 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -221,6 +221,7 @@ class VirtualMachine extends EventEmitter { Sprite, RenderedTarget, JSZip, + Variable, i_will_not_ask_for_help_when_these_break: () => { console.warn('You are using unsupported APIs. WHEN your code breaks, do not expect help.'); From 2c9d301da2e9746afbb04e9a4e7e4e5a15878792 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Fri, 17 Jan 2025 23:16:30 -0600 Subject: [PATCH 016/106] ir: Fix variable cache collision when variable or list field has null ID Fixes https://github.com/TurboWarp/scratch-vm/issues/239 --- src/compiler/irgen.js | 8 ++-- .../tw-block-with-null-for-variable-id.sb3 | Bin 0 -> 3610 bytes ...-with-null-for-variable-id.sb3.tw-snapshot | 39 ++++++++++++++++++ ...-with-null-for-variable-id.sb3.tw-snapshot | 39 ++++++++++++++++++ 4 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/execute/tw-block-with-null-for-variable-id.sb3 create mode 100644 test/snapshot/__snapshots__/tw-block-with-null-for-variable-id.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-block-with-null-for-variable-id.sb3.tw-snapshot diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index b1b8ded5e38..ca3d7f310b1 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 0000000000000000000000000000000000000000..68b151ee32dce6812521f664a61035fd7e26c307 GIT binary patch literal 3610 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 K&l0SEs(%2^bad(f literal 0 HcmV?d00001 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 00000000000..17631a6dc0a --- /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 00000000000..17631a6dc0a --- /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; +}; }) From af3b7513a4c10d658910d32a792b480d7e8b17ae Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 18 Jan 2025 00:29:09 -0600 Subject: [PATCH 017/106] ir: Match vanilla quirks when handling variable or list fields with null ID --- src/compiler/irgen.js | 59 +++++++++++++----- ...atic-variable-creation-literal-null-id.sb3 | Bin 0 -> 2718 bytes .../tw_automatic_variable_creation.js | 43 +++++++++++++ ...e-creation-literal-null-id.sb3.tw-snapshot | 13 ++++ ...e-creation-literal-null-id.sb3.tw-snapshot | 13 ++++ 5 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 test/fixtures/execute/tw-automatic-variable-creation-literal-null-id.sb3 create mode 100644 test/integration/tw_automatic_variable_creation.js create mode 100644 test/snapshot/__snapshots__/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index ca3d7f310b1..0ef1a696e88 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -19,17 +19,12 @@ const LIST_TYPE = 'list'; */ /** - * Create a variable codegen object. - * @param {'target'|'stage'} scope The scope of this variable -- which object owns it. - * @param {import('../engine/variable.js')} varObj The Scratch Variable - * @returns {*} A variable codegen object. + * @typedef DescendedVariable + * @property {'target'|'stage'} scope + * @property {string} id + * @property {string} name + * @property {boolean} isCloud */ -const createVariableData = (scope, varObj) => ({ - scope, - id: varObj.id, - name: varObj.name, - isCloud: varObj.isCloud -}); /** * @param {string} code @@ -1245,7 +1240,7 @@ class ScriptTreeGenerator { * @param {string} name The name of the variable. * @param {''|'list'} type The variable type. * @private - * @returns {*} A parsed variable object. + * @returns {DescendedVariable} A parsed variable object. */ _descendVariable (id, name, type) { const target = this.target; @@ -1253,13 +1248,25 @@ class ScriptTreeGenerator { // Look for by ID in target... if (Object.prototype.hasOwnProperty.call(target.variables, id)) { - return createVariableData('target', target.variables[id]); + const currVar = target.variables[id]; + return { + scope: 'target', + id: currVar.id, + name: currVar.name, + isCloud: currVar.isCloud + }; } // Look for by ID in stage... if (!target.isStage) { if (stage && Object.prototype.hasOwnProperty.call(stage.variables, id)) { - return createVariableData('stage', stage.variables[id]); + const currVar = stage.variables[id]; + return { + scope: 'stage', + id: currVar.id, + name: currVar.name, + isCloud: currVar.isCloud + }; } } @@ -1268,7 +1275,12 @@ class ScriptTreeGenerator { if (Object.prototype.hasOwnProperty.call(target.variables, varId)) { const currVar = target.variables[varId]; if (currVar.name === name && currVar.type === type) { - return createVariableData('target', currVar); + return { + scope: 'target', + id: currVar.id, + name: currVar.name, + isCloud: currVar.isCloud + }; } } } @@ -1279,7 +1291,12 @@ class ScriptTreeGenerator { if (Object.prototype.hasOwnProperty.call(stage.variables, varId)) { const currVar = stage.variables[varId]; if (currVar.name === name && currVar.type === type) { - return createVariableData('stage', currVar); + return { + scope: 'stage', + id: currVar.id, + name: currVar.name, + isCloud: currVar.isCloud + }; } } } @@ -1287,6 +1304,9 @@ class ScriptTreeGenerator { // Create it locally... const newVariable = new Variable(id, name, type, false); + + // Intentionally not using newVariable.id so that this matches vanilla Scratch quirks regarding + // handling of null variable IDs. target.variables[id] = newVariable; if (target.sprite) { @@ -1300,7 +1320,14 @@ class ScriptTreeGenerator { } } - return createVariableData('target', newVariable); + return { + scope: 'target', + // If the given ID was null, this won't match the .id property of the Variable object. + // This is intentional to match vanilla Scratch quirks. + id, + name: newVariable.name, + isCloud: newVariable.isCloud + }; } descendProcedure (block) { diff --git a/test/fixtures/execute/tw-automatic-variable-creation-literal-null-id.sb3 b/test/fixtures/execute/tw-automatic-variable-creation-literal-null-id.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..57a7c005e21a554d98f1b3ef1093efc494b7f4f9 GIT binary patch literal 2718 zcma)8XHXN^77if^y$GSL5_(q%ArP{WUIU1LfPkSGs&oW_&_W04gep}abc7&X6hTE~ zk+QOMP*|EPB48+jl!v=N-g`T!2F+kSc-^Y95rmfE`92&mWq)sStQ^meRS>C%LR)wwn{?6PY zZ8Mf$BF!@)*W&m9O#{SwKD4=MvB&vjeY$y6rRSS!G0O@Z3@OiNU3~7Qw#Jz-y~Bip7B9)$SQS%I+91$3ZEJ|O&U&)89;nFCFIAdbyM5JK z7NIhbWO_-j-K$VmNq!g3hbt!{u{rCiVjvr7%jRl4P$WDm_W5;zX>R&1hX zDjIDvyVH(~a?y4DTf$5RlYA|2y+`P+@cTJJZ=noa$}%-6=}&rvb@JaMGN?fP>%Ent z1Ow7;YYnFnwXr4cw{N+|OessAz^`PSea2H!vd|ZTNoWOLy>s7y>oQlTN8MRiZ3sc( zAp)n>8VQ{U?Pq#${5^qh#1Y7$Z>Bt;@7fsVX!0mw<5gm6$xp@wJe6PJEF#A88gzVN z5cY7B>M|h)8>5w-#K)(K4SEdU(;y9(T?m0^#=D2Q0ZH=~8eMsn_zkc|`khDDbSv6a z`7yOQ!NZ5DC1KrW+@mMAYoAm26C|dX+>%T@Wslt>5#je{$76g(~f0a@a&mK8cp&JtUqGAFG+)q92@3C*J8sAy(z&jLG zOto)sU_ejFTDvnJ_&_}ZF;LJ7Ewz|H<{~Jhe;>we&Z!#cK$0%LUB$G8fNv7_`X|)6~#OS97Q9-`;r=!B40lt((j6&2)NoLpS+2m}I- zbcQ=SDmptUBX7(42fBJ)Gh~esgwBU1O?A+{YDB&$$6g=fY&D2A@9(W2o13!9yXGSQ zz~|x=jU{I}wMBDKO!KaabsSf;qBo^=eBwdCj5?eo1&!|ieLaBiRmv=Xaveh357r-6rE9cG};BFEU$o4P;^8pBOR5{2*eLk zk1XfB=XBXmxT3*H+=5dWOiN3*cXonmhdNQC%jMUMVN((uRVHN^+?`209 z70;nv-vm`(pBk>-2|oWT^|_bYhL<dzxvg$ zV}W=qp(kC5`>ooGN?9;M)msi?2eET&F7tLDjNa%BR+^Nz4p(n}+omr0O&pB`xsHCB zSvu+7aQV6Mpt}C$PT<7k&_c*h#E&s@vf52$8&VHL(xQkBr-gg1U$!QLmYX|hC+`E116HgY4bxaV0gT38T(5AH10{(Ib4zyBuz=Ig=ibpc4&iqd~<XYf13Yp zW>=iPDV`1a6(tD5lF6@Zw;9IqG!wny@Ha=;a!^T>Z*&R9?`>QcNeOR9lS?M|1+z># z|1l;BND0*KrH`k9k@t+)E!+7NkV;m|ncyr7o~sE?2_})(0gNC)pD@-m_0Si!1<|0f zL~Ytw%DZw=K`642(P*lu^MZ&vP?NbPTR2VBf*zLg=Kj^}KNxcw6hy*O9JGZKrLd$UJ#}{*34h39GDn>gd^VeX zd_|v+$|5DmRp^2Tl6#pXr^|a!FT5P!wuMA<&5JtlyHuFzu^UYeYDdDpGH2xGd&!sq z#{K9Wp@jzAEaI*hennPww7C~y&ew>=&RCzL?E8A- zCYZc~K1)9r3Qa-9%ROfPIW?6dky#08>Z$B6jtN3mg-TovH~dRjVlpKLOf*_ppnZ#V zY++XUsQ1zckGFZBt^l6|ttYz>%5zy6RCtmKU zq&9UcPb<#D-2k<-p49m>hQ7lHpyQ~&`0|3(r_48f2eDBAP;{=C*P{OJAzAz7yO literal 0 HcmV?d00001 diff --git a/test/integration/tw_automatic_variable_creation.js b/test/integration/tw_automatic_variable_creation.js new file mode 100644 index 00000000000..e77d575ad53 --- /dev/null +++ b/test/integration/tw_automatic_variable_creation.js @@ -0,0 +1,43 @@ +const fs = require('fs'); +const path = require('path'); +const {test} = require('tap'); +const VM = require('../../src/virtual-machine'); + +for (const compilerEnabled of [false, true]) { + const prefix = compilerEnabled ? 'compiler' : 'interpreter'; + test(`${prefix} - quirks when block field has literal null for variable ID`, t => { + const vm = new VM(); + vm.setCompilerOptions({ + enabled: compilerEnabled + }); + t.equal(vm.runtime.compilerOptions.enabled, compilerEnabled, 'compiler options sanity check'); + + // The execute tests ensure that this fixture compiles and runs fine and the snapshot test ensures + // it compiles correctly. This additional test will ensure that the internal variable objects are + // being created with the expected properties. + const fixturePath = path.join( + __dirname, + '../fixtures/execute/tw-automatic-variable-creation-literal-null-id.sb3' + ); + + vm.loadProject(fs.readFileSync(fixturePath)).then(() => { + vm.greenFlag(); + vm.runtime._step(); + + // Variable does not exist, should get made as local variable in sprite + const variables = vm.runtime.targets[1].variables; + t.equal(Object.keys(variables).length, 1, 'created 1 new variable'); + + // Scratch quirk - the entry in .variables should have key "null" + const newVariableKey = Object.keys(variables)[0]; + t.equal(newVariableKey, 'null', 'key is "null"'); + + // Scratch quirk - the actual variable.id should be the random string + const newVariable = Object.values(variables)[0]; + t.notEqual(newVariable.id, 'null', 'variable.id is not "null"'); + t.type(newVariable.id, 'string', 'variable.id is a string'); + + t.end(); + }); + }); +} diff --git a/test/snapshot/__snapshots__/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot new file mode 100644 index 00000000000..ac6f722391f --- /dev/null +++ b/test/snapshot/__snapshots__/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot @@ -0,0 +1,13 @@ +// TW Snapshot +// Input SHA-256: 4764ae15e39b22b1a071c9ac79f8758f24ef41855802db8674e200fd26139ed0 + +// 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 = target.variables["null"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a", null); +b1.value = 5; +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "d", null); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot new file mode 100644 index 00000000000..ac6f722391f --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot @@ -0,0 +1,13 @@ +// TW Snapshot +// Input SHA-256: 4764ae15e39b22b1a071c9ac79f8758f24ef41855802db8674e200fd26139ed0 + +// 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 = target.variables["null"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a", null); +b1.value = 5; +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "d", null); +retire(); return; +}; }) From cd63c87f07ee344a7fa5ca62bcc42da9e81aadfb Mon Sep 17 00:00:00 2001 From: Muffin Date: Tue, 11 Feb 2025 00:49:36 -0600 Subject: [PATCH 018/106] js: reset variable types after compatibility layer call Fixes https://github.com/TurboWarp/scratch-vm/issues/245 --- src/compiler/jsgen.js | 2 ++ .../tw-compatibility-layer-type-barrier.sb3 | Bin 0 -> 2890 bytes ...ibility-layer-type-barrier.sb3.tw-snapshot | 34 ++++++++++++++++++ ...ibility-layer-type-barrier.sb3.tw-snapshot | 34 ++++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 test/fixtures/execute/tw-compatibility-layer-type-barrier.sb3 create mode 100644 test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 914e5cc72b1..10387a797a7 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -1342,6 +1342,8 @@ class JSGenerator { const opcodeFunction = this.evaluateOnce(`runtime.getOpcodeFunction("${sanitize(opcode)}")`); result += `}, ${opcodeFunction}, ${this.isWarp}, ${setFlags}, "${sanitize(node.id)}", ${frameName})`; + this.yielded(); + return result; } diff --git a/test/fixtures/execute/tw-compatibility-layer-type-barrier.sb3 b/test/fixtures/execute/tw-compatibility-layer-type-barrier.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..635f80d5d92fccbd4c860a95ad46d3021b0c81da GIT binary patch literal 2890 zcma);XHXN^9>oJBNa&K#q)JUdF@#V85_$r46T}C zE7eEXY((;!Q!orrT;xo4Oo*1p`8?WON-2C`O!3NT;9FLQ3jH}`odLS4gXYO1I(T=c z31q_eWbLMs%@Y?rB?96Kyu4Ws!E@KADbv8B!N*7@ftg-!8J~*^gfm1r2jSO0Q#HF9 z?0l3OyA)<80RA?N6U!4xyOVqJ%k~eO!hrfAsV5V~UU3Y*d2|L6;Sz%F$(OXvxTui3 zAiAZAaFB^vukFZrtDJID>Ee(hSx>G6JR|(a(fLYciTR8;sz_ds5!?%hs7IdCG|BFZ z8*Va%);VEsQJi4I5)b3^mReC;mmY<+rhlyQ!PR12@E^~W$70jwjhasHjkkviG0Xa} zFcm^LqEy}$59YuM@BfL}p&bOPzifa9A>doaH{!sg$?mF<2m`^4QC9!#RUorhPA+D^ zQ$SfX{tS3A!`l@sQtKHe(uvX|eV$r=rtQUWWQnA-@qF#$W`DKoU?uD1YgNTfAHEap zxsMP{+|%)jdy>#Cx_-!?{Mwpv^#pLJyd&WrT<%kV#u9fDJ)Q?wzR>+FF}(*VmlO%8 zE8MBAbm<@zoMf9Aa_^3%6i&UlOD-1<&lz!sx$cwsK6q*f`K;xfUEz$`xb#eEufpEr zf&HRp=3(#&<6ae64Kild(C31OW!i$4jHC9{&TCq51HbTBI{hXm|Ce#Ib%mXx))ETN z>tKJsy-o(R%MALVWSx)q`__ft{MgDT{|-0v9FCY^LN&IuHdpb-DL(aspVEFIlK3Oq zS@BYom9gOt)$mBEW419Nc!$2$M!IQdCsOv?gC*H3TWPHWu>lIEdv+_z1HHmRT`WRx zK27Lmi-qtB4Juhx+b(Vs>nwu>^@?orK3oD@Ci~uh#45Hl8s1{A=}2#Ioa74ESq{Us z(1Q$K2XrO*(FdGXQ@$;R)zwcdYeuxJga*;5^s4sKfPmIa+Vy6!p&NPiBaAPD?-KJ$ z=%}2Gr;Nwjxy1R=QTVRM0R#)=QoJ0l&99MEnbeGPOT0$OoJ>Ht3gSIEO^dOinH{U; z41hc;ea3On*0&^`c&m5VIhj-2G5}VlFI1u79(-L{v~}rrkC5 z<&D$XR;nd8CR$$DhRuUGLGBZ-9ioPwUO7CcumEwSzV zYOc`7YJ{$$y+id#f22giKlM%>U4ZfJG8_NYc=hkUqQBYcjmZCv}laI|GBaKsz8S{)gcE@bxA z8_K8LuIFHyhkQJTlE2HsC$=&{C$MHttNKc^o65`~T(-ZV$9?v;9L6Xx~75ouy@`8=at zg-FU?iKvF^K^i1tk>Wf_IuY6~EFtK*v(qxod{%cV1G%tHxWC=SF#D~h{i;JD$j2IZ&Loehk)Lf8PrW}uAYA%tsEzoGM5h7sIAFX^z2zh0Z z29W}ZWZiv{{l~2`wWG1n5hEjKEoJMBvm|z^k_0qA_+9yD$&9__IlPRMRzRhIF%ciUVMb84Gd#CX)u6YjL zdc9bZ#AMDi1!3 zDYuH5)gKrun+N=zzzR+=1f&JAR{QI+3$RsD1z@KR#Zw^+NdG zb?vZALZ4E+TMF)%kAo!3T)6pR!+lHDzk3ufmKi(zwt4@7Kp}^*i8j&pRoYNy=be7c zwdt^0q{&mUFY5811LO|pmAHVzZL`5X1O1F)JbQgwp8#jY)?>LPwNXn` zsYqx10!RI=^AZ3X>d0h}i$LKPl{pElBWd#Q^P?}DjbR5y%H=*3P#$cT5_-U8k| zTJ|tZvnwRu|JBNWKokc0D0!kyUtd!7Oq)%>gR+vr+v)L1x{179`=O`tWHtULmjWJg zMW@QYw$`I^K|5zEc*617>hBehUT?FO&oVa$FWz$xwRMgHIm2gTdjjVm1ExCspH5#w z-a9UKNa*~&n~(r4p-va?jfd=R2I?HOB~BfIXL`2QlarTsNG#UoOw3Tg|L>K@K>6GG wd&~S)`74M1lCcB-9hH7{{1pO!Ies{H{5MFjHV3i(RIwc2_s2i(XHdX@0XjAoxc~qF literal 0 HcmV?d00001 diff --git a/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot new file mode 100644 index 00000000000..1ffc985c450 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot @@ -0,0 +1,34 @@ +// TW Snapshot +// Input SHA-256: 7be6188a713254fa9b1f4ca207fbb6116aad958f321cd54f4f07f49a9f2c1a58 + +// 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 = runtime.getOpcodeFunction("looks_sayforsecs"); +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); +b1.value = (0 + 0); +yield* executeInCompatibilityLayer({"MESSAGE":"Hello!","SECS":0.1,}, b2, false, false, "d", null); +if (((((+b1.value || 0) + 2) || 0) === 2)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "i", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, 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["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +thread.timer = timer(); +var a0 = Math.max(0, 1000 * 0); +runtime.requestRedraw(); +yield; +while (thread.timer.timeElapsed() < a0) { +yield; +} +thread.timer = null; +b0.value = "string"; +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot new file mode 100644 index 00000000000..1ffc985c450 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot @@ -0,0 +1,34 @@ +// TW Snapshot +// Input SHA-256: 7be6188a713254fa9b1f4ca207fbb6116aad958f321cd54f4f07f49a9f2c1a58 + +// 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 = runtime.getOpcodeFunction("looks_sayforsecs"); +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); +b1.value = (0 + 0); +yield* executeInCompatibilityLayer({"MESSAGE":"Hello!","SECS":0.1,}, b2, false, false, "d", null); +if (((((+b1.value || 0) + 2) || 0) === 2)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "i", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, 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["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +thread.timer = timer(); +var a0 = Math.max(0, 1000 * 0); +runtime.requestRedraw(); +yield; +while (thread.timer.timeElapsed() < a0) { +yield; +} +thread.timer = null; +b0.value = "string"; +retire(); return; +}; }) From 709d155be832f197166b1dc7ae0c44743c9660b7 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 19 Feb 2025 22:10:44 -0600 Subject: [PATCH 019/106] npm audit fix --- package-lock.json | 539 ++++++++++++++++++++++++++++++++++------------ package.json | 2 +- 2 files changed, 406 insertions(+), 135 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb08394a736..8884150aba3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,7 +53,7 @@ "scratch-blocks": "0.1.0-prerelease.20230527085947", "scratch-l10n": "3.16.20231222031921", "scratch-render": "0.1.0-prerelease.20231220210403", - "scratch-render-fonts": "1.0.0-prerelease.20231017225105", + "scratch-render-fonts": "github:TurboWarp/scratch-render-fonts#master", "scratch-storage": "2.3.1", "script-loader": "0.7.2", "stats.js": "0.17.0", @@ -2196,23 +2196,31 @@ } }, "node_modules/@turbowarp/scratch-svg-renderer": { - "version": "1.0.0-202312300007-62fe825", - "resolved": "https://registry.npmjs.org/@turbowarp/scratch-svg-renderer/-/scratch-svg-renderer-1.0.0-202312300007-62fe825.tgz", - "integrity": "sha512-x8+FsBVbMOeFA/K40upm4Bh9/nQ7L3LIg871lsvnLOsFnVsmAaKDhqWOyzU+XQgg/Qv0/+f+NoE+1FO1JtRiFw==", + "version": "1.0.202409161736", + "resolved": "https://registry.npmjs.org/@turbowarp/scratch-svg-renderer/-/scratch-svg-renderer-1.0.202409161736.tgz", + "integrity": "sha512-Lztj24zQqT8Ddw7gz1zCbRFZXi/h3r9boEzlQs5omtHeImGZe6I8mLkoHyeP/jJGOUpp5LKZgTKGOStBLtRSiw==", + "license": "MPL-2.0", "peer": true, "dependencies": { + "@turbowarp/nanolog": "^0.2.0", "base64-js": "1.2.1", "base64-loader": "1.0.0", "css-tree": "1.1.3", - "dompurify": "2.2.7", + "dompurify": "^2.5.6", "fastestsmallesttextencoderdecoder": "^1.0.22", - "minilog": "3.1.0", "transformation-matrix": "1.15.0" }, "peerDependencies": { - "scratch-render-fonts": "^1.0.0-prerelease" + "scratch-render-fonts": "github:TurboWarp/scratch-render-fonts#master" } }, + "node_modules/@turbowarp/scratch-svg-renderer/node_modules/dompurify": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz", + "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "peer": true + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -3372,21 +3380,22 @@ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", + "qs": "6.13.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -3400,6 +3409,7 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3409,6 +3419,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -3417,15 +3428,17 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/body-parser/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -3458,12 +3471,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "devOptional": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -3854,6 +3868,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", @@ -4349,6 +4392,7 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4360,10 +4404,11 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4588,10 +4633,11 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -5058,6 +5104,7 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5076,6 +5123,7 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -5230,7 +5278,8 @@ "node_modules/dompurify": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.7.tgz", - "integrity": "sha512-jdtDffdGNY+C76jvodNTu9jt5yYj59vuTUyx+wXdzcSwAGTYZDAQkQ7Iwx9zcGrA4ixC1syU4H3RZROqRxokxg==" + "integrity": "sha512-jdtDffdGNY+C76jvodNTu9jt5yYj59vuTUyx+wXdzcSwAGTYZDAQkQ7Iwx9zcGrA4ixC1syU4H3RZROqRxokxg==", + "dev": true }, "node_modules/domutils": { "version": "1.7.0", @@ -5294,6 +5343,20 @@ "semver": "bin/semver" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -5402,7 +5465,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.4.617", @@ -5411,9 +5475,10 @@ "dev": true }, "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -5444,10 +5509,11 @@ } }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5587,6 +5653,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-iterator-helpers": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", @@ -5610,6 +5694,18 @@ "safe-array-concat": "^1.0.1" } }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", @@ -5654,14 +5750,16 @@ } }, "node_modules/es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "dev": true, "hasInstallScript": true, + "license": "ISC", "dependencies": { "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", "next-tick": "^1.1.0" }, "engines": { @@ -6222,6 +6320,29 @@ "node": ">=6" } }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esniff/node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "dev": true, + "license": "ISC" + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -6309,6 +6430,7 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6380,10 +6502,11 @@ } }, "node_modules/execa/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, + "license": "MIT", "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -6562,37 +6685,38 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -6601,6 +6725,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/array-flatten": { @@ -6625,12 +6753,13 @@ "dev": true }, "node_modules/express/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -6943,10 +7072,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "devOptional": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -6955,13 +7085,14 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -6977,6 +7108,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -6985,7 +7117,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/find-cache-dir": { "version": "3.3.2", @@ -7128,9 +7261,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "dev": true, "funding": [ { @@ -7138,6 +7271,7 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -7814,6 +7948,7 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -8060,14 +8195,24 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8082,6 +8227,19 @@ "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -8240,11 +8398,12 @@ "dev": true }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8410,6 +8569,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "optional": true, "engines": { "node": ">= 0.4" }, @@ -8427,9 +8588,10 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -8573,9 +8735,10 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -8698,6 +8861,7 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -9158,10 +9322,11 @@ } }, "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", - "dev": true + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", + "dev": true, + "license": "MIT" }, "node_modules/ip-regex": { "version": "2.1.0", @@ -9481,6 +9646,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -10610,6 +10776,15 @@ "node": ">= 8.16.2" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -10637,6 +10812,7 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -10715,10 +10891,14 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-source-map": { "version": "1.0.4", @@ -10886,6 +11066,7 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -11666,9 +11847,13 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -11812,6 +11997,7 @@ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -12226,10 +12412,11 @@ "dev": true }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "3.0.0", @@ -12679,10 +12866,11 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -12698,6 +12886,7 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -13379,7 +13568,7 @@ }, "node_modules/scratch-parser": { "version": "0.0.0-development", - "resolved": "git+ssh://git@github.com/TurboWarp/scratch-parser.git#9911fe8e6b5aed34ea19aff5490c3948d1523fc5", + "resolved": "git+ssh://git@github.com/TurboWarp/scratch-parser.git#e00db024414831fb61a1117f8585f91fc177bf4c", "license": "MPL-2.0", "dependencies": { "@turbowarp/json": "^0.1.1", @@ -13441,9 +13630,8 @@ } }, "node_modules/scratch-render-fonts": { - "version": "1.0.0-prerelease.20231017225105", - "resolved": "https://registry.npmjs.org/scratch-render-fonts/-/scratch-render-fonts-1.0.0-prerelease.20231017225105.tgz", - "integrity": "sha512-Ske5+x9OzfT7wf+eAnMQHutCzyle1er3ncywPMLPC6UDjKrlHYUFVNeTR3vJb3EoMdBNPl/yVKuJItGPQoUugg==", + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/TurboWarp/scratch-render-fonts.git#6be162025085d738317b40a01644cf8dcbcee023", "dependencies": { "base64-loader": "1.0.0" } @@ -13645,10 +13833,11 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -13673,6 +13862,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -13681,13 +13871,25 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serialize-javascript": { "version": "1.9.1", @@ -13774,15 +13976,16 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, + "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -13864,7 +14067,8 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/sha.js": { "version": "2.4.11", @@ -13978,13 +14182,72 @@ "dev": true }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14592,6 +14855,7 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -17115,9 +17379,10 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.6.tgz", + "integrity": "sha512-2lBVf/VMVIddjSn3GqbT90GvIJ/eYXJkt8cTzU7NbjKqK8fwv18Ftr4PlbF46b/e88743iZFL5Dtr/rC4hjIeA==", + "license": "MIT", "dependencies": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", @@ -17535,6 +17800,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "devOptional": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -17547,6 +17813,7 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6" } @@ -17683,6 +17950,7 @@ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -18095,6 +18363,7 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -18750,10 +19019,11 @@ } }, "node_modules/webpack-cli/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, + "license": "MIT", "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -19991,10 +20261,11 @@ } }, "node_modules/ws": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", - "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", "dev": true, + "license": "MIT", "dependencies": { "async-limiter": "~1.0.0" } diff --git a/package.json b/package.json index b5286ec8a74..2c841260adb 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "scratch-blocks": "0.1.0-prerelease.20230527085947", "scratch-l10n": "3.16.20231222031921", "scratch-render": "0.1.0-prerelease.20231220210403", - "scratch-render-fonts": "1.0.0-prerelease.20231017225105", + "scratch-render-fonts": "github:TurboWarp/scratch-render-fonts#master", "scratch-storage": "2.3.1", "script-loader": "0.7.2", "stats.js": "0.17.0", From 2d29cdc63ada11edbcd519d5b8249a39a703fbb7 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Fri, 7 Mar 2025 01:11:17 -0600 Subject: [PATCH 020/106] Quit VM when execute test times out A future test project will be designed such that failing to quit the VM after timing out would severely inhibit the performance of the other tests. --- test/integration/execute.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/integration/execute.js b/test/integration/execute.js index 2c758ecce39..88d9e7d475b 100644 --- a/test/integration/execute.js +++ b/test/integration/execute.js @@ -45,6 +45,9 @@ const whenThreadsComplete = (t, vm, uri, timeLimit = 5000) => const timeoutId = setTimeout(() => { t.fail(`Timeout waiting for threads to complete: ${uri}`); reject(new Error('time limit reached')); + + // Attempt to stop the lingering VM from interfering with other tests. + vm.quit(); }, timeLimit); // Clear the interval to allow the process to exit From 7ef5e29c16589d7f9449c9838d9211f9c6d0efce Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Fri, 7 Mar 2025 01:21:08 -0600 Subject: [PATCH 021/106] interpreter: fix skipped blocks in recursive procedures using "stop this script" Closes https://github.com/TurboWarp/scratch-vm/issues/249 Regression from 20f25f252c0560215fb1997beafac1419c2b969b --- src/engine/sequencer.js | 7 +- test/fixtures/execute/tw-gh-249-quicksort.sb3 | Bin 0 -> 41135 bytes .../tw-gh-249-quicksort.sb3.tw-snapshot | 112 +++++++++++++++++ .../tw-gh-249-quicksort.sb3.tw-snapshot | 119 ++++++++++++++++++ 4 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/execute/tw-gh-249-quicksort.sb3 create mode 100644 test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index 1f3bbc5ed63..c374fb694b9 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -194,6 +194,7 @@ class Sequencer { } // Save the current block ID to notice if we did control flow. while ((currentBlockId = thread.peekStack())) { + const initialStackSize = thread.stack.length; let isWarpMode = thread.peekStackFrame().warpMode; if (isWarpMode && !thread.warpTimer) { // Initialize warp-mode timer if it hasn't been already. @@ -239,7 +240,11 @@ class Sequencer { return; } // If no control flow has happened, switch to next block. - if (thread.peekStack() === currentBlockId && !thread.peekStackFrame().waitingReporter) { + if ( + thread.stack.length === initialStackSize && + thread.peekStack() === currentBlockId && + !thread.peekStackFrame().waitingReporter + ) { thread.goToNextBlock(); } // If no next block has been found at this point, look on the stack. diff --git a/test/fixtures/execute/tw-gh-249-quicksort.sb3 b/test/fixtures/execute/tw-gh-249-quicksort.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..ff393d2a91fd57a1279c8662c7a60b56595e43ab GIT binary patch literal 41135 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 0.5; a0--) { +b0.value.push((b1.value[(((b0.value.length + 1) || 0) | 0) - 1] ?? "")); +b0._monitorUpToDate = false; +} +thread.procedures["Wqsort %s %s"](1,b0.value.length); +return ""; +}; }) + +// Sprite1 Wvalidate +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["7AH{dO^X;}C[{[l~g-7m"]; +const b1 = stage.variables["gPJ}c-PZz?Y+_L][iMU_"]; +const b2 = stage.variables["EF^k=u-t@S)w60;RP?dZ-list-list"]; +const b3 = stage.variables["FsKqV/2kid0gw0J+Jj(c"]; +const b4 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ_validate () { +b0.value = 1; +b1.value = 1; +for (var a0 = b2.value.length; a0 >= 0.5; a0--) { +if (!compareEqual(listGet(b2.value, b1.value), listGet(b3.value, b1.value))) { +b0.value = 0; +yield* executeInCompatibilityLayer({"MESSAGE":("fail mismatch at index " + ("" + b1.value)),}, b4, true, false, ",", null); +} +b1.value = ((+b1.value || 0) + 1); +} +if (((+b0.value || 0) === 1)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass sorted",}, b4, true, false, "aE", null); +} +return ""; +}; }) + +// Sprite1 Wqsort %s %s +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["EF^k=u-t@S)w60;RP?dZ-pivot-"]; +const b1 = stage.variables["EF^k=u-t@S)w60;RP?dZ-list-list"]; +const b2 = stage.variables["EF^k=u-t@S)w60;RP?dZ-low-"]; +const b3 = stage.variables["EF^k=u-t@S)w60;RP?dZ-high-"]; +const b4 = stage.variables["EF^k=u-t@S)w60;RP?dZ-tmp-"]; +const b5 = target.variables["JIHtr29*ug5G;5*`f2.K-i-"]; +const b6 = target.variables["JIHtr29*ug5G;5*`f2.K-min pos-"]; +const b7 = target.variables["JIHtr29*ug5G;5*`f2.K-min-"]; +const b8 = target.variables["JIHtr29*ug5G;5*`f2.K-j-"]; +return function funXYZ_qsort__ (p0,p1) { +if (compareLessThan(p0, p1)) { +if (!(((+p1 || 0) - (+p0 || 0)) <= 7)) { +b0.value = (b1.value[((((((+p1 || 0) + (+p0 || 0)) || 0) / 2) || 0) | 0) - 1] ?? ""); +b2.value = p0; +b3.value = p1; +while (true) { +while (compareLessThan(listGet(b1.value, b2.value), b0.value)) { +b2.value = ((+b2.value || 0) + 1); +} +while (compareGreaterThan(listGet(b1.value, b3.value), b0.value)) { +b3.value = ((+b3.value || 0) + -1); +} +if (compareGreaterThan(b2.value, b3.value)) { +thread.procedures["Wqsort %s %s"](p0,b3.value); +thread.procedures["Wqsort %s %s"](b2.value,p1); +return ""; +} else { +b4.value = listGet(b1.value, b2.value); +listReplace(b1, b2.value, listGet(b1.value, b3.value)); +listReplace(b1, b3.value, b4.value); +b2.value = ((+b2.value || 0) + 1); +b3.value = ((+b3.value || 0) + -1); +} +} +} else { +b5.value = p0; +for (var a0 = (((+p1 || 0) - (+p0 || 0)) || 0); a0 >= 0.5; a0--) { +b6.value = b5.value; +b7.value = listGet(b1.value, b5.value); +b8.value = ((+b5.value || 0) + 1); +for (var a1 = (((+p1 || 0) - (+b5.value || 0)) || 0); a1 >= 0.5; a1--) { +if (compareLessThan(listGet(b1.value, b8.value), b7.value)) { +b7.value = listGet(b1.value, b8.value); +b6.value = b8.value; +} +b8.value = ((+b8.value || 0) + 1); +} +if (compareEqual(b6.value, b5.value)) { +} else { +b4.value = listGet(b1.value, b5.value); +listReplace(b1, b5.value, b7.value); +listReplace(b1, b6.value, b4.value); +} +b5.value = ((+b5.value || 0) + 1); +} +} +} +return ""; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot new file mode 100644 index 00000000000..bf45bf0cc9c --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot @@ -0,0 +1,119 @@ +// TW Snapshot +// Input SHA-256: ce657aa0f3e55d0c2166813c9fa3dd076c3f0c81df2e527f44d0ad31856a448d + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "Z", null); +yield* thread.procedures["Wrun"](); +yield* thread.procedures["Wvalidate"](); +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "aw", null); +retire(); return; +}; }) + +// Sprite1 Wrun +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["EF^k=u-t@S)w60;RP?dZ-list-list"]; +const b1 = stage.variables["rQq!wAuU2T9DV9,S[/s."]; +return function* genXYZ_run () { +b0.value = []; +for (var a0 = 100; a0 >= 0.5; a0--) { +b0.value.push((b1.value[(((b0.value.length + 1) || 0) | 0) - 1] ?? "")); +b0._monitorUpToDate = false; +if (isStuck()) yield; +} +yield* thread.procedures["Wqsort %s %s"](1,b0.value.length); +return ""; +}; }) + +// Sprite1 Wvalidate +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["7AH{dO^X;}C[{[l~g-7m"]; +const b1 = stage.variables["gPJ}c-PZz?Y+_L][iMU_"]; +const b2 = stage.variables["EF^k=u-t@S)w60;RP?dZ-list-list"]; +const b3 = stage.variables["FsKqV/2kid0gw0J+Jj(c"]; +const b4 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ_validate () { +b0.value = 1; +b1.value = 1; +for (var a0 = b2.value.length; a0 >= 0.5; a0--) { +if (!compareEqual(listGet(b2.value, b1.value), listGet(b3.value, b1.value))) { +b0.value = 0; +yield* executeInCompatibilityLayer({"MESSAGE":("fail mismatch at index " + ("" + b1.value)),}, b4, true, false, ",", null); +} +b1.value = ((+b1.value || 0) + 1); +if (isStuck()) yield; +} +if (((+b0.value || 0) === 1)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass sorted",}, b4, true, false, "aE", null); +} +return ""; +}; }) + +// Sprite1 Wqsort %s %s +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["EF^k=u-t@S)w60;RP?dZ-pivot-"]; +const b1 = stage.variables["EF^k=u-t@S)w60;RP?dZ-list-list"]; +const b2 = stage.variables["EF^k=u-t@S)w60;RP?dZ-low-"]; +const b3 = stage.variables["EF^k=u-t@S)w60;RP?dZ-high-"]; +const b4 = stage.variables["EF^k=u-t@S)w60;RP?dZ-tmp-"]; +const b5 = target.variables["JIHtr29*ug5G;5*`f2.K-i-"]; +const b6 = target.variables["JIHtr29*ug5G;5*`f2.K-min pos-"]; +const b7 = target.variables["JIHtr29*ug5G;5*`f2.K-min-"]; +const b8 = target.variables["JIHtr29*ug5G;5*`f2.K-j-"]; +return function* genXYZ_qsort__ (p0,p1) { +if (compareLessThan(p0, p1)) { +if (!(((+p1 || 0) - (+p0 || 0)) <= 7)) { +b0.value = (b1.value[((((((+p1 || 0) + (+p0 || 0)) || 0) / 2) || 0) | 0) - 1] ?? ""); +b2.value = p0; +b3.value = p1; +while (true) { +while (compareLessThan(listGet(b1.value, b2.value), b0.value)) { +b2.value = ((+b2.value || 0) + 1); +if (isStuck()) yield; +} +while (compareGreaterThan(listGet(b1.value, b3.value), b0.value)) { +b3.value = ((+b3.value || 0) + -1); +if (isStuck()) yield; +} +if (compareGreaterThan(b2.value, b3.value)) { +yield* thread.procedures["Wqsort %s %s"](p0,b3.value); +yield* thread.procedures["Wqsort %s %s"](b2.value,p1); +return ""; +} else { +b4.value = listGet(b1.value, b2.value); +listReplace(b1, b2.value, listGet(b1.value, b3.value)); +listReplace(b1, b3.value, b4.value); +b2.value = ((+b2.value || 0) + 1); +b3.value = ((+b3.value || 0) + -1); +} +if (isStuck()) yield; +} +} else { +b5.value = p0; +for (var a0 = (((+p1 || 0) - (+p0 || 0)) || 0); a0 >= 0.5; a0--) { +b6.value = b5.value; +b7.value = listGet(b1.value, b5.value); +b8.value = ((+b5.value || 0) + 1); +for (var a1 = (((+p1 || 0) - (+b5.value || 0)) || 0); a1 >= 0.5; a1--) { +if (compareLessThan(listGet(b1.value, b8.value), b7.value)) { +b7.value = listGet(b1.value, b8.value); +b6.value = b8.value; +} +b8.value = ((+b8.value || 0) + 1); +if (isStuck()) yield; +} +if (compareEqual(b6.value, b5.value)) { +} else { +b4.value = listGet(b1.value, b5.value); +listReplace(b1, b5.value, b7.value); +listReplace(b1, b6.value, b4.value); +} +b5.value = ((+b5.value || 0) + 1); +if (isStuck()) yield; +} +} +} +return ""; +}; }) From 1da38dad801db439827980197613384ce323f8f0 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Thu, 27 Mar 2025 13:11:23 -0500 Subject: [PATCH 022/106] Update GitHub Actions workflow - Node.js 22 - Replace npm run test with npm run tap to avoid unnecessarily running ESLint twice --- .github/workflows/node.js.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index de686d4f43b..7aa40ca0e77 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -14,9 +14,9 @@ jobs: - name: Install Node.js uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af with: - node-version: 20 + node-version: 22 cache: npm - run: npm ci - run: npm run lint - run: npm run build - - run: npm run test + - run: npm run tap From b8520ccd9ad31d037f686c437cf2a004385c92b6 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Thu, 27 Mar 2025 13:34:21 -0500 Subject: [PATCH 023/106] Fix visual report error when thread target does not match editing target Fixes #252 --- src/compiler/jsgen.js | 2 +- src/engine/execute.js | 2 +- src/engine/runtime.js | 7 +- .../tw-slow-custom-reporter-stack-click.sb3 | Bin 0 -> 3074 bytes .../tw_slow_custom_reporter_stack_click.js | 66 ++++++++++++++++++ 5 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/tw-slow-custom-reporter-stack-click.sb3 create mode 100644 test/integration/tw_slow_custom_reporter_stack_click.js diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 10387a797a7..9807be5a01a 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -1160,7 +1160,7 @@ class JSGenerator { const value = this.localVariables.next(); this.source += `const ${value} = ${this.descendInput(node.input).asUnknown()};`; // blocks like legacy no-ops can return a literal `undefined` - this.source += `if (${value} !== undefined) runtime.visualReport("${sanitize(this.script.topBlockId)}", ${value});\n`; + this.source += `if (${value} !== undefined) runtime.visualReport(target, "${sanitize(this.script.topBlockId)}", ${value});\n`; break; } diff --git a/src/engine/execute.js b/src/engine/execute.js index 8cb192f0938..c411f244c93 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -92,7 +92,7 @@ const handleReport = function (resolvedValue, sequencer, thread, blockCached, la // at the top of the thread stack. if (lastOperation && typeof resolvedValue !== 'undefined' && thread.atStackTop()) { if (thread.stackClick) { - sequencer.runtime.visualReport(currentBlockId, resolvedValue); + sequencer.runtime.visualReport(thread.target, currentBlockId, resolvedValue); } if (thread.updateMonitor) { const targetId = sequencer.runtime.monitorBlocks.getBlock(currentBlockId).targetId; diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 0f0c74a86f3..f407dbdd5c8 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -3073,11 +3073,14 @@ class Runtime extends EventEmitter { /** * Emit value for reporter to show in the blocks. + * @param {Target} target The target that the block was run in. * @param {string} blockId ID for the block. * @param {string} value Value to show associated with the block. */ - visualReport (blockId, value) { - this.emit(Runtime.VISUAL_REPORT, {id: blockId, value: String(value)}); + visualReport (target, blockId, value) { + if (target === this.getEditingTarget()) { + this.emit(Runtime.VISUAL_REPORT, {id: blockId, value: String(value)}); + } } /** diff --git a/test/fixtures/tw-slow-custom-reporter-stack-click.sb3 b/test/fixtures/tw-slow-custom-reporter-stack-click.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..ef59b599a3588fa5ccb2090ba4e643606fb94a8b GIT binary patch literal 3074 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 literal 0 HcmV?d00001 diff --git a/test/integration/tw_slow_custom_reporter_stack_click.js b/test/integration/tw_slow_custom_reporter_stack_click.js new file mode 100644 index 00000000000..847ca04112c --- /dev/null +++ b/test/integration/tw_slow_custom_reporter_stack_click.js @@ -0,0 +1,66 @@ +const {test} = require('tap'); +const fs = require('fs'); +const path = require('path'); +const VirtualMachine = require('../../src/virtual-machine'); + +const fixtureData = fs.readFileSync(path.join(__dirname, '../fixtures/tw-slow-custom-reporter-stack-click.sb3')); + +// After starting this block, first step will yield, second step will report value +const procedureCallBlockId = 'e'; + +test('when thread target is editing target', t => { + const vm = new VirtualMachine(); + vm.loadProject(fixtureData).then(() => { + const visualReports = []; + vm.on('VISUAL_REPORT', visualReport => { + visualReports.push(visualReport); + }); + + vm.setEditingTarget(vm.runtime.getSpriteTargetByName('Sprite1').id); + vm.runtime.toggleScript(procedureCallBlockId, { + stackClick: true + }); + + t.same(visualReports, []); + + vm.runtime._step(); + t.same(visualReports, []); + + vm.runtime._step(); + t.same(visualReports, [ + { + id: 'e', + value: 'return value' + } + ]); + + t.end(); + }); +}); + +test('when thread target is not editing target', t => { + const vm = new VirtualMachine(); + vm.loadProject(fixtureData).then(() => { + const visualReports = []; + vm.on('VISUAL_REPORT', visualReport => { + visualReports.push(visualReport); + }); + + vm.setEditingTarget(vm.runtime.getSpriteTargetByName('Sprite1').id); + vm.runtime.toggleScript(procedureCallBlockId, { + stackClick: true + }); + + t.same(visualReports, []); + + vm.runtime._step(); + t.same(visualReports, []); + + vm.setEditingTarget(vm.runtime.getSpriteTargetByName('Sprite2').id); + + vm.runtime._step(); + t.same(visualReports, []); + + t.end(); + }); +}); From ba9ae068ca689192a88422df622761159f7ffd40 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Tue, 13 May 2025 21:45:21 -0500 Subject: [PATCH 024/106] Don't compress formats that are already compressed (#258) Closes https://github.com/TurboWarp/scratch-vm/issues/253 --- src/virtual-machine.js | 20 +++++++++-- test/fixtures/tw-mixed-file-formats.sb3 | Bin 0 -> 119487 bytes .../tw_compression_per_file_type.js | 31 ++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/tw-mixed-file-formats.sb3 create mode 100644 test/integration/tw_compression_per_file_type.js diff --git a/src/virtual-machine.js b/src/virtual-machine.js index e02d87222a2..14ff8310a2f 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -537,6 +537,22 @@ class VirtualMachine extends EventEmitter { file.date = date; } + // Tell JSZip to only compress file formats where there will be a significant gain. + const COMPRESSABLE_FORMATS = [ + '.json', + '.svg', + '.wav', + '.ttf', + '.otf' + ]; + for (const file of Object.values(zip.files)) { + if (COMPRESSABLE_FORMATS.some(ext => file.name.endsWith(ext))) { + file.options.compression = 'DEFLATE'; + } else { + file.options.compression = 'STORE'; + } + } + return zip; } @@ -546,9 +562,9 @@ class VirtualMachine extends EventEmitter { */ saveProjectSb3 (type) { return this._saveProjectZip().generateAsync({ + // Don't configure compression here. _saveProjectZip() will set it for each file. type: type || 'blob', - mimeType: 'application/x.scratch.sb3', - compression: 'DEFLATE' + mimeType: 'application/x.scratch.sb3' }); } diff --git a/test/fixtures/tw-mixed-file-formats.sb3 b/test/fixtures/tw-mixed-file-formats.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..f06c40d680be8bdae6db161f135443ef8ff38936 GIT binary patch literal 119487 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 literal 0 HcmV?d00001 diff --git a/test/integration/tw_compression_per_file_type.js b/test/integration/tw_compression_per_file_type.js new file mode 100644 index 00000000000..35f02a68cdb --- /dev/null +++ b/test/integration/tw_compression_per_file_type.js @@ -0,0 +1,31 @@ +const {test} = require('tap'); +const fs = require('fs'); +const path = require('path'); +const VM = require('../../src/virtual-machine'); +const makeTestStorage = require('../fixtures/make-test-storage'); +const JSZip = require('@turbowarp/jszip'); + +test('saveProjectSb3() per-file compression', t => { + const vm = new VM(); + vm.attachStorage(makeTestStorage()); + const fixture = fs.readFileSync(path.join(__dirname, '../fixtures/tw-mixed-file-formats.sb3')); + vm.loadProject(fixture) + .then(() => vm.saveProjectSb3('arraybuffer')) + .then(buffer => JSZip.loadAsync(buffer)) + .then(zip => { + const isCompressed = pathInZip => { + // note: uses JSZip private APIs, not very stable, but it should be okay... + const file = zip.files[pathInZip]; + return file._data.compression.magic === '\x08\x00'; + }; + + t.ok(isCompressed('project.json')); + t.ok(isCompressed('5cb46ddd903fc2c9976ff881df9273c9.wav')); + t.ok(isCompressed('cd21514d0531fdffb22204e0ec5ed84a.svg')); + + t.notOk(isCompressed('0b2e50ca4107ce57416e2ceb840a6347.jpg')); + t.notOk(isCompressed('5c8826d846c06dddeb77590e8792fb7d.png')); + + t.end(); + }); +}); From 4eb911771d504cf22be454801e0367a1e9e472cb Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Tue, 13 May 2025 23:02:30 -0500 Subject: [PATCH 025/106] Update sb3fix --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8884150aba3..ce30af175a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2134,9 +2134,9 @@ "integrity": "sha512-9nWywp+0SH7ROVzQPQQO9gMWBikahsqyMWp1Ku8VV0q+q6bnx6dS0aNPTjqTtF2GHAY55hcREsqKzaoUdWBSwg==" }, "node_modules/@turbowarp/jszip": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@turbowarp/jszip/-/jszip-3.11.0.tgz", - "integrity": "sha512-G+xld2rPv0b7ZKIk4ZZLW8l46+VfdUsreYjWml8bl3IHrmQXgijkmiDwTq17CBf5GPlz4+F/TpJdclq0jhMSVQ==", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@turbowarp/jszip/-/jszip-3.11.1.tgz", + "integrity": "sha512-1tWXTxAac1T/g0VHC9lIY0Ij7Qyt7sORIaAT4L0/Y+pjU1ZtXD9ti/+RnXzTVHXp6AM8fM2O3mF22/aSEVPXiQ==", "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", @@ -2187,12 +2187,12 @@ "integrity": "sha512-texcM9oxfEsADVlVDR5UhLkYclPKsV9mytJh+9pHHonNcUrxRVGF6FkJTzWO/Hl5NafU1crSdw737nqKE3atSA==" }, "node_modules/@turbowarp/sb3fix": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@turbowarp/sb3fix/-/sb3fix-0.3.0.tgz", - "integrity": "sha512-tZjpPb37UUnr6mxeZ12FLqHFhQ66rIUEIfFMWoLLzmt8VFE6JjM74chyphsB3AwON5ehs678zzXkhRSOZgPK3A==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@turbowarp/sb3fix/-/sb3fix-0.3.6.tgz", + "integrity": "sha512-pKRyJbZYGHFAQNacwJEoz5sh8SnSDRFFle1BcEoyZHRuDE/9TZoBFNfYzoyjKCeOyOBStcS8kmGhak45YabaDg==", "license": "MPL-2.0", "dependencies": { - "@turbowarp/jszip": "^3.11.0" + "@turbowarp/jszip": "^3.11.1" } }, "node_modules/@turbowarp/scratch-svg-renderer": { From f957e1c6c1e5244976300ac5fd6ae8a625ed6a76 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Tue, 20 May 2025 13:29:33 -0500 Subject: [PATCH 026/106] Fix Mouse.postData error if called before project loads --- src/io/mouse.js | 21 ++++++++++++--------- test/unit/tw_mouse.js | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 test/unit/tw_mouse.js diff --git a/src/io/mouse.js b/src/io/mouse.js index 169e6af0b67..bc46d907d84 100644 --- a/src/io/mouse.js +++ b/src/io/mouse.js @@ -101,16 +101,19 @@ class Mouse { if (!(data.x > 0 && data.x < data.canvasWidth && data.y > 0 && data.y < data.canvasHeight)) return; + // target will not exist if project is still loading const target = this._pickTarget(data.x, data.y); - const isNewMouseDown = !previousDownState && this._isDown; - const isNewMouseUp = previousDownState && !this._isDown; - - // Draggable targets start click hats on mouse up. - // Non-draggable targets start click hats on mouse down. - if (target.draggable && isNewMouseUp) { - this._activateClickHats(target); - } else if (!target.draggable && isNewMouseDown) { - this._activateClickHats(target); + if (target) { + const isNewMouseDown = !previousDownState && this._isDown; + const isNewMouseUp = previousDownState && !this._isDown; + + // Draggable targets start click hats on mouse up. + // Non-draggable targets start click hats on mouse down. + if (target.draggable && isNewMouseUp) { + this._activateClickHats(target); + } else if (!target.draggable && isNewMouseDown) { + this._activateClickHats(target); + } } } } diff --git a/test/unit/tw_mouse.js b/test/unit/tw_mouse.js new file mode 100644 index 00000000000..17aeb200f37 --- /dev/null +++ b/test/unit/tw_mouse.js @@ -0,0 +1,14 @@ +const {test} = require('tap'); +const Runtime = require('../../src/engine/runtime'); + +test('isDown does not error before project loads', t => { + const rt = new Runtime(); + rt.ioDevices.mouse.postData({ + isDown: true, + x: 20, + y: 20, + canvasWidth: 100, + canvasHeight: 100 + }); + t.end(); +}); From 5bc497aabbc974525e4109256b3875037d3a2756 Mon Sep 17 00:00:00 2001 From: ghost <161080149+AshimeeAlt@users.noreply.github.com> Date: Tue, 20 May 2025 22:48:52 -0400 Subject: [PATCH 027/106] Add blockShape option to extensions (#210) --- src/engine/runtime.js | 5 +++ src/extension-support/tw-block-shape.js | 25 ++++++++++++ .../tw-extension-api-common.js | 2 + test/unit/tw_block_shape.js | 38 +++++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 src/extension-support/tw-block-shape.js create mode 100644 test/unit/tw_block_shape.js diff --git a/src/engine/runtime.js b/src/engine/runtime.js index f407dbdd5c8..503a1fbc449 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -1429,6 +1429,11 @@ class Runtime extends EventEmitter { break; } + // Allow extensiosn to override outputShape + if (blockInfo.blockShape) { + blockJSON.outputShape = blockInfo.blockShape; + } + const blockText = Array.isArray(blockInfo.text) ? blockInfo.text : [blockInfo.text]; let inTextNum = 0; // text for the next block "arm" is blockText[inTextNum] let inBranchNum = 0; // how many branches have we placed into the JSON so far? diff --git a/src/extension-support/tw-block-shape.js b/src/extension-support/tw-block-shape.js new file mode 100644 index 00000000000..854975ada88 --- /dev/null +++ b/src/extension-support/tw-block-shape.js @@ -0,0 +1,25 @@ +// Use the constants instead of manually redefining them again +const ScratchBlocksConstants = require('../engine/scratch-blocks-constants'); + +/** + * Types of block shapes + * @enum {number} + */ +const BlockShape = { + /** + * Output shape: hexagonal (booleans/predicates). + */ + HEXAGONAL: ScratchBlocksConstants.OUTPUT_SHAPE_HEXAGONAL, + + /** + * Output shape: rounded (numbers). + */ + ROUND: ScratchBlocksConstants.OUTPUT_SHAPE_ROUND, + + /** + * Output shape: squared (any/all values; strings). + */ + SQUARE: ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE +}; + +module.exports = BlockShape; diff --git a/src/extension-support/tw-extension-api-common.js b/src/extension-support/tw-extension-api-common.js index e2ac0b74d0f..1f5928fbc0f 100644 --- a/src/extension-support/tw-extension-api-common.js +++ b/src/extension-support/tw-extension-api-common.js @@ -1,11 +1,13 @@ const ArgumentType = require('./argument-type'); const BlockType = require('./block-type'); +const BlockShape = require('./tw-block-shape'); const TargetType = require('./target-type'); const Cast = require('../util/cast'); const Scratch = { ArgumentType, BlockType, + BlockShape, TargetType, Cast }; diff --git a/test/unit/tw_block_shape.js b/test/unit/tw_block_shape.js new file mode 100644 index 00000000000..a5ef50282a6 --- /dev/null +++ b/test/unit/tw_block_shape.js @@ -0,0 +1,38 @@ +const {test} = require('tap'); +const Runtime = require('../../src/engine/runtime'); +const Scratch = require('../../src/extension-support/tw-extension-api-common'); + +test('blockShape', t => { + const rt = new Runtime(); + rt._registerExtensionPrimitives({ + id: 'shapetest', + name: 'shapetest', + blocks: [ + { + blockType: Scratch.BlockType.REPORTER, + blockShape: Scratch.BlockShape.HEXAGONAL, + opcode: 'hexagonal', + text: 'hexagonal' + }, + { + blockType: Scratch.BlockType.BOOLEAN, + blockShape: Scratch.BlockShape.ROUND, + opcode: 'round', + text: 'round' + }, + { + blockType: Scratch.BlockType.REPORTER, + blockShape: Scratch.BlockShape.SQUARE, + opcode: 'square', + text: 'square' + } + ] + }); + + const json = rt.getBlocksJSON(); + t.equal(json.length, 3); + t.equal(json[0].outputShape, 1); + t.equal(json[1].outputShape, 2); + t.equal(json[2].outputShape, 3); + t.end(); +}); From bf572166ab6ab32ae810dcb1bfd711b650ccc5bc Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 31 May 2025 18:19:26 -0500 Subject: [PATCH 028/106] Update scratch-parser --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index ce30af175a5..1bdcb228867 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13568,7 +13568,7 @@ }, "node_modules/scratch-parser": { "version": "0.0.0-development", - "resolved": "git+ssh://git@github.com/TurboWarp/scratch-parser.git#e00db024414831fb61a1117f8585f91fc177bf4c", + "resolved": "git+ssh://git@github.com/TurboWarp/scratch-parser.git#083d6425bc0c43d17f393be2f41f00b6488ba940", "license": "MPL-2.0", "dependencies": { "@turbowarp/json": "^0.1.1", From fa82d53a9490eec29bb7bcef214b2bb8e09e0172 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 4 Jun 2025 13:04:22 -0500 Subject: [PATCH 029/106] Update GitHub Actions workflows - update actions/setup-node to fix extra 10 minute delay in CI - update Node.js - use version ranges instead of commit hashes to get future updates automatically (we already trust the GitHub Actions team) - don't use npm cache in deploy workflow --- .github/workflows/deploy.yml | 11 +++++------ .github/workflows/node.js.yml | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 615842d64e7..8939480c289 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -13,14 +13,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/checkout@v4 with: persist-credentials: false - name: Install Node.js - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af + uses: actions/setup-node@v4 with: - node-version: 20 - cache: npm + node-version: 22 - name: Install dependencies run: npm ci - name: Build playground @@ -31,7 +30,7 @@ jobs: # It will still generate what it can, so it's safe to ignore the error continue-on-error: true - name: Upload artifact - uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa + uses: actions/upload-pages-artifact@v3 with: path: ./playground/ @@ -47,4 +46,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 7aa40ca0e77..43505523085 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -8,11 +8,11 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/checkout@v4 with: persist-credentials: false - name: Install Node.js - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af + uses: actions/setup-node@v4 with: node-version: 22 cache: npm From ef02dc86d8725f3c56adbc6f8384e48bc843d07a Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 7 Jun 2025 18:13:45 -0500 Subject: [PATCH 030/106] Mark pen drawable as non-interactive Using API added in https://github.com/TurboWarp/scratch-render/commit/1ffefcf2cdff2fcbe0bc7f0f000521ae2843f3a8 This replaces the hardcoded PenSkin exclusion in the renderer --- src/extensions/scratch3_pen/index.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/extensions/scratch3_pen/index.js b/src/extensions/scratch3_pen/index.js index b1b8eace4ac..d9734a38a09 100644 --- a/src/extensions/scratch3_pen/index.js +++ b/src/extensions/scratch3_pen/index.js @@ -137,10 +137,14 @@ class Scratch3PenBlocks { * @private */ _getPenLayerID () { - if (this._penSkinId < 0 && this.runtime.renderer) { - this._penSkinId = this.runtime.renderer.createPenSkin(); - this._penDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); - this.runtime.renderer.updateDrawableSkinId(this._penDrawableId, this._penSkinId); + const renderer = this.runtime.renderer; + if (this._penSkinId < 0 && renderer) { + this._penSkinId = renderer.createPenSkin(); + this._penDrawableId = renderer.createDrawable(StageLayering.PEN_LAYER); + if (renderer.markDrawableAsNoninteractive) { + renderer.markDrawableAsNoninteractive(this._penSkinId); + } + renderer.updateDrawableSkinId(this._penDrawableId, this._penSkinId); } return this._penSkinId; } From df92bc28997e75c5455cb589069f4e13f6d1043c Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 7 Jun 2025 18:17:42 -0500 Subject: [PATCH 031/106] Mark video sensing drawable as non-interactive --- src/io/video.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/io/video.js b/src/io/video.js index 35eeadf7cf4..7d8b01c8736 100644 --- a/src/io/video.js +++ b/src/io/video.js @@ -157,6 +157,9 @@ class Video { if (renderer.markSkinAsPrivate) { renderer.markSkinAsPrivate(this._skinId); } + if (renderer.markDrawableAsNoninteractive) { + renderer.markDrawableAsNoninteractive(this._skinId); + } } // if we haven't already created and started a preview frame render loop, do so From 6222be2a3c1e1fe22add331685a4f5b746eec969 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 7 Jun 2025 18:33:32 -0500 Subject: [PATCH 032/106] Fix wrong drawables being marked non-interactive --- src/extensions/scratch3_pen/index.js | 2 +- src/io/video.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extensions/scratch3_pen/index.js b/src/extensions/scratch3_pen/index.js index d9734a38a09..99ebfa99acb 100644 --- a/src/extensions/scratch3_pen/index.js +++ b/src/extensions/scratch3_pen/index.js @@ -142,7 +142,7 @@ class Scratch3PenBlocks { this._penSkinId = renderer.createPenSkin(); this._penDrawableId = renderer.createDrawable(StageLayering.PEN_LAYER); if (renderer.markDrawableAsNoninteractive) { - renderer.markDrawableAsNoninteractive(this._penSkinId); + renderer.markDrawableAsNoninteractive(this._penDrawableId); } renderer.updateDrawableSkinId(this._penDrawableId, this._penSkinId); } diff --git a/src/io/video.js b/src/io/video.js index 7d8b01c8736..65453e3be2b 100644 --- a/src/io/video.js +++ b/src/io/video.js @@ -158,7 +158,7 @@ class Video { renderer.markSkinAsPrivate(this._skinId); } if (renderer.markDrawableAsNoninteractive) { - renderer.markDrawableAsNoninteractive(this._skinId); + renderer.markDrawableAsNoninteractive(this._drawable); } } From fbca1bf49b3ec1c4b2c1b4defb5c533a00a6db0e Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Mon, 8 Sep 2025 11:48:55 +1000 Subject: [PATCH 033/106] Fixed `NaN = 0` wrongly reporting true, and add a test --- src/compiler/jsgen.js | 4 +- test/fixtures/execute/tw-NaN.sb3 | Bin 2773 -> 2869 bytes .../__snapshots__/tw-NaN.sb3.tw-snapshot | 49 ++++++++++-------- .../__snapshots__/tw-tangent.sb3.tw-snapshot | 14 ++--- .../warp-timer/tw-NaN.sb3.tw-snapshot | 49 ++++++++++-------- .../warp-timer/tw-tangent.sb3.tw-snapshot | 14 ++--- 6 files changed, 68 insertions(+), 62 deletions(-) diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 10e41eaa9d4..82f6caf839d 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -57,8 +57,8 @@ const isSafeInputForEqualsOptimization = (input, other) => { if (input.opcode !== InputOpcode.CONSTANT) return false; // Only optimize when the constant can always be thought of as a number if (input.isAlwaysType(InputType.NUMBER) || input.isAlwaysType(InputType.STRING_NUM)) { - if (other.isSometimesType(InputType.STRING_NAN) || other.isSometimesType(InputType.BOOLEAN_INTERPRETABLE)) { - // Never optimize 0 if the other input can be '' or a boolean. + if (other.isSometimesType(InputType.NUMBER_NAN | InputType.STRING_NAN | InputType.BOOLEAN_INTERPRETABLE)) { + // Never optimize 0 if the other input can be NaN, '' or a boolean. // eg. if '< 0 = "" >' was optimized it would turn into `0 === +""`, // which would be true even though Scratch would return false. return (+input.inputs.value) !== 0; diff --git a/test/fixtures/execute/tw-NaN.sb3 b/test/fixtures/execute/tw-NaN.sb3 index 17ddc26bdb14c47bb00600accae4b19495d903eb..411b0c6670dc97141a3da3f88a42f25a25e06e48 100644 GIT binary patch delta 2305 zcmV+c3I6ug6}1+BP)h>@3IG5A2mouh$WTllbhT~>002ls000aC003}uZ)#;@bS`Rh zZ*IMud2^dM7{3YIZO~l z8puB$5JEh>@9%v8+u|Bf7+8pgpnrS~a5$pSLZDBB2sMCz2VJ%dlC}nz!T>|fL9Flf zO#?VMr0Jp-5NPP|e%&GZBwf~t>mu)Viyj35TiYZdjpD&uafkVGq98q_2K9*%5MO17 zH6VpMByb^R8^Wo@nqU|rx@)j?-Ds;lwQIC`9n~~UQ){=|tuAUIy@!m|E@YiuqlYf& z6Z$rj!2?2nA;rYoWI9ps6ZG5NR<`vQ=&P%(o0A3zN#q%^cD6hv&itg*7Tdvrmnawp z1`6h9Ns;Rl&|hYYQ*0nI4xktMkOf1(1pVG^GmABi13)|w?{h)NWaJ~H+k4QnqIqt- z$Z>8O50YgU%Jv4gNNy?H2O2@Nn;9|ty$ zGWPsvJ{%Z++dfzyY^f|Jod&o7jboLa9XMeDN;kFHCN*hpv34fF#K;MSDf@tt4wcmK^xoV z(bJiYJkx=e?qGd_j5~c`1Ki6?#NO$9>TwevX2AEMRhwEk)PK1V)tQ;AUY#YAYuB9LcDX!sz1hstIiDhU*=$DHhXCiXDBl+gE4EJj8x ziP|U;0nh_Z8R5km9Ox-+nbOf0Waz}B0dY>Td9TBKr~@tN*c=YFcE`KJ0aMa$umrLs zjSe?P0USug%`AaenZ zWYF4`M=Qi4kJ6`NXxX)(g-g*o16&aqw7xt>>slPGFEVK10<^wX@26ko{PYXQPyemb zPydyH{_Ar=e=P<*t_AwDQs^guDrCEwKBg zu%832hz#t9Ij~Q}VLz0C-7oS_rxyQoI7k&Q(Bao(%Ly&jP(G2K{+0&v#2r`diLWfAI`8sMJsc8R~yO5B29_)Q7cDPfMwf09QnY`WHFWhvL+~kfELyQ2(-e z>R-xH|AIsPt16*?CByv79OmP4q)++JzSwWBkmd_4{u$#H|AA3|t>|ZrP^=(nEd?2s z79<2*5t)K~ol}sJctO6FDafdxAm3D9kZkGnm4u-c5kk0Q*k~SWutygKQRN^?Z{EC5^@_~9^6;Yh| zebU0J(sdz5ddXxlNzzd%>H0&`H;PDqmqYrxIOz?UTZMN;--c{df3E=7#j=NL$=8Z9biUJDwh&h>53KgJ%|tSg6gXpfyFYSr0{2I0D3~fU>^MqDK#n zn7YtEKp}CW_{{>Kua>;*pwsEB!S-6O13Q|z+}5;z)fVb?O|!SsGc~l`gIEQK^|-{tto~9(?4*$wvfk;si|G7DG(_$+76v-aRT<1PTBE z00;nUx5!YFMhMXaYq!WylN$-r4r{l_P)r|mwQdLi07yfV`w1)rYq!WylPd}u0hp6U b3Nr+2x5!YFeF_=@ZIhS^HwHlp00000jP_Al delta 2208 zcmV;R2w(TL7S$DhP)h>@3IG5A2mpKxh*jg$Dqju=001>W000aC003}uZ)#;@bS`Rh zZ*IL?3v-(`0RAgXz1{8MdVuZP@ou-Jd9-O0yN#Vbmt_J3CkYv1h(ZT}K8>cR0RrfMv)3RUYk(PyFf=^Gj=i~U z01wABduc=jS|(g=d&Hb%uTA3nD7f2WPNRrz?U9&HlgZWOfaU8HL3T+4niDG`p~fz2 zK?)B^W?Qyx=(?`9k&4U?vU+XE4)(1Mx~7jf zwwX>I5eg}PCcz%ViK0)Suea6w=x5N^dg|?Y1H@z+SP6FadPcnEO=&7S!GjAF4I>Lh z%e$n=4+-eMU@vFbLS!7lAPylT!(4!V=WdvBO%no00FraA>6nZ{giQAs2F`S;O)&Mm z+r|U2Z0N-g)Cwa^ktU}XP?KLIG>NrD5uylE5?!Ewt0}t(n=@EanLucOCHjO|%68x& zoGzyW!*>U#yMuj=anfo42IQ;8?hc$Yg0fvY+oh$$DjR12Y>YfB0~5Q@BJ=y(q9i;< zGvs9hx5<=SG5S-F;?P_0P^xPv2WKZ4LY*OOX8_q~2Cki4M;x2Z!3L>ILLM?Lk1PcS zFH>ZH&+|Z19>>E|b{xwuvr01I`D5_4Wb`!)^lewKZ(B~^7DwM{mHKwpu(5psy_mZw zus!IQ9yTY)y2l4*U~mV zXtew4V5L#W>QsV?t{4cj7z7F|2@E|stIW55StT`vy6Kanz{UZl3kiHXVjNku2sJAK zvGm71hE53v4+e@Z6Kl8z!z2NXhzF^7U1fd<886Y+cR}GCxkml=RE_#ftWk|x8ugnTNej*s%8yk( zq5L581bV&Y2{ePyR0|(JA^Y=9;Q14khSCPy(#VB!cQcefiHCAmCX}cklrO6f<w`uxc#7(~^V|u&5^uN~e4*rXn zvFuum<&=u&0xpQ0c>9~;HN?f+ml4k?5bvP+#yXIT<31;j&#R1ML(EoAEw=hqrqcK1 zD?P>{9}_*7L3i*}=-kpsV!#zJ7s{fOJ|#otiGR}mFx_am7&UKYghk2<>avb4q~fNT0(jU8>)*q`Dx z_NQ13FKdb6q?8s9a6#l~d9z7>%U|NOypgffq`*#Zt8e$Wa_#h06?l~-zcA8-lES^jv_^5^1~KbEn)S77;n>S)k&F=KhP7|SmeF92K+Iq^<5 z#k&v}??gsCzd*b}^?fyv>#Gw^U;SHUUtNgV%CE&%|8NK*77xcU|Cw)plNSj@{|X}- z)Ql)7jUEA9p>ok1Zbt7$JbFW!=miDQ`(8(H-iR4IsKwxRtaq&h=*;*MF?i^dDtB|6z;glQ`Os`M-RzuQVZl5;J~Oi}9hoou=Zi zD?al7P}HjVx*{$OBn4b@a)JD`C6JDIAV0|jGA;<@=jsFbSuT*DID!09Wgx%E1oAT{ zknUpwDfUlo(3Oe8m)fHM9kHT_Ybgp^8b}jxLF59dZV4n74`PDD5>Uho{54BJ#ik>x_rlsGp5W z*~gc$^|XFldlln)UJ0<mE^kei3#VwVLBHMYH9J~w^^-2H>vWrHtGoJP z5a!sT?5&{H)tcgTI5Zivq=1D0lDGIB?j}$WO+!hB8Nr z2?K@Ym`&%W^RV4)zz?y9B4rYgd3-+}r-vITnZBuP76Pt8CEgeq{(L|t7uy@AzL8VaV$9DAM;)8uz{ZLn16af`sSv1E0ufvFF} zQxp?#nykWRT9qseZ?#%GP~YjaV9T&y=!Vf#QKxO&oo>f6%;hT0`-S0U$MP12Z(A1r z_(kDbvgA9)hKC+3^K89XI#KVjNtl7M(<~ezGrjLton$kDjsuq`X7;*+F`|oPl%>;C zV3eQ$2_ByWn1wS##BLe|F*`cj_7Pov*c2mwmH-2-rrJzaOV3#M0JW(vH=vV7m?`)_ zP)h>@3IG5A2mpKxh*guO2+;(542V^edkNAGd<=+HSC42V^e iiwYV6IFqIdGX#7Lh*gu_3K{_ollTfZ2H^<+0000tjU3 Date: Mon, 8 Sep 2025 15:11:03 +1000 Subject: [PATCH 034/106] Re-analyze loop block inputs after each loop --- src/compiler/iroptimizer.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 15424a7263e..4e2941018d6 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -610,8 +610,9 @@ class IROptimizer { let keepLooping; do { const newState = state.clone(); - this.analyzeStack(stack, newState); - modified = keepLooping = state.or(newState); + modified = this.analyzeStack(stack, newState) || modified; + modified = (keepLooping = state.or(newState)) || modified; + modified = this.analyzeInputs(block.inputs, state) || modified; } while (keepLooping); block.entryState = state.clone(); return modified; From d8c73c71d255d1a9a6526b1cd7e3da8c077fac89 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:28:11 +1000 Subject: [PATCH 035/106] Account for `stop this script` in type analysis and add test --- src/compiler/iroptimizer.js | 27 +++++++++++++++++++++++++-- test/fixtures/tw-type-assertions.sb3 | Bin 5400 -> 5697 bytes 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 4e2941018d6..c17379102e8 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -129,6 +129,9 @@ class IROptimizer { this.ir = ir; /** @type {boolean} Used for testing */ this.ignoreYields = false; + + /** @private @type {TypeState | null} The state the analyzed script could exit in */ + this.exitState = null; } /** @@ -510,6 +513,18 @@ class IROptimizer { return modified; } + /** + * @param {TypeState} state + */ + addPossibleExitState (state) { + if (this.exitState === null) { + this.exitState = state.clone(); + return; + } + + this.exitState.or(state); + } + /** * @param {IntermediateStackBlock} stackBlock * @param {TypeState} state @@ -542,6 +557,10 @@ class IROptimizer { modified = state.or(trueState) || modified; break; } + case StackOpcode.CONTROL_STOP_SCRIPT: { + this.addPossibleExitState(state); + break; + } case StackOpcode.PROCEDURE_CALL: { modified = this.analyzeInputs(inputs.inputs, state) || modified; const script = this.ir.procedures[inputs.variant]; @@ -691,8 +710,12 @@ class IROptimizer { this.optimizeScript(this.ir.procedures[procVariant], alreadyOptimized); } - script.cachedAnalysisEndState = new TypeState(); - this.analyzeStack(script.stack, script.cachedAnalysisEndState); + this.exitState = null; + const exitState = new TypeState(); + this.analyzeStack(script.stack, exitState); + + this.addPossibleExitState(exitState); + script.cachedAnalysisEndState = this.exitState; this.optimizeStack(script.stack, new TypeState()); } diff --git a/test/fixtures/tw-type-assertions.sb3 b/test/fixtures/tw-type-assertions.sb3 index 29392ebe18ebd7d02e3b51aef8f8101cb342b93e..1c91c399a197b9e6f845024d0d46980b9baef1b6 100644 GIT binary patch delta 4499 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 From 7cc8f580b3e15b805ef5b1b441b190392cfcd49b Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Mon, 8 Sep 2025 17:08:23 +1000 Subject: [PATCH 036/106] Fix yielding loop arguments not re-analyzing --- src/compiler/iroptimizer.js | 4 +++- .../tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot | 2 +- .../tw-zombie-cube-escape-284516654.sb3.tw-snapshot | 2 +- .../tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot | 2 +- .../tw-zombie-cube-escape-284516654.sb3.tw-snapshot | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index c17379102e8..100f38900fa 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -620,11 +620,13 @@ class IROptimizer { */ analyzeLoopedStack (stack, state, block) { if (block.yields && !this.ignoreYields) { - const modified = state.clear(); + let modified = state.clear(); block.entryState = state.clone(); block.exitState = state.clone(); + modified = this.analyzeInputs(block.inputs, state) || modified; return this.analyzeStack(stack, state) || modified; } + let modified = false; let keepLooping; do { diff --git a/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot index e5108d03f52..8f918a81081 100644 --- a/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot @@ -18,7 +18,7 @@ const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_run_without_screen_r () { b0.value = ((daysSince2000() * 86400) + 3); runtime.ioDevices.clock.resetProjectTimer(); -while (!((runtime.ioDevices.clock.projectTimer() > 0.1) || ((daysSince2000() * 86400) > b0.value))) { +while (!((runtime.ioDevices.clock.projectTimer() > 0.1) || compareGreaterThan((daysSince2000() * 86400), b0.value))) { if (isStuck()) yield; } if (compareLessThan((daysSince2000() * 86400), b0.value)) { diff --git a/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot index 826f1e0058f..5a401185577 100644 --- a/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot @@ -10,7 +10,7 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, ",a.euo_AgQTxR+D^x0M0", null); b1.value = 0; b2.value = ""; -while (!(b2.value.toLowerCase() > "".toLowerCase())) { +while (!(("" + b2.value).toLowerCase() > "".toLowerCase())) { startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "step" }); yield; } diff --git a/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot index e5108d03f52..8f918a81081 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot @@ -18,7 +18,7 @@ const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_run_without_screen_r () { b0.value = ((daysSince2000() * 86400) + 3); runtime.ioDevices.clock.resetProjectTimer(); -while (!((runtime.ioDevices.clock.projectTimer() > 0.1) || ((daysSince2000() * 86400) > b0.value))) { +while (!((runtime.ioDevices.clock.projectTimer() > 0.1) || compareGreaterThan((daysSince2000() * 86400), b0.value))) { if (isStuck()) yield; } if (compareLessThan((daysSince2000() * 86400), b0.value)) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot index 826f1e0058f..5a401185577 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot @@ -10,7 +10,7 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, ",a.euo_AgQTxR+D^x0M0", null); b1.value = 0; b2.value = ""; -while (!(b2.value.toLowerCase() > "".toLowerCase())) { +while (!(("" + b2.value).toLowerCase() > "".toLowerCase())) { startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "step" }); yield; } From 7ed29f5801c4ad4399d852bf5b4f19244b13cc5b Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Mon, 8 Sep 2025 17:11:50 +1000 Subject: [PATCH 037/106] Fix sound dropdown playing wrong sound when sounds have a number name --- src/compiler/irgen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 5ff94513b1b..89a72949a73 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -548,7 +548,7 @@ class ScriptTreeGenerator { case 'sound_sounds_menu': // This menu is special compared to other menus -- it actually has an opcode function. - return this.createConstantInput(block.fields.SOUND_MENU.value); + return this.createConstantInput(block.fields.SOUND_MENU.value, true); case 'control_get_counter': return new IntermediateInput(InputOpcode.CONTROL_COUNTER, InputType.NUMBER_POS_INT | InputType.NUMBER_ZERO); From e1ad53e7f52debaa67649205c00eb9fea100284d Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sun, 14 Sep 2025 11:14:18 -0500 Subject: [PATCH 038/106] Add compatibility layer for extensions relying on old compiler (#264) The new compiler broke all the extensions doing compiler patches. We promised not to help them when those break but it seems enough people use those extensions that we sort of got forced into finding some solution, so this makes these changes: - The exports for the new compiler are now in `these_broke_before_and_will_break_again` - `i_will_not_ask_for_help_when_these_break` now returns some stubs that pretend to be the old compiler. It also emits an event so -gui can show a warning. - Focus is on compatibility & safety, not performance. There will be unnecessary casts and scripts marked as yielding. - Extensions that meet these assumptions should work without changes: - Extensions do not try to combine this compatibility layer with any APIs provided by the new compiler. - Extensions treat IR nodes received from descendSubstack and similar as opaque objects because they will be the new intermediate objects instead of { kind: "..." } - Extensions need to implement the JS generators for all AST node kinds they use. Can not rely on the default JS generator because those generators are expecting a different format than { kind: "..." } Lack of tests is intentional since this will be removed at some point when we have a proper API we can tell people to use --- src/compiler/enums.js | 2 + src/compiler/irgen.js | 21 ++ src/compiler/jsgen.js | 9 + src/compiler/old-compiler-compatibility.js | 349 +++++++++++++++++++++ src/virtual-machine.js | 21 +- 5 files changed, 399 insertions(+), 3 deletions(-) create mode 100644 src/compiler/old-compiler-compatibility.js diff --git a/src/compiler/enums.js b/src/compiler/enums.js index 5432aa4b78c..53b311886b2 100644 --- a/src/compiler/enums.js +++ b/src/compiler/enums.js @@ -103,6 +103,7 @@ const StackOpcode = { DEBUGGER: 'tw.debugger', VISUAL_REPORT: 'visualReport', COMPATIBILITY_LAYER: 'compat', + OLD_COMPILER_COMPATIBILITY_LAYER: 'oldCompiler', HAT_EDGE: 'hat.edge', HAT_PREDICATE: 'hat.predicate', @@ -201,6 +202,7 @@ const InputOpcode = { CAST_COLOR: 'cast.toColor', COMPATIBILITY_LAYER: 'compat', + OLD_COMPILER_COMPATIBILITY_LAYER: 'oldCompiler', LOOKS_BACKDROP_NUMBER: 'looks.backdropNumber', LOOKS_BACKDROP_NAME: 'looks.backdropName', diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 89a72949a73..e84cbc21e5a 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -14,6 +14,7 @@ const { IntermediateScript, IntermediateRepresentation } = require('./intermediate'); +const oldCompilerCompatiblity = require('./old-compiler-compatibility.js'); /** * @fileoverview Generate intermediate representations from Scratch blocks. @@ -96,6 +97,12 @@ class ScriptTreeGenerator { } } } + + this.oldCompilerStub = ( + oldCompilerCompatiblity.enabled ? + new oldCompilerCompatiblity.ScriptTreeGeneratorStub(this) : + null + ); } setProcedureVariant (procedureVariant) { @@ -199,6 +206,13 @@ class ScriptTreeGenerator { * @returns {IntermediateInput} Compiled input node for this input. */ descendInput (block, preserveStrings = false) { + if (this.oldCompilerStub) { + const oldCompilerResult = this.oldCompilerStub.descendInputFromNewCompiler(block); + if (oldCompilerResult) { + return oldCompilerResult; + } + } + switch (block.opcode) { case 'colour_picker': return this.createConstantInput(block.fields.COLOUR.value, true); @@ -593,6 +607,13 @@ class ScriptTreeGenerator { * @returns {IntermediateStackBlock} Compiled node for this block. */ descendStackedBlock (block) { + if (this.oldCompilerStub) { + const oldCompilerResult = this.oldCompilerStub.descendStackedBlockFromNewCompiler(block); + if (oldCompilerResult) { + return oldCompilerResult; + } + } + switch (block.opcode) { case 'control_all_at_once': // In Scratch 3, this block behaves like "if 1 = 1" diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 82f6caf839d..5008e6edbfa 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -6,6 +6,7 @@ const VariablePool = require('./variable-pool'); const jsexecute = require('./jsexecute'); const environment = require('./environment'); const {StackOpcode, InputOpcode, InputType} = require('./enums.js'); +const oldCompilerCompatibility = require('./old-compiler-compatibility.js'); // These imports are used by jsdoc comments but eslint doesn't know that /* eslint-disable no-unused-vars */ @@ -124,6 +125,8 @@ class JSGenerator { this.isInHat = false; this.debug = this.target.runtime.debug; + + this.oldCompilerStub = new oldCompilerCompatibility.JSGeneratorStub(this); } /** @@ -198,6 +201,9 @@ class JSGenerator { // Compatibility layer inputs never use flags. return `(${this.generateCompatibilityLayerCall(node, false)})`; + case InputOpcode.OLD_COMPILER_COMPATIBILITY_LAYER: + return this.oldCompilerStub.descendInputFromNewCompiler(block); + case InputOpcode.CONSTANT: if (block.isAlwaysType(InputType.NUMBER)) { if (typeof node.value !== 'number') throw new Error(`JS: '${block.type}' type constant had ${typeof node.value} type value. Expected number.`); @@ -540,6 +546,9 @@ class JSGenerator { break; } + case InputOpcode.OLD_COMPILER_COMPATIBILITY_LAYER: + return this.oldCompilerStub.descendStackedBlockFromNewCompiler(block); + case StackOpcode.HAT_EDGE: this.isInHat = true; this.source += '{\n'; diff --git a/src/compiler/old-compiler-compatibility.js b/src/compiler/old-compiler-compatibility.js new file mode 100644 index 00000000000..07a4086c557 --- /dev/null +++ b/src/compiler/old-compiler-compatibility.js @@ -0,0 +1,349 @@ +/** + * @fileoverview + * Reimplements a subset of the old (pre-September 2025) compiler + * to maintain compatibility with extensions patching the old compiler. + * + * Safety and compatibility is more important than performance. There may be + * unnecessary type casts and scripts may be marked as yielding even when they + * don't actually yield. Additionally, anything running in this compatibility layer + * is not expected to receive the performance benefits of the new compiler. + * + * These assumptions are made about extensions using this compatibility layer: + * - Extensions do not try to combine this compatibility layer with any APIs + * provided by the new compiler. + * - Extensions treat IR nodes received from descendSubstack and similar as + * opaque objects. + * - Extensions need to implement the JS generators for all AST node kinds + * they use. Can not rely on the default JS generator. + */ + +const {InputOpcode, InputType} = require('./enums'); +// eslint-disable-next-line no-unused-vars +const {IntermediateInput, IntermediateStackBlock, IntermediateStack} = require('./intermediate'); + +class IRGeneratorStub { + // Doesn't seem like extensions override anything, though the class may + // still need to exist to avoid type errors. +} + +class ScriptTreeGeneratorStub { + /** + * @param {import("./irgen").ScriptTreeGenerator} real + */ + constructor (real) { + /** + * @type {import("./irgen").ScriptTreeGenerator} + */ + this.real = real; + + this.fakeThis = { + thread: real.thread, + target: real.target, + blocks: real.blocks, + runtime: real.runtime, + stage: real.stage, + script: real.script, + + /** + * @param parentBlock Parent VM block. + * @param {string} inputName Name of input. + * @returns opaque object + */ + descendInputOfBlock (parentBlock, inputName) { + const node = real.descendInputOfBlock(parentBlock, inputName, true); + return node; + }, + + /** + * @param {*} parentBlock Parent VM block. + * @param {*} substackName Name of substack. + * @returns opaque object + */ + descendSubstack (parentBlock, substackName) { + const substack = real.descendSubstack(parentBlock, substackName); + return substack; + }, + + analyzeLoop () { + // TODO: not always necessary + real.script.yields = true; + } + }; + } + + /** + * Intended for extensions to override. + * Always call from `fakeThis` context. + * @param {{opcode: string}} block VM block + * @returns {{kind: string}} Node object from old compiler. + */ + descendInput (block) { // eslint-disable-line no-unused-vars + return null; + } + + /** + * Intended for extensions to override. + * Always call from `fakeThis` context. + * @param {{opcode: string}} block VM block + * @returns {{kind: string}} Node object from old compiler. + */ + descendStackedBlock (block) { // eslint-disable-line no-unused-vars + return null; + } + + /** + * @param block VM block + * @returns {IntermediateInput|null} + */ + descendInputFromNewCompiler (block) { + const node = this.descendInput.call(this.fakeThis, block); + if (node) { + return new IntermediateInput(InputOpcode.OLD_COMPILER_COMPATIBILITY_LAYER, InputType.ANY, { + oldNode: node + }, true); + } + return null; + } + + /** + * @param block VM block + * @returns {IntermediateStackBlock|null} + */ + descendStackedBlockFromNewCompiler (block) { + const node = this.descendStackedBlock.call(this.fakeThis, block); + if (node) { + return new IntermediateStackBlock(InputOpcode.OLD_COMPILER_COMPATIBILITY_LAYER, { + oldNode: node + }, true); + } + return null; + } +} + +// These are part of the old compiler's API. +const TYPE_NUMBER = 1; +const TYPE_STRING = 2; +const TYPE_BOOLEAN = 3; +const TYPE_UNKNOWN = 4; +const TYPE_NUMBER_NAN = 5; + +/** + * Part of the old compiler's API. + */ +class TypedInput { + /** + * @param {string} source JavaScript + * @param {number|IntermediateInput} typeOrIntermediate + */ + constructor (source, typeOrIntermediate) { + /** + * JavaScript. + * @type {string} + */ + this.source = source; + + if (typeOrIntermediate instanceof IntermediateInput) { + // Path used by the compatibility layer itself + + /** + * @type {IntermediateInput} + */ + this.intermediate = typeOrIntermediate; + + /** + * @type {number} See TYPE_* constants above + */ + this.type = TYPE_UNKNOWN; + } else { + // Path used by extensions + this.intermediate = null; + this.type = typeOrIntermediate; + } + } + + asNumber () { + return `(+${this.source} || 0)`; + } + + asNumberOrNaN () { + return `(+${this.source})`; + } + + asString () { + return `("" + ${this.source})`; + } + + asBoolean () { + return `toBoolean(${this.source})`; + } + + asColor () { + return this.asUnknown(); + } + + asUnknown () { + return this.source; + } + + asSafe () { + return this.asUnknown(); + } + + isAlwaysNumber () { + // TODO + return false; + } + + isAlwaysNumberOrNaN () { + // TODO + return false; + } + + isNeverNumber () { + // TODO + return false; + } +} + +/** + * Part of the old compiler's API. + */ +class VariablePool { + constructor (prefix) { + this.prefix = prefix; + this.count = 0; + } + + next () { + return `${this.prefix}${this.count++}`; + } +} + +/** + * Part of the old compiler's API. + */ +class Frame { + constructor (isLoop) { + this.isLoop = isLoop; + this.isLastBlock = false; + } +} + +class JSGeneratorStub { + /** + * @param {import("./jsgen")} real + */ + constructor (real) { + /** + * @type {import("./jsgen")} + */ + this.real = real; + + this.fakeThis = { + script: real.script, + ir: real.ir, + target: real.target, + + get frames () { + return real.frames; + }, + get currentFrame () { + return real.currentFrame; + }, + + get source () { + return real.source; + }, + set source (newSource) { + real.source = newSource; + }, + + localVariables: new VariablePool('oldCompilerLocal'), + + /** + * @param {IntermediateInput} intermediate + * @returns {void} output is concatenated in this.source + */ + descendInput (intermediate) { + const js = real.descendInput(intermediate); + return new TypedInput(js, intermediate); + }, + + /** + * @param {IntermediateStack} stack Stack of blocks. + * @param {Frame} frame New frame + */ + descendStack (stack, frame) { + real.descendStack(stack, frame); + }, + + yieldLoop: () => real.yieldLoop(), + yieldNotWarp: () => real.yieldNotWarp(), + yieldStuckOrNotWarp: () => real.yieldStuckOrNotWarp(), + yielded: () => real.yielded(), + requestRedraw: () => real.requestRedraw() + }; + } + + /** + * Intended for extensions to override. + * Always call from `fakeThis` context. + * @param {{kind: string}} node Old compiler AST node. + * @returns {TypedInput} Old compiler TypedInput. + */ + descendInput (node) { + throw new Error(`Unknown input: ${node.kind}`); + } + + /** + * Intended for extensions to override. + * Always call from `fakeThis` context. + * @param {{kind: string}} node Old compiler AST node. + */ + descendStackedBlock (node) { + throw new Error(`Unknown stacked block: ${node.kind}`); + } + + /** + * @param {IntermediateInput} intermediate + * @returns {string} JavaScript + */ + descendInputFromNewCompiler (intermediate) { + const oldNode = intermediate.inputs.oldNode; + const typedInput = this.descendInput.call(this.fakeThis, oldNode); + return typedInput.asSafe(); + } + + /** + * @param {IntermediateStackBlock} intermediate + * @returns {void} source property on real JSGenerator is modified directly + */ + descendStackedBlockFromNewCompiler (intermediate) { + const oldNode = intermediate.inputs.oldNode; + this.descendStackedBlock.call(this.fakeThis, oldNode); + } +} + +/** + * Part of old compiler's API. + */ +JSGeneratorStub.unstable_exports = { + TYPE_NUMBER, + TYPE_STRING, + TYPE_BOOLEAN, + TYPE_UNKNOWN, + TYPE_NUMBER_NAN, + VariablePool, + TypedInput, + Frame +}; + +const oldCompilerCompatibility = { + enabled: false, + IRGeneratorStub, + ScriptTreeGeneratorStub, + TypedInput, + JSGeneratorStub +}; + +module.exports = oldCompilerCompatibility; diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 9feb91a7c00..4a8f55cf613 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -223,9 +223,9 @@ class VirtualMachine extends EventEmitter { JSZip, Variable, - i_will_not_ask_for_help_when_these_break: () => { + these_broke_before_and_will_break_again: () => { console.warn('You are using unsupported APIs. WHEN your code breaks, do not expect help.'); - return ({ + return { JSGenerator: require('./compiler/jsgen.js'), IRGenerator: require('./compiler/irgen.js').IRGenerator, ScriptTreeGenerator: require('./compiler/irgen.js').ScriptTreeGenerator, @@ -239,7 +239,22 @@ class VirtualMachine extends EventEmitter { InputType: require('./compiler/enums.js').InputType, Thread: require('./engine/thread.js'), execute: require('./engine/execute.js') - }); + }; + }, + + i_will_not_ask_for_help_when_these_break: () => { + this.emit('LEGACY_EXTENSION_API', 'i_will_not_ask_for_help_when_these_break'); + + const oldCompilerCompatibility = require('./compiler/old-compiler-compatibility.js'); + oldCompilerCompatibility.enabled = true; + + return { + IRGenerator: oldCompilerCompatibility.IRGeneratorStub, + ScriptTreeGenerator: oldCompilerCompatibility.ScriptTreeGeneratorStub, + JSGenerator: oldCompilerCompatibility.JSGeneratorStub, + Thread: require('./engine/thread.js'), + execute: require('./engine/execute.js') + }; } }; } From 5b027b995e9a797a34f14ad444c3ce769f2912ee Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 15 Sep 2025 17:56:52 -0500 Subject: [PATCH 039/106] Fix motion_turnleft and motion_turnright missing type casts --- src/compiler/irgen.js | 4 ++-- ...-rotate-by-decimal-without-leading-zero.sb3 | Bin 0 -> 2784 bytes ...ecimal-without-leading-zero.sb3.tw-snapshot | 17 +++++++++++++++++ ...ecimal-without-leading-zero.sb3.tw-snapshot | 17 +++++++++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/execute/tw-rotate-by-decimal-without-leading-zero.sb3 create mode 100644 test/snapshot/__snapshots__/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index e84cbc21e5a..2a22749b345 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -865,14 +865,14 @@ class ScriptTreeGenerator { return new IntermediateStackBlock(StackOpcode.MOTION_DIRECTION_SET, { direction: new IntermediateInput(InputOpcode.OP_SUBTRACT, InputType.NUMBER, { left: new IntermediateInput(InputOpcode.MOTION_DIRECTION_GET, InputType.NUMBER), - right: this.descendInputOfBlock(block, 'DEGREES') + right: this.descendInputOfBlock(block, 'DEGREES').toType(InputType.NUMBER) }) }); case 'motion_turnright': return new IntermediateStackBlock(StackOpcode.MOTION_DIRECTION_SET, { direction: new IntermediateInput(InputOpcode.OP_ADD, InputType.NUMBER, { left: new IntermediateInput(InputOpcode.MOTION_DIRECTION_GET, InputType.NUMBER), - right: this.descendInputOfBlock(block, 'DEGREES') + right: this.descendInputOfBlock(block, 'DEGREES').toType(InputType.NUMBER) }) }); diff --git a/test/fixtures/execute/tw-rotate-by-decimal-without-leading-zero.sb3 b/test/fixtures/execute/tw-rotate-by-decimal-without-leading-zero.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..4b8c5e145296e691992db55f6540c239b6e163f8 GIT binary patch literal 2784 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 literal 0 HcmV?d00001 diff --git a/test/snapshot/__snapshots__/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot new file mode 100644 index 00000000000..d92f0cf7405 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot @@ -0,0 +1,17 @@ +// TW Snapshot +// Input SHA-256: 0a7a3ee1aac2ba5b063f53b742ef992e395ee668efa9205279f93f1949e8a755 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); +target.setDirection(90); +target.setDirection((target.direction + 0.25)); +target.setDirection((target.direction + 0.25)); +if ((target.direction === 90.5)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "i", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "h", null); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot new file mode 100644 index 00000000000..d92f0cf7405 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot @@ -0,0 +1,17 @@ +// TW Snapshot +// Input SHA-256: 0a7a3ee1aac2ba5b063f53b742ef992e395ee668efa9205279f93f1949e8a755 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); +target.setDirection(90); +target.setDirection((target.direction + 0.25)); +target.setDirection((target.direction + 0.25)); +if ((target.direction === 90.5)) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "i", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "h", null); +retire(); return; +}; }) From fa035541dae86a69cfc9f7ada69c9b79ce23dd2f Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 20 Sep 2025 13:41:23 -0500 Subject: [PATCH 040/106] Give up analyzing looped stack after 10000 iterations Temporary fix for an infinite loop, to be properly fixed later --- src/compiler/iroptimizer.js | 12 +++++++ ...cedure-reporter-infinite-analyzer-loop.sb3 | Bin 0 -> 35213 bytes ...ter-infinite-analyzer-loop.sb3.tw-snapshot | 29 +++++++++++++++++ ...ter-infinite-analyzer-loop.sb3.tw-snapshot | 30 ++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 test/fixtures/execute/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3 create mode 100644 test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 100f38900fa..f44dd730ce8 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -627,9 +627,21 @@ class IROptimizer { return this.analyzeStack(stack, state) || modified; } + let iterations = 0; let modified = false; let keepLooping; 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); + modified = state.clear(); + block.entryState = state.clone(); + block.exitState = state.clone(); + modified = this.analyzeInputs(block.inputs, state) || modified; + return this.analyzeStack(stack, state) || modified; + } + iterations++; + const newState = state.clone(); modified = this.analyzeStack(stack, newState) || modified; modified = (keepLooping = state.or(newState)) || modified; diff --git a/test/fixtures/execute/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3 b/test/fixtures/execute/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..1d91e7bc4db94f2ec92bdf34eb6ae9660b1fc418 GIT binary patch literal 35213 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 literal 0 HcmV?d00001 diff --git a/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot new file mode 100644 index 00000000000..2244a1bfbde --- /dev/null +++ b/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot @@ -0,0 +1,29 @@ +// TW Snapshot +// Input SHA-256: a12680688ca945364abe1e094b35cf53326f70189cb09b58d5f52b4de0c3b2a9 + +// Text script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a~", null); +thread.procedures["Wtest 1"](); +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "dh", null); +retire(); return; +}; }) + +// Text Wtest 1 +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = target.variables["ts-.PQ{/]mN_9@MbG:m/"]; +return function funXYZ_test_1 () { +for (var a0 = (+thread.procedures["Wany procedure reporter"]() || 0); a0 >= 0.5; a0--) { +b0.value = ((+b0.value || 0) + 1); +} +return ""; +}; }) + +// Text Wany procedure reporter +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +return function funXYZ_any_procedure_report () { +return 0; +return ""; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot new file mode 100644 index 00000000000..f3b5937c508 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot @@ -0,0 +1,30 @@ +// TW Snapshot +// Input SHA-256: a12680688ca945364abe1e094b35cf53326f70189cb09b58d5f52b4de0c3b2a9 + +// Text script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a~", null); +yield* thread.procedures["Wtest 1"](); +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "dh", null); +retire(); return; +}; }) + +// Text Wtest 1 +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = target.variables["ts-.PQ{/]mN_9@MbG:m/"]; +return function* genXYZ_test_1 () { +for (var a0 = (+thread.procedures["Wany procedure reporter"]() || 0); a0 >= 0.5; a0--) { +b0.value = ((+b0.value || 0) + 1); +if (isStuck()) yield; +} +return ""; +}; }) + +// Text Wany procedure reporter +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +return function funXYZ_any_procedure_report () { +return 0; +return ""; +}; }) From cc96ee8c70ac24b165dfe536d8b2f1b327011cfe Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 21 Sep 2025 22:59:06 +1000 Subject: [PATCH 041/106] Fix `-0` being turned into `0` in the type matrix test --- src/compiler/intermediate.js | 43 ++++++++++++++++++++- test/integration/tw_operator_type_matrix.js | 6 +-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/compiler/intermediate.js b/src/compiler/intermediate.js index 23c82cc8fe8..2a663145651 100644 --- a/src/compiler/intermediate.js +++ b/src/compiler/intermediate.js @@ -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. @@ -350,5 +390,6 @@ module.exports = { IntermediateInput, IntermediateStack, IntermediateScript, - IntermediateRepresentation + IntermediateRepresentation, + stringifyType }; diff --git a/test/integration/tw_operator_type_matrix.js b/test/integration/tw_operator_type_matrix.js index 2402067302c..035102fe037 100644 --- a/test/integration/tw_operator_type_matrix.js +++ b/test/integration/tw_operator_type_matrix.js @@ -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 = [ @@ -113,7 +113,7 @@ test('operator type matrix', async t => { 1, [ 4, - `${inputs[i]}` + `${Object.is(inputs[i], -0) ? '-0' : inputs[i]}` ] ]; } @@ -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)}.` ); }; From c16be2517896a0f825f494fd3b171b6de33eb7e8 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 21 Sep 2025 22:59:56 +1000 Subject: [PATCH 042/106] Fix #273 --- src/compiler/iroptimizer.js | 2 +- .../__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index f44dd730ce8..fe162349062 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -644,8 +644,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/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot index 224f800f45e..d2efe972b71 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(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)) { From 749e9233787baf51d6e0ce48e1766973cb0ee774 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 21 Sep 2025 23:10:50 +1000 Subject: [PATCH 043/106] Fix #272 (thanks @Geotale) --- src/compiler/iroptimizer.js | 34 ++++++++++--------- .../__snapshots__/tw-NaN.sb3.tw-snapshot | 6 ++-- ...s-515-non-finite-direction.sb3.tw-snapshot | 2 +- .../warp-timer/tw-NaN.sb3.tw-snapshot | 6 ++-- ...s-515-non-finite-direction.sb3.tw-snapshot | 2 +- 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index fe162349062..f20a47ea4f1 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -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 @@ -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; diff --git a/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot index 537fd7102ad..655a04a4e77 100644 --- a/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot @@ -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)) { diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot index 59991893cea..00bb8c4d3e3 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot @@ -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); } diff --git a/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot index 537fd7102ad..655a04a4e77 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot @@ -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)) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot index 59991893cea..00bb8c4d3e3 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot @@ -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); } From d17ceccd830188887ac2746b2c1fc720ffc91a52 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 21 Sep 2025 23:13:11 +1000 Subject: [PATCH 044/106] Fix #269 --- src/compiler/irgen.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 2a22749b345..8bc9897b97e 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -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, { @@ -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': From 41af457060a0814dfae161c61c6fa1507dfe6c27 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 22 Sep 2025 17:05:30 -0500 Subject: [PATCH 045/106] Move analyzeStackBlock analyzeInputs call into the switch statement Makes later commits easier. --- src/compiler/iroptimizer.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index f20a47ea4f1..d3bbbeaf000 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -541,18 +541,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 +561,12 @@ class IROptimizer { break; } case StackOpcode.CONTROL_STOP_SCRIPT: { + modified = this.analyzeInputs(inputs, state) || modified; this.addPossibleExitState(state); 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 +578,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 +587,9 @@ class IROptimizer { } break; } + default: + modified = this.analyzeInputs(inputs, state) || modified; + break; } return modified; From 44e2589e65fe2c4ed97bc6aa2f4ead75b8a72c50 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 22 Sep 2025 17:06:21 -0500 Subject: [PATCH 046/106] Fix https://github.com/TurboWarp/scratch-vm/issues/277 Need to clear the state before analyzing the condition as the condition may be re-evaluated after yielding. --- src/compiler/iroptimizer.js | 5 +++ .../tw-wait-until-condition-gh-277.sb3 | Bin 0 -> 2928 bytes ...ait-until-condition-gh-277.sb3.tw-snapshot | 34 ++++++++++++++++++ ...ait-until-condition-gh-277.sb3.tw-snapshot | 34 ++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 test/fixtures/execute/tw-wait-until-condition-gh-277.sb3 create mode 100644 test/snapshot/__snapshots__/tw-wait-until-condition-gh-277.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-wait-until-condition-gh-277.sb3.tw-snapshot diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index d3bbbeaf000..91ebd5cf46b 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -565,6 +565,11 @@ class IROptimizer { 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; 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 0000000000000000000000000000000000000000..a170d42f7370e5d81c336d3298b08a1c52dee520 GIT binary patch literal 2928 zcma);c{CL28^>qtJDIU>W8bokWlX}@%?y&zD50^HEEBTVFpOkNwu&T-U6w{9!jK}_ zuB=0mtdlKUR9yG`{SU$*MUW4ndaqMfP3$CoJ%}~`tkvx zXycZG%8%j4yw-ICVx9&;YT5^HivdXrgL3FuCtm!F1@&4zT zuyr3kMaFqTbmb&f{kErj?vE@ToC%-K-(A1;N^DQK4;W=wU`I#CzRa0?d&?)NJ0q@y zR@C9lQft#>-xTk+5{`v^qQWal|iwc)MGTQx&;wxSS=Nfl?>x$gLdXQQnK z>ZEwhV*IEjXlvn!%x(lMN zJiy3ASZxJE=&XH`G5aJkWKt|eKDHNC?w6#w3!|J@4(e=I6ACNwLhP!KKlxP1MQbAI zHBHg2x;ne0RML@?8;4r;mMN4z$%?sGRH`U~2v@2h?Bhdk?;oy3vxb*zGw6w`R<~X# z9;}Y3`b>!J{rKW5cLF+8U88?7P--))-+x4G z`n-)|iY@sI)_sALt>N^qn2-^O&^}{0%gEyTdGinP6*1f~J7R2l;SK}-dH-i@pI0}_|?R+~e zNIgZl`A39j)z|8p%h;oLUkf^KeWrgXE*|jW#;i>qBa;Q}kih`{xdhMZW+kw?hsFc` zZE95}KTVqv07zv2pD8#L=Ai?F!lBxpFf1JI1=H2gglTHKYw2pa>%gJVzf3)Kr213M zd4BN`7!&y+V|sdIa~ zT6$)zuXHnPQhc{ETl9I~+^RqR!gJVgaA^4T&5ey2@o}-#F#$>>9(dF>|LuC?H2$Z& zg;KHehf=?-+G#6TrDG4W2T5JOY+G30SGxLrV{7*M$U%Ro_rTi3?5}2; z*Qx5g(#p=wkde{e=?G!`QmmS)X-xr5@kvB#48H0xcc*@BeKd5guCdqQ$KoD-N}?pc zq4d)z^;iA0>(R5r)8gK9^T90=M?SfgtNvpW>!EWM(-OO`Z{`a8Y=$>CPQgbYE{nlG4Fqs_?K@)5LTPD}m{ zXR}>Gne=^i<*Rghs;|qFDEsLTn57o|RxT;n@SZj4lHFkw2thfyo2+2B6L`C>4yMP8 z3&2NTOe`vJ&fqu#03ZUKIJk|5t{#;7>SO1PS#PC_Dat=G+gFMq9Tbb|YX3?H-C88M zPU4xv+k_+puI%kKPt&O&rZS-m8(K7CUhAtcxTX0mPe#U|kd>kV6IW5BW%(9bQEF21j_Tcl|xFDP0Ha0?a0nC}EtVp38#@ zfaDPKc9wXcIBCa<$FV_3Q%eUkcaJf{LE!XlkK4A#rkbo$zR77M)c@BYLFu{~Q zuJ(^Y83^pP(wfk z_Q3{eBDt=L0c^K^b9XXr1jM_27u4BwKS=pXzFCqarp4z<|IH_yw$v>udXLAR#7gHpXS&CYxev^#rene}5M>`R+`uxi zrkMiLLzrrC2sVC}YBIlq@S*rU&|~+zbk4pfxbip+GPoKX>dFxg$R)uqX}-<*$>rmW zkTN$eK83-arJ5VwMT=$T&KI|nv-k_x%`Nmj?cbyiWK$A)4Sc2}>Yx@+#lFf11R@(8 zqAm%^O7-QoyVBx=4tG)gJtoGPgBZ4k^d5eWik%X?&ahm-v kRQkQ+?-2OABjYg|{tFUp(Tq%gspyaI$KyZhFQb4z0Uli<>i_@% literal 0 HcmV?d00001 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__/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; +}; }) From 5d917cca0580b9e5dcff5fdeeb95d8994859421f Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 22 Sep 2025 17:36:38 -0500 Subject: [PATCH 047/106] Use log.error instead of console.error --- src/compiler/iroptimizer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 91ebd5cf46b..73e348a6720 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 */ @@ -647,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(); From 2639653647652199f46995af0a7e1ad1d13dc1ee Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 22 Sep 2025 18:32:13 -0500 Subject: [PATCH 048/106] Revert "Fix #273" This reverts commit c16be2517896a0f825f494fd3b171b6de33eb7e8. Caused https://github.com/TurboWarp/scratch-vm/issues/276 --- src/compiler/iroptimizer.js | 2 +- .../__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 73e348a6720..97135787272 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -659,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/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)) { From 40715dc259e24d811514b6ca49597c03685d1c53 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 22 Sep 2025 18:32:21 -0500 Subject: [PATCH 049/106] Add test case for https://github.com/TurboWarp/scratch-vm/issues/276 --- .../tw-loop-condition-optimization-gh-276.sb3 | Bin 0 -> 3277 bytes ...dition-optimization-gh-276.sb3.tw-snapshot | 28 +++++++++++++++++ ...dition-optimization-gh-276.sb3.tw-snapshot | 29 ++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 test/fixtures/execute/tw-loop-condition-optimization-gh-276.sb3 create mode 100644 test/snapshot/__snapshots__/tw-loop-condition-optimization-gh-276.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-loop-condition-optimization-gh-276.sb3.tw-snapshot 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 0000000000000000000000000000000000000000..48099303ce15a5d8950c76836b2560cd7b0e4bf3 GIT binary patch literal 3277 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 literal 0 HcmV?d00001 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__/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 ""; +}; }) From 5a90e13981cb62201724fd16497bb64728405055 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 22 Sep 2025 18:37:42 -0500 Subject: [PATCH 050/106] Fix TypeState#after setting variable types to undefined If a variable existed in `this` but not in `other`, its resulting type would be set to undefined. Changing it to use the type from `this` seems to fix https://github.com/TurboWarp/scratch-vm/issues/273. --- src/compiler/iroptimizer.js | 2 +- .../tw-procedure-return-recursion.sb3.tw-snapshot | 6 +++--- .../tw-procedure-return-recursion.sb3.tw-snapshot | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 97135787272..6cadd77168d 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -94,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; }); } 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__/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"); From c372e925a52c20cc5410e7128d0c88e9ca8b6c60 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 22 Sep 2025 19:27:08 -0500 Subject: [PATCH 051/106] Add test case for 6a37fee3866cb96fbc054009b6b1f31bb9244cf9 --- .../tw-warp-loop-condition-analysis.sb3 | Bin 0 -> 3363 bytes ...rp-loop-condition-analysis.sb3.tw-snapshot | 39 +++++++++++++++++ ...rp-loop-condition-analysis.sb3.tw-snapshot | 40 ++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 test/fixtures/execute/tw-warp-loop-condition-analysis.sb3 create mode 100644 test/snapshot/__snapshots__/tw-warp-loop-condition-analysis.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-warp-loop-condition-analysis.sb3.tw-snapshot 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 0000000000000000000000000000000000000000..126857522d82ea44de2d6b67d6097a33716bdeb4 GIT binary patch literal 3363 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 Date: Mon, 22 Sep 2025 19:28:17 -0500 Subject: [PATCH 052/106] Add test case for 7cc8f580b3e15b805ef5b1b441b190392cfcd49b --- .../tw-non-warp-loop-condition-analysis.sb3 | Bin 0 -> 3185 bytes ...rp-loop-condition-analysis.sb3.tw-snapshot | 29 ++++++++++++++++++ ...rp-loop-condition-analysis.sb3.tw-snapshot | 29 ++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 test/fixtures/execute/tw-non-warp-loop-condition-analysis.sb3 create mode 100644 test/snapshot/__snapshots__/tw-non-warp-loop-condition-analysis.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-non-warp-loop-condition-analysis.sb3.tw-snapshot 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 0000000000000000000000000000000000000000..59c1cfcf66cee6cdfcb5254567d83f32845187be GIT binary patch literal 3185 zcma);c{CJ!7stmklWpv4vS#063}ftBVh}^oC|iS(eJvD?y{yT;reS1Fqz0+UBqW7s zY-2=Y%M!9h;q{*PkLP(h=RN27-E+_HoO^!vp7Z_V_x)U?B?BW1003YD__n-5UM(l~ zo&W*>iCh2x+i^80B+$pxJxs+XG%(=#CI7&$TAYW9&Slmwa_x!|0Ce8Zdk8Bc6L}9< zr~ z1ap1jDUDjy5{OZx&9pd+TIS3L+lr@7NkNvT0FKNF^=!QAGzd@aGQWZk&2P5#T) zXH<5|OWcg;Bp{kn*{LhI2wd|146ZX-JJp&*A<+sz4R_2kdPKUml;St4Q09P++Fl_S2<**^J{BwTijFcj z*q7Ll0)~Z0>RHJ739I5_a?k^`1`Dc&hb%|oLp{ekDio?qgWHqSxl6*_ z{8czmhVp8JjLRfSI4sE3({vpOtcp&7`V+2NQ|yheb-;96#8XNkl(tt8y8vad5Q3kS z)pi-;dSAc7pSx7e$uO+&Z0BB4->qjY`m+!@hTUQA#lx|*FXExkcvMXc49)Nd1Fh#>u<`pyXd`5WJ)YWuU*iOu1xE#xu-nU&gUH8x? z8C^AGNgrSUJ?$^@>zeBKdBk>suhNr%iY1p@j7xn;E^jQW%W=eA^g&EKvF4^-jJ~ka z1(l}V=Ym`R7QUc)vd@Dl;1YL>qHvnj`3G;>)e9XWn6C$~_#5{-Tluyw_bDPi8^>%f ztQRRzVQ9g~!LAfVe!Q)fS43W7mZ^YJ2xG1#M=TGgJXn&+RYtJvJ>EB^+Q44>>|B=1 zki8D;8EJg}2M_x6z^qSlZM=BaFh?<5P)I(K6T@B-b!Jr`!h$_@m)ze+W(?bh- zRVDO>m;ZT7_IPpL$y+I-EhpYKK;M)jYzBFrStMNS>Zlu}j9$(^k5MZO6dt8>;3?m1 zHtLl&3ej^+F24~rug_Ml&}Zk@X@>8u zC@wpSd)naJ)LzXRv-4KaY4a;Xp{QtJ>-8DyQXt3-cF3p?|N02a>}Dmfx@(CA{8QAb zR9U9RF$Gds|0fC#fq7`cAaIC=CkzdTV_;fp>M(T;cc>QBT@wz0{8!Xt2TB0t9OnUF z9597nd{jrLxw$Ku9zy$H%YX42)0)jQMPN@V%7k5#Kb*EeT^$@~4`UIX99XAatzG1?8g zRdt;kH^?J>)SD-cMzBUq0YijAU|Fy7-ofLaiMyUES zLOFOwbv=4|s4MD4n+tm>cH~oBw;C`iwiZsSrHbvicGGbF*25d?TuEzD2RgzxpTXFd z+wFhN+%9r)#2Wai^-)%#qGc=F0WDn|+F16dj%5KOJ+%GJ+GtN5C+E_0tqubN4g;$@ zO-GHwyTyk)jY4ON_0Ba-;mGaVVZ(k7t50I%vIQ-^`|)zCy*}$?UIKYUgUTj@+wJaF zpUziR^rqKQd0Uf8+RG|9A-Ukc zz90vl4q^)g@WjCr2e&LCtNT@cdgwVL=G$2!^0FnSdkV4m{mN5X8V6ZCw-@lP6W9}x zuZ6?}uI=u&Q|XlrCvzb4>(J%IQsS!!xcRx;oWUr= zAoKJLnNwQU7^WCWBW{X17Bh``vXgi%jHl)VQ}rD|Z_Q;?IAlylBu5gw`YUZ0NX$72 za&WJ+5z4%l0-RDcC@9^F%F`Fiv|cv~q7m5-mse6Ex~;N!B!R;D$uA3r#!*UC&&B~UMYuJuPh1S2V%6!BLRIlq<7g*L(R z;(WyzG(En9Rc@@j4<2s8^SO8M^b{Uz%JJ2f?i|sO6b!?&q4P&Q2BI44fLQO#zg57#_MPhbEXL( z>jvmakRb~{Q$sVq+{r`H`#cZa@6kK?aj}`ZlF$*ue#HHG6eeE!@TT^gh|-|$P2K?yW zIMK*RTtkUy7n)mL*&maAC&MtE^Ud!_2~@ErU;Ty92jKYovOUPN&0t>AbS*~|ssJ{n z0P+2hzobn6B77kg6M4}!4(KXBlh_qT;C)#{ca6lS6;CsT~{nzoF8f i6aR$3UlTzf0N~#s0ci<5ehC0D9LLo09es=w0N_8jvX`I$ literal 0 HcmV?d00001 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__/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; +}; }) From 214b86a063f72c4a126bb47d77a56049cb398e48 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 22 Sep 2025 19:29:06 -0500 Subject: [PATCH 053/106] Add test case for d8c73c71d255d1a9a6526b1cd7e3da8c077fac89 --- ...-analysis-understands-stop-this-script.sb3 | Bin 0 -> 3262 bytes ...derstands-stop-this-script.sb3.tw-snapshot | 30 ++++++++++++++++++ ...derstands-stop-this-script.sb3.tw-snapshot | 30 ++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 test/fixtures/execute/tw-state-analysis-understands-stop-this-script.sb3 create mode 100644 test/snapshot/__snapshots__/tw-state-analysis-understands-stop-this-script.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-state-analysis-understands-stop-this-script.sb3.tw-snapshot 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 0000000000000000000000000000000000000000..735f45d77caa48a86c503a91a37b36a1dee968fb GIT binary patch literal 3262 zcma);c{CJ!7srQ;eT%_J_K1`;&0w;ReT%GPXBcE(Bij@a%D%-|B0FI$BTFJXg_5xh zN|Pm;5JSoGde8gE^E{pNp7Z?fx#ym9&+p!IzW;nb*I54y4I=;mpa*!i4jJoyu}7Ez z0RYrl0D$?l>lfhbfp!j(_6YR#d1+}A@>!PsSgPvay;86h@yUih)^MgUKh=eA$UaZK zs=en3dx zbbS2y4Z`$|sA8gIZ6pGNAsa;P94CFpM5z3tRIHG&lPOsa>9fPAv-uB4Oqu$TI?#rR zZ^TYY8ULM*y`rKUD1ldJRZfa6NI$8@`x4sES!}%OIgi&wtn*#1mliD8k`;_y@FlP< z^f(-aD76?}Q6(s)lO$N)sgim9;}TNdYQa)+RU`+L^*QpSyMDq~WfYtdD|%KoS0
ROiMLqst~xX&NKW&c~nw* z`9mjvgvahJfd)K^b=3gHi`!-PGdbpMu^V5^j8gNixINy}9=$AiYsN_tjk6fRd83bc zm*w(}>sm6Q!(fkTC;23LbY!w=nv+bNiaL1?!Q7QI0=R6hOf?@#7?q$5+U3W!t?1&0KPh^;P20u0C0*IN9 z)AV?bbDf9=3%3hqYK%CIKX7!*9}JMhbSs)xRIS44Iz!(wD(j26ZObrP*bBSotgn4r zIXEoA_y@AM+c8C&FBOOE*G;P^bwEYJUSu>o*4>m8Me!~pAHKQxDxM2_0i>2@RcRWz>0adBw)Xlw`)~Pk#U4y9m!Z#aEfx zR~fWtv2Bu1U!={uh2V$GFs->CC*dTJPxn0sQejzUP=3U&Ee+i;Yv8-V$?taBzv=pi zp3E#ZT&-<;DIYmaRvgz1Z<>y>siemj+9-h?b&&d$uVf${4m0TEi~UWtn)-Eq6HwKUr1YR(`Sd)=m&;iCyW0z3(g z_g@=KQz@?LE*B&wqc(mvR-;F%Jk^ZQ6YFMv#8*C2TVy*VACdgBgtgJmo{K0vImaQRbbEC0LP-6E_n!s2pNhm`M?St)-U<(5AT=NHnx(Mei z!MUEJ8eFze%MhDkq6o!;tb+K^@6(qSL4$A@J~Tf5yeDM<$~b7krnZqsXvaITFVsrD zuo;~Zn=ko+iF*OsuynUv?zXNvyJi$a}D&irczc1at(G3 z>LLTXe$Caz)fEMSKxCk38MHGD?II6#k`BD%=546Y8Y2Xn4^NzKrR%GMzAn)1S+diF7#2eWC|SjFMZ>TXYiLSm%lBsARgg*9W%U`Ftio{lE^+7>lV4mppd)%+gn?o z1ZMb?r+Iq9F;pl0%Rl^E7chqxwJ(*~eyH%?X;?6jtFai?9o8kTxX#;uG#JtxE;BA^ zep^BQxwW(8KXot`;x_($cIl{N!}Uhpenn01_MIuh=t9^z%v#Jp{hNIKZ5jzlZi+7)QMuoxe=7$@)HP8#_3vB!H2yjQVGTDZmHsSZleq?ZM`{(f`@ zSns1I6L z_?8$tV35u!0_4j{=zQ{ic2}IfK8_9gLr#cBx3sj+Zi`_OMK#qODKm7STS8NK-!HmQ z!T(KcTe>XDo+`Vvv?r8>fc`om0eE~ztD8QKN}!Ztz;1!(y$+Q{lG1<~<~)iIT^<_W zGXgNu2>C{^CaZ?OuF8w1nTXdo^Pu5<$ps-06w7EZo&Vyjs46vrxiV8E`GPsUz~i9= z#mujaS+&GTVhf2*ECQnFMB4mW|!Zc$lo3#Qys5t}qfS z%T;R{SjZBSc5%>Ht%(KH^QoFG0{KL4@e;)IP0soi>h_S;N3M6x9HM~^l1s7uK_t$% zIx1XWgiRrjxE%Q)pyfjsF!yv~iz?C!$@yzHNads}Y5s)aQ$OWLO3L~^=8UmE6*UO( z|8MzIp#1Iq{j&da@=p%^H5PSh Date: Mon, 22 Sep 2025 19:30:23 -0500 Subject: [PATCH 054/106] Add test case for 7ed29f5801c4ad4399d852bf5b4f19244b13cc5b --- ...avoids-number-literal-if-name-conflict.sb3 | Bin 0 -> 2035 bytes ...r-literal-if-name-conflict.sb3.tw-snapshot | 21 ++++++++++++++++++ ...r-literal-if-name-conflict.sb3.tw-snapshot | 21 ++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 test/fixtures/execute/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3 create mode 100644 test/snapshot/__snapshots__/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-sound-menu-avoids-number-literal-if-name-conflict.sb3.tw-snapshot 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 0000000000000000000000000000000000000000..ce978f1954e0192d3a7d2bc9941df72e9e62949e GIT binary patch literal 2035 zcma)-cTm&W7RP_|P#4zhQk0@}1YSrXVNpPE3DUcZfFy)OAQTq}eU~B$y^KLXq%1{N zjDi%Y@}w70L}Hevp+tBrgoh-oNHZ_9vor28^Jctv&L8*AJ>NT@bIzROY$qfv0RR99 zAhwS>+fDe6;DiByB?kaf{M+jh;lX%ZlwojWco?I^H*(n+OyNn?Fk4}U+t(~Rf-dz( zLme>Mz5k7FR@C!u-ag}b{wtcJys*jTq~Z|)T1^U-p-m(O3-5`OI%rw1d~(gfl<7Y#4? zvR`B_W(su6>2He}p3$#T_Z6N@qZdAl6eQ)BP;fIBWAq2K|GiaOS3mFmYlYRNkzokx zj7(2)LQbfBwxnT`R9vD&nS0^|U;1yAZJ$!QtkHhVK%EsYd$4JteA$Y%;&=9#k11JI zYVPkmZIv`nk-nWlftZ|h~y|^mmufm>rk{5o`S=Aa% zwY9>Q1<<}fDuB8c(G|50!*ccFA_Ryn91=|=f?9!u zL4~?y>3 zQ)#Pn$&#SAz|~p&s+e|o+b=!3IG?Q!RJM;EXZ$_|agVfwiHMteS}GGyKAC;D;-LB4 zY`BTE0z>(Qtxn%c|DEmvWInOk$)}j8aFC8B*e3@A+i6Q<^yy{dG`zLg-AxPjkUbE5xlJtDYh{gcs?5l=_-0Ry&6}BqB1?Qsc?Q zJP(gWHJwj%oyNgiuIhWgT#+L@Ad|n=)6PI8@;Y=Dc9Wf0VC!Pis66*j_wFl8>}lG= zcG4dlO1{d}JmG2zGTvuhXhEWW$CYX;p95Rsy!=69vRu55Bcw}hO}MV+@ltuGwG$*W z8PRzt=KPOllrbSIK;<`~XMEG(8!iB9gfM~!KoBq^LI8o_4~0S@a6AN$L*N5YaI9fu z^tDh2JDD45;5P|b)9qq|4e@; zA7l4wP*5xZPC&vDus@;lUP#=4$fo&evO7x$E5NKi zq+Ds`P)T73q|Ir;{R#M)N;G9pfl&Ll*;l(?0X*s{Xlkr#lQO<%a{a1p(0EVo7{?LR zcQ)ztz>?7ep2h6$d2=_6i0Z7aY;T$M21hsMH9il`Xy;;-3}9*)_`~1enKD*`e$KRJ!+Hu9>iT$kT nF9HBxlIG)z$3yv9(NYuuz9g{Db|U Date: Mon, 22 Sep 2025 19:35:06 -0500 Subject: [PATCH 055/106] Use Object.create(null) instead of {} Avoids any weird issues if variables have strange IDs like "toString" --- src/compiler/iroptimizer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 6cadd77168d..416f1c3e060 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -17,7 +17,7 @@ const { class TypeState { constructor () { /** @type {Object.}*/ - this.variables = {}; + this.variables = Object.create(null); } /** @@ -31,7 +31,7 @@ class TypeState { break; } } - this.variables = {}; + this.variables = Object.create(null); return modified; } From 2244b26773ca958613873b33dc23681775d9f963 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 24 Sep 2025 16:48:01 -0500 Subject: [PATCH 056/106] Discard old state after calling yielding procedure --- src/compiler/iroptimizer.js | 12 ++++++ ...analyze-yields-due-to-direct-recursion.sb3 | Bin 0 -> 3330 bytes ...tate-accounts-for-yields-in-procedures.sb3 | Bin 0 -> 3243 bytes ...ds-due-to-direct-recursion.sb3.tw-snapshot | 39 ++++++++++++++++++ ...s-for-yields-in-procedures.sb3.tw-snapshot | 38 +++++++++++++++++ ...procedure-return-recursion.sb3.tw-snapshot | 4 +- ...ds-due-to-direct-recursion.sb3.tw-snapshot | 39 ++++++++++++++++++ ...s-for-yields-in-procedures.sb3.tw-snapshot | 38 +++++++++++++++++ ...procedure-return-recursion.sb3.tw-snapshot | 4 +- 9 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/execute/tw-analyze-yields-due-to-direct-recursion.sb3 create mode 100644 test/fixtures/execute/tw-exit-state-accounts-for-yields-in-procedures.sb3 create mode 100644 test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 416f1c3e060..ae7d98e495f 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -99,6 +99,14 @@ class TypeState { }); } + /** + * @param {TypeState} other + * @returns {boolean} + */ + overwrite (other) { + return this.mutate(other, varId => other.variables[varId] ?? InputType.ANY); + } + /** * @param {*} variable A variable codegen object. * @param {InputType} type The type to set this variable to @@ -490,6 +498,8 @@ class IROptimizer { if (!script || !script.cachedAnalysisEndState) { modified = state.clear() || modified; + } else if (script.yields) { + modified = state.overwrite(script.cachedAnalysisEndState) || modified; } else { modified = state.after(script.cachedAnalysisEndState) || modified; } @@ -578,6 +588,8 @@ class IROptimizer { if (!script || !script.cachedAnalysisEndState) { modified = state.clear() || modified; + } else if (script.yields) { + modified = state.overwrite(script.cachedAnalysisEndState) || modified; } else { modified = state.after(script.cachedAnalysisEndState) || modified; } diff --git a/test/fixtures/execute/tw-analyze-yields-due-to-direct-recursion.sb3 b/test/fixtures/execute/tw-analyze-yields-due-to-direct-recursion.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..136864b417e341ade429b75c618475aca7379c65 GIT binary patch literal 3330 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 XAi>lCc<~bept-p77oFvw5eM)O$|&Lp literal 0 HcmV?d00001 diff --git a/test/fixtures/execute/tw-exit-state-accounts-for-yields-in-procedures.sb3 b/test/fixtures/execute/tw-exit-state-accounts-for-yields-in-procedures.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..6d194449637014725c30803b67f292eeb3ef212b GIT binary patch literal 3243 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 literal 0 HcmV?d00001 diff --git a/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot new file mode 100644 index 00000000000..c19e45f7049 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot @@ -0,0 +1,39 @@ +// TW Snapshot +// Input SHA-256: 848a4efc16b174b53f0a4b581e6b6d1091ae9eaa916e040c963e360ce3883509 + +// 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["FpLI$ida6)qR,q~y`1|*"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "j", null); +b1.value = (1 + 2); +yield* thread.procedures["Znon-warp recursion %s"](2); +if ((("" + listGet(b2.value, b1.value)).toLowerCase() === "the only thing".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "t", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "s", null); +retire(); return; +}; }) + +// Sprite1 Znon-warp recursion %s +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +return function* genXYZ_non_warp_recursion_ (p0) { +if (compareGreaterThan(p0, 0)) { +yield; +yield* thread.procedures["Znon-warp recursion %s"](((+p0 || 0) - 1)); +} +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 () { +for (var a0 = 1; a0 >= 0.5; a0--) { +yield; +} +b0.value = "random"; +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot new file mode 100644 index 00000000000..c8bf63116b7 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot @@ -0,0 +1,38 @@ +// TW Snapshot +// Input SHA-256: 4715c75fe8effcdcdea3ad810949e33a7b6beb3fbd253c1edc2ed4f2bd093df3 + +// 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["FpLI$ida6)qR,q~y`1|*"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); +b1.value = (1 + 2); +yield* thread.procedures["Zsomething that yields"](); +if ((("" + listGet(b2.value, b1.value)).toLowerCase() === "the only thing".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "o", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null); +retire(); return; +}; }) + +// Sprite1 Zsomething that yields +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +return function* genXYZ_something_that_yield () { +for (var a0 = 2; a0 >= 0.5; a0--) { +yield; +} +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 () { +for (var a0 = 1; a0 >= 0.5; a0--) { +yield; +} +b0.value = "random"; +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 6b2bc2a9f60..c242a148a32 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot @@ -10,7 +10,7 @@ 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 === 4)) { +if (((+b1.value || 0) === 4)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp recursion yields",}, b0, false, false, "ao", null); } b1.value = 0; @@ -20,7 +20,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass warp recursion does not yiel } b1.value = 0; b2.value = (yield* thread.procedures["Zfib %s"](7)); -if ((b1.value === 20)) { +if (((+b1.value || 0) === 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-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot new file mode 100644 index 00000000000..c19e45f7049 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot @@ -0,0 +1,39 @@ +// TW Snapshot +// Input SHA-256: 848a4efc16b174b53f0a4b581e6b6d1091ae9eaa916e040c963e360ce3883509 + +// 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["FpLI$ida6)qR,q~y`1|*"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "j", null); +b1.value = (1 + 2); +yield* thread.procedures["Znon-warp recursion %s"](2); +if ((("" + listGet(b2.value, b1.value)).toLowerCase() === "the only thing".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "t", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "s", null); +retire(); return; +}; }) + +// Sprite1 Znon-warp recursion %s +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +return function* genXYZ_non_warp_recursion_ (p0) { +if (compareGreaterThan(p0, 0)) { +yield; +yield* thread.procedures["Znon-warp recursion %s"](((+p0 || 0) - 1)); +} +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 () { +for (var a0 = 1; a0 >= 0.5; a0--) { +yield; +} +b0.value = "random"; +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot new file mode 100644 index 00000000000..c8bf63116b7 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot @@ -0,0 +1,38 @@ +// TW Snapshot +// Input SHA-256: 4715c75fe8effcdcdea3ad810949e33a7b6beb3fbd253c1edc2ed4f2bd093df3 + +// 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["FpLI$ida6)qR,q~y`1|*"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); +b1.value = (1 + 2); +yield* thread.procedures["Zsomething that yields"](); +if ((("" + listGet(b2.value, b1.value)).toLowerCase() === "the only thing".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "o", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null); +retire(); return; +}; }) + +// Sprite1 Zsomething that yields +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +return function* genXYZ_something_that_yield () { +for (var a0 = 2; a0 >= 0.5; a0--) { +yield; +} +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 () { +for (var a0 = 1; a0 >= 0.5; a0--) { +yield; +} +b0.value = "random"; +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 6b2bc2a9f60..c242a148a32 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,7 +10,7 @@ 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 === 4)) { +if (((+b1.value || 0) === 4)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp recursion yields",}, b0, false, false, "ao", null); } b1.value = 0; @@ -20,7 +20,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass warp recursion does not yiel } b1.value = 0; b2.value = (yield* thread.procedures["Zfib %s"](7)); -if ((b1.value === 20)) { +if (((+b1.value || 0) === 20)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp fib yielded",}, b0, false, false, "au", null); } yield* thread.procedures["Zrecursing yields between each %s"]("initial"); From aafaa74d9ab239a52404907a710acebcd6ba5745 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 24 Sep 2025 17:18:34 -0500 Subject: [PATCH 057/106] Replace isNaN with Number.isNaN in jsexecute --- src/compiler/jsexecute.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/compiler/jsexecute.js b/src/compiler/jsexecute.js index e8139245512..1f7847a3794 100644 --- a/src/compiler/jsexecute.js +++ b/src/compiler/jsexecute.js @@ -278,12 +278,12 @@ baseRuntime += `const isNotActuallyZero = val => { */ baseRuntime += `const compareEqualSlow = (v1, v2) => { const n1 = +v1; - if (isNaN(n1) || (n1 === 0 && isNotActuallyZero(v1))) return ('' + v1).toLowerCase() === ('' + v2).toLowerCase(); + if (Number.isNaN(n1) || (n1 === 0 && isNotActuallyZero(v1))) return ('' + v1).toLowerCase() === ('' + v2).toLowerCase(); const n2 = +v2; - if (isNaN(n2) || (n2 === 0 && isNotActuallyZero(v2))) return ('' + v1).toLowerCase() === ('' + v2).toLowerCase(); + if (Number.isNaN(n2) || (n2 === 0 && isNotActuallyZero(v2))) return ('' + v1).toLowerCase() === ('' + v2).toLowerCase(); return n1 === n2; }; -const compareEqual = (v1, v2) => (typeof v1 === 'number' && typeof v2 === 'number' && !isNaN(v1) && !isNaN(v2) || v1 === v2) ? v1 === v2 : compareEqualSlow(v1, v2);`; +const compareEqual = (v1, v2) => (typeof v1 === 'number' && typeof v2 === 'number' && !Number.isNaN(v1) && !Number.isNaN(v2) || v1 === v2) ? v1 === v2 : compareEqualSlow(v1, v2);`; /** * Determine if one value is greater than another. @@ -299,14 +299,14 @@ runtimeFunctions.compareGreaterThan = `const compareGreaterThanSlow = (v1, v2) = } else if (n2 === 0 && isNotActuallyZero(v2)) { n2 = NaN; } - if (isNaN(n1) || isNaN(n2)) { + if (Number.isNaN(n1) || Number.isNaN(n2)) { const s1 = ('' + v1).toLowerCase(); const s2 = ('' + v2).toLowerCase(); return s1 > s2; } return n1 > n2; }; -const compareGreaterThan = (v1, v2) => typeof v1 === 'number' && typeof v2 === 'number' && !isNaN(v1) ? v1 > v2 : compareGreaterThanSlow(v1, v2)`; +const compareGreaterThan = (v1, v2) => typeof v1 === 'number' && typeof v2 === 'number' && !Number.isNaN(v1) ? v1 > v2 : compareGreaterThanSlow(v1, v2)`; /** * Determine if one value is less than another. @@ -322,14 +322,14 @@ runtimeFunctions.compareLessThan = `const compareLessThanSlow = (v1, v2) => { } else if (n2 === 0 && isNotActuallyZero(v2)) { n2 = NaN; } - if (isNaN(n1) || isNaN(n2)) { + if (Number.isNaN(n1) || Number.isNaN(n2)) { const s1 = ('' + v1).toLowerCase(); const s2 = ('' + v2).toLowerCase(); return s1 < s2; } return n1 < n2; }; -const compareLessThan = (v1, v2) => typeof v1 === 'number' && typeof v2 === 'number' && !isNaN(v2) ? v1 < v2 : compareLessThanSlow(v1, v2)`; +const compareLessThan = (v1, v2) => typeof v1 === 'number' && typeof v2 === 'number' && !Number.isNaN(v2) ? v1 < v2 : compareLessThanSlow(v1, v2)`; /** * Generate a random integer. From bbfa559972cc30e9f6cdd995cc4d5c642d1e538b Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:22:03 +1000 Subject: [PATCH 058/106] Fix sensing size of type --- src/compiler/irgen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 8bc9897b97e..09ece34548f 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -540,7 +540,7 @@ class ScriptTreeGenerator { case 'costume name': return new IntermediateInput(InputOpcode.SENSING_OF_COSTUME_NAME, InputType.STRING, {object}); case 'size': - return new IntermediateInput(InputOpcode.SENSING_OF_SIZE, InputType.NUMBER_POS_REAL, {object}); + return new IntermediateInput(InputOpcode.SENSING_OF_SIZE, InputType.NUMBER_POS, {object}); } } From bc9a3d03b1b85305801a7ce8741023938dd2e8a7 Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:29:50 +1000 Subject: [PATCH 059/106] Fix sensing x/y of types --- src/compiler/irgen.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 09ece34548f..66997be19b0 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -530,9 +530,9 @@ class ScriptTreeGenerator { } else { switch (property) { case 'x position': - return new IntermediateInput(InputOpcode.SENSING_OF_POS_X, InputType.NUMBER_REAL, {object}); + return new IntermediateInput(InputOpcode.SENSING_OF_POS_X, InputType.NUMBER, {object}); case 'y position': - return new IntermediateInput(InputOpcode.SENSING_OF_POS_Y, InputType.NUMBER_REAL, {object}); + return new IntermediateInput(InputOpcode.SENSING_OF_POS_Y, InputType.NUMBER, {object}); case 'direction': return new IntermediateInput(InputOpcode.SENSING_OF_DIRECTION, InputType.NUMBER_REAL, {object}); case 'costume #': From 8fe321c357b75dda23ab1c10dca57991606d44de Mon Sep 17 00:00:00 2001 From: Tacodiva <27910867+Tacodiva@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:30:32 +1000 Subject: [PATCH 060/106] Make types for blocks which returns ints more spercific --- src/compiler/irgen.js | 26 +++++++++---------- .../tw-gh-249-quicksort.sb3.tw-snapshot | 2 +- .../tw-gh-249-quicksort.sb3.tw-snapshot | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 8bc9897b97e..f6b8f85c67a 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -262,7 +262,7 @@ class ScriptTreeGenerator { index: this.descendInputOfBlock(block, 'INDEX') }); case 'data_lengthoflist': - return new IntermediateInput(InputOpcode.LIST_LENGTH, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO, { + return new IntermediateInput(InputOpcode.LIST_LENGTH, InputType.NUMBER_POS_INT | InputType.NUMBER_ZERO, { list: this.descendVariable(block, 'LIST', LIST_TYPE) }); case 'data_listcontainsitem': @@ -271,7 +271,7 @@ class ScriptTreeGenerator { item: this.descendInputOfBlock(block, 'ITEM') }); case 'data_itemnumoflist': - return new IntermediateInput(InputOpcode.LIST_INDEX_OF, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO, { + return new IntermediateInput(InputOpcode.LIST_INDEX_OF, InputType.NUMBER_POS_INT | InputType.NUMBER_ZERO, { list: this.descendVariable(block, 'LIST', LIST_TYPE), item: this.descendInputOfBlock(block, 'ITEM') }); @@ -290,12 +290,12 @@ class ScriptTreeGenerator { case 'looks_backdropnumbername': if (block.fields.NUMBER_NAME.value === 'number') { - return new IntermediateInput(InputOpcode.LOOKS_BACKDROP_NUMBER, InputType.NUMBER_POS_REAL); + return new IntermediateInput(InputOpcode.LOOKS_BACKDROP_NUMBER, InputType.NUMBER_POS_INT); } return new IntermediateInput(InputOpcode.LOOKS_BACKDROP_NAME, InputType.STRING); case 'looks_costumenumbername': if (block.fields.NUMBER_NAME.value === 'number') { - return new IntermediateInput(InputOpcode.LOOKS_COSTUME_NUMBER, InputType.NUMBER_POS_REAL); + return new IntermediateInput(InputOpcode.LOOKS_COSTUME_NUMBER, InputType.NUMBER_POS_INT); } return new IntermediateInput(InputOpcode.LOOKS_COSTUME_NAME, InputType.STRING); case 'looks_size': @@ -482,13 +482,13 @@ class ScriptTreeGenerator { }); case 'sensing_current': switch (block.fields.CURRENTMENU.value.toLowerCase()) { - case 'year': return new IntermediateInput(InputOpcode.SENSING_TIME_YEAR, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); - case 'month': return new IntermediateInput(InputOpcode.SENSING_TIME_MONTH, InputType.NUMBER_POS_REAL); - case 'date': return new IntermediateInput(InputOpcode.SENSING_TIME_DATE, InputType.NUMBER_POS_REAL); - case 'dayofweek': return new IntermediateInput(InputOpcode.SENSING_TIME_WEEKDAY, InputType.NUMBER_POS_REAL); - case 'hour': return new IntermediateInput(InputOpcode.SENSING_TIME_HOUR, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); - case 'minute': return new IntermediateInput(InputOpcode.SENSING_TIME_MINUTE, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); - case 'second': return new IntermediateInput(InputOpcode.SENSING_TIME_SECOND, InputType.NUMBER_POS_REAL | InputType.NUMBER_ZERO); + case 'year': return new IntermediateInput(InputOpcode.SENSING_TIME_YEAR, InputType.NUMBER_POS_INT | InputType.NUMBER_ZERO); + case 'month': return new IntermediateInput(InputOpcode.SENSING_TIME_MONTH, InputType.NUMBER_POS_INT); + case 'date': return new IntermediateInput(InputOpcode.SENSING_TIME_DATE, InputType.NUMBER_POS_INT); + case 'dayofweek': return new IntermediateInput(InputOpcode.SENSING_TIME_WEEKDAY, InputType.NUMBER_POS_INT); + case 'hour': return new IntermediateInput(InputOpcode.SENSING_TIME_HOUR, InputType.NUMBER_POS_INT | InputType.NUMBER_ZERO); + case 'minute': return new IntermediateInput(InputOpcode.SENSING_TIME_MINUTE, InputType.NUMBER_POS_INT | InputType.NUMBER_ZERO); + case 'second': return new IntermediateInput(InputOpcode.SENSING_TIME_SECOND, InputType.NUMBER_POS_INT | InputType.NUMBER_ZERO); default: return this.createConstantInput(0); } case 'sensing_dayssince2000': @@ -523,7 +523,7 @@ class ScriptTreeGenerator { switch (property) { case 'background #': // fallthrough for scratch 1.0 compatibility case 'backdrop #': - return new IntermediateInput(InputOpcode.SENSING_OF_BACKDROP_NUMBER, InputType.NUMBER_POS_REAL); + return new IntermediateInput(InputOpcode.SENSING_OF_BACKDROP_NUMBER, InputType.NUMBER_POS_INT); case 'backdrop name': return new IntermediateInput(InputOpcode.SENSING_OF_BACKDROP_NAME, InputType.STRING); } @@ -536,7 +536,7 @@ class ScriptTreeGenerator { case 'direction': return new IntermediateInput(InputOpcode.SENSING_OF_DIRECTION, InputType.NUMBER_REAL, {object}); case 'costume #': - return new IntermediateInput(InputOpcode.SENSING_OF_COSTUME_NUMBER, InputType.NUMBER_POS_REAL, {object}); + return new IntermediateInput(InputOpcode.SENSING_OF_COSTUME_NUMBER, InputType.NUMBER_POS_INT, {object}); case 'costume name': return new IntermediateInput(InputOpcode.SENSING_OF_COSTUME_NAME, InputType.STRING, {object}); case 'size': 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 224f800f45e..edbe98dd2e9 100644 --- a/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot @@ -19,7 +19,7 @@ const b1 = stage.variables["rQq!wAuU2T9DV9,S[/s."]; return function funXYZ_run () { b0.value = []; for (var a0 = 100; a0 >= 0.5; a0--) { -b0.value.push((b1.value[((b0.value.length + 1) | 0) - 1] ?? "")); +b0.value.push((b1.value[(b0.value.length + 1) - 1] ?? "")); b0._monitorUpToDate = false; } thread.procedures["Wqsort %s %s"](1,b0.value.length); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot index 283e439826b..5f407d57fb6 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot @@ -19,7 +19,7 @@ const b1 = stage.variables["rQq!wAuU2T9DV9,S[/s."]; return function* genXYZ_run () { b0.value = []; for (var a0 = 100; a0 >= 0.5; a0--) { -b0.value.push((b1.value[((b0.value.length + 1) | 0) - 1] ?? "")); +b0.value.push((b1.value[(b0.value.length + 1) - 1] ?? "")); b0._monitorUpToDate = false; if (isStuck()) yield; } From 2ac7095947a0f0e0b0b2d510f778d0aa717bbd88 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 4 Oct 2025 20:05:31 -0500 Subject: [PATCH 061/106] Optimize loops with provably-integer iteration counts --- src/compiler/jsgen.js | 6 +++++- ...analyze-yields-due-to-direct-recursion.sb3.tw-snapshot | 2 +- .../tw-comparison-matrix-runtime.sb3.tw-snapshot | 4 ++-- test/snapshot/__snapshots__/tw-counter.sb3.tw-snapshot | 2 +- ...tate-accounts-for-yields-in-procedures.sb3.tw-snapshot | 4 ++-- ...rus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot | 4 ++-- .../__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot | 4 ++-- ...tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot | 2 +- .../tw-procedure-return-stops-scripts.sb3.tw-snapshot | 2 +- .../tw-procedure-return-warp.sb3.tw-snapshot | 8 ++++---- .../tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot | 2 +- ...rting-script-keeps-running-until-yield.sb3.tw-snapshot | 2 +- .../__snapshots__/tw-unsafe-equals.sb3.tw-snapshot | 4 ++-- ...analyze-yields-due-to-direct-recursion.sb3.tw-snapshot | 2 +- .../tw-comparison-matrix-runtime.sb3.tw-snapshot | 4 ++-- .../__snapshots__/warp-timer/tw-counter.sb3.tw-snapshot | 2 +- ...tate-accounts-for-yields-in-procedures.sb3.tw-snapshot | 4 ++-- ...rus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot | 4 ++-- .../warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot | 4 ++-- ...tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot | 2 +- .../tw-procedure-return-stops-scripts.sb3.tw-snapshot | 2 +- .../warp-timer/tw-procedure-return-warp.sb3.tw-snapshot | 8 ++++---- .../tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot | 2 +- ...rting-script-keeps-running-until-yield.sb3.tw-snapshot | 2 +- .../warp-timer/tw-unsafe-equals.sb3.tw-snapshot | 4 ++-- 25 files changed, 45 insertions(+), 41 deletions(-) diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 5008e6edbfa..a74c633ec33 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -610,7 +610,11 @@ class JSGenerator { break; case StackOpcode.CONTROL_REPEAT: { const i = this.localVariables.next(); - this.source += `for (var ${i} = ${this.descendInput(node.times)}; ${i} >= 0.5; ${i}--) {\n`; + if (node.times.isAlwaysType(InputType.NUMBER_INT)) { + this.source += `for (var ${i} = ${this.descendInput(node.times)}; ${i} > 0; ${i}--) {\n`; + } else { + this.source += `for (var ${i} = ${this.descendInput(node.times)}; ${i} >= 0.5; ${i}--) {\n`; + } this.descendStack(node.do, new Frame(true)); this.yieldLoop(); this.source += `}\n`; diff --git a/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot index c19e45f7049..8536858fee5 100644 --- a/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot @@ -31,7 +31,7 @@ return ""; (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 () { -for (var a0 = 1; a0 >= 0.5; a0--) { +for (var a0 = 1; a0 > 0; a0--) { yield; } b0.value = "random"; diff --git a/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot index 686c36b9e13..6c6b55de7f5 100644 --- a/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot @@ -23,10 +23,10 @@ return function* genXYZ_run_test () { thread.procedures["Wsetup values"](); b0.value = 0; b1.value = 0; -for (var a0 = b2.value.length; a0 >= 0.5; a0--) { +for (var a0 = b2.value.length; a0 > 0; a0--) { b1.value = ((+b1.value || 0) + 1); b3.value = 0; -for (var a1 = b2.value.length; a1 >= 0.5; a1--) { +for (var a1 = b2.value.length; a1 > 0; a1--) { b3.value = ((+b3.value || 0) + 1); b0.value = ((+b0.value || 0) + 1); if (!compareEqual(compareGreaterThan(listGet(b2.value, b1.value), (b2.value[(b3.value | 0) - 1] ?? "")), (b4.value[(b0.value | 0) - 1] ?? ""))) { diff --git a/test/snapshot/__snapshots__/tw-counter.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-counter.sb3.tw-snapshot index a4d1176a8e7..abbfa97a51e 100644 --- a/test/snapshot/__snapshots__/tw-counter.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-counter.sb3.tw-snapshot @@ -32,7 +32,7 @@ runtime.ext_scratch3_control._counter = 0; if ((runtime.ext_scratch3_control._counter === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass clear = 0",}, b0, false, false, "w", null); } -for (var a0 = 10; a0 >= 0.5; a0--) { +for (var a0 = 10; a0 > 0; a0--) { runtime.ext_scratch3_control._counter++; yield; } diff --git a/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot index c8bf63116b7..7676e37b15c 100644 --- a/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot @@ -20,7 +20,7 @@ retire(); return; // Sprite1 Zsomething that yields (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_something_that_yield () { -for (var a0 = 2; a0 >= 0.5; a0--) { +for (var a0 = 2; a0 > 0; a0--) { yield; } return ""; @@ -30,7 +30,7 @@ return ""; (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 () { -for (var a0 = 1; a0 >= 0.5; a0--) { +for (var a0 = 1; a0 > 0; a0--) { yield; } b0.value = "random"; diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot index 704116bfee2..af096a9106d 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot @@ -26,7 +26,7 @@ retire(); return; const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); return function* genXYZ_no_refresh () { -for (var a0 = 30; a0 >= 0.5; a0--) { +for (var a0 = 30; a0 > 0; a0--) { thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -53,7 +53,7 @@ return ""; const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); return function* genXYZ_has_refresh () { -for (var a0 = 30; a0 >= 0.5; a0--) { +for (var a0 = 30; a0 > 0; a0--) { thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); 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 edbe98dd2e9..1dc2a0741df 100644 --- a/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot @@ -18,7 +18,7 @@ const b0 = stage.variables["EF^k=u-t@S)w60;RP?dZ-list-list"]; const b1 = stage.variables["rQq!wAuU2T9DV9,S[/s."]; return function funXYZ_run () { b0.value = []; -for (var a0 = 100; a0 >= 0.5; a0--) { +for (var a0 = 100; a0 > 0; a0--) { b0.value.push((b1.value[(b0.value.length + 1) - 1] ?? "")); b0._monitorUpToDate = false; } @@ -36,7 +36,7 @@ const b4 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_validate () { b0.value = 1; b1.value = 1; -for (var a0 = b2.value.length; a0 >= 0.5; a0--) { +for (var a0 = b2.value.length; a0 > 0; a0--) { if (!compareEqual((b2.value[(b1.value | 0) - 1] ?? ""), (b3.value[(b1.value | 0) - 1] ?? ""))) { b0.value = 0; yield* executeInCompatibilityLayer({"MESSAGE":("fail mismatch at index " + ("" + b1.value)),}, b4, true, false, ",", null); diff --git a/test/snapshot/__snapshots__/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot index e3cf8b7c36e..0f6a49f62b7 100644 --- a/test/snapshot/__snapshots__/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot @@ -9,7 +9,7 @@ const b2 = stage.variables["l^q!%fq]Bv;72dlGf}^Z"]; return function* genXYZ () { b0.value = 0; yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b1, false, false, "}fY]VN(X|v/[G`P0?@s2", null); -for (var a0 = 30; a0 >= 0.5; a0--) { +for (var a0 = 30; a0 > 0; a0--) { b2.value = runtime.ioDevices.clock.projectTimer(); thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); diff --git a/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot index 21e08e6c87b..9159b5c7232 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot @@ -25,7 +25,7 @@ const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_return_stops_the_scr () { b0.value = 0; -for (var a0 = 100; a0 >= 0.5; a0--) { +for (var a0 = 100; a0 > 0; a0--) { b0.value = (b0.value + 1); if ((b0.value === 25)) { return "stopped!"; diff --git a/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot index fde5f016583..d6aad6c51fb 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot @@ -38,7 +38,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_non_warp () { b0.value = 0; -for (var a0 = 5; a0 >= 0.5; a0--) { +for (var a0 = 5; a0 > 0; a0--) { thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -56,7 +56,7 @@ if ((("" + (yield* thread.procedures["Wverify runs warp %s"]((yield* thread.proc yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp and warp mix",}, b1, false, false, "S", null); } b0.value = 0; -for (var a2 = 5; a2 >= 0.5; a2--) { +for (var a2 = 5; a2 > 0; a2--) { thread.timer = timer(); var a3 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -79,7 +79,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_verify_runs_warp_ (p0) { b0.value = 0; -for (var a0 = 5; a0 >= 0.5; a0--) { +for (var a0 = 5; a0 > 0; a0--) { thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -101,7 +101,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_verify_runs_non_warp (p0) { b0.value = 0; -for (var a0 = 5; a0 >= 0.5; a0--) { +for (var a0 = 5; a0 > 0; a0--) { thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); diff --git a/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot index 63559f0dbfb..646fdfd02e4 100644 --- a/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot @@ -29,7 +29,7 @@ const b2 = stage.variables["JbF5exWEi*m?-UEmkASS"]; return function* genXYZ () { b0.value = 0; yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b1, false, false, "0/2-)Gp^^=haQ1OMD.xb", null); -for (var a0 = 15; a0 >= 0.5; a0--) { +for (var a0 = 15; a0 > 0; a0--) { if (((+b2.value || 0) === 200)) { b2.value = 50; } else { diff --git a/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot index 2783ca0147a..62e48ec1cae 100644 --- a/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot @@ -24,7 +24,7 @@ if (compareEqual(b0.value, 0)) { b0.value = 1; startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); b1.value = 1; -for (var a0 = 1; a0 >= 0.5; a0--) { +for (var a0 = 1; a0 > 0; a0--) { yield; } b1.value = 2; diff --git a/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot index 90a01cba05d..3804c87f6b3 100644 --- a/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot @@ -24,7 +24,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass 4",}, b0, false, false, "8]2 if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 5",}, b0, false, false, "ZU^{OfKTg|+Au$$q0[]u", null); } -for (var a0 = 1; a0 >= 0.5; a0--) { +for (var a0 = 1; a0 > 0; a0--) { if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 6",}, b0, false, false, "HB+_IN}6=K[*ksxKXH0`", null); } @@ -47,7 +47,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass 10",}, b0, false, false, "B` if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 11",}, b0, false, false, "TJ:#TkYBys*!RYiKLXb)", null); } -for (var a1 = 1; a1 >= 0.5; a1--) { +for (var a1 = 1; a1 > 0; a1--) { if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 12",}, b0, false, false, ",Z,~10Qo~j;(+VL+I3q:", null); } diff --git a/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot index c19e45f7049..8536858fee5 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot @@ -31,7 +31,7 @@ return ""; (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 () { -for (var a0 = 1; a0 >= 0.5; a0--) { +for (var a0 = 1; a0 > 0; a0--) { yield; } b0.value = "random"; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot index f274502d07a..656fc83d0bc 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot @@ -23,10 +23,10 @@ return function* genXYZ_run_test () { thread.procedures["Wsetup values"](); b0.value = 0; b1.value = 0; -for (var a0 = b2.value.length; a0 >= 0.5; a0--) { +for (var a0 = b2.value.length; a0 > 0; a0--) { b1.value = ((+b1.value || 0) + 1); b3.value = 0; -for (var a1 = b2.value.length; a1 >= 0.5; a1--) { +for (var a1 = b2.value.length; a1 > 0; a1--) { b3.value = ((+b3.value || 0) + 1); b0.value = ((+b0.value || 0) + 1); if (!compareEqual(compareGreaterThan(listGet(b2.value, b1.value), (b2.value[(b3.value | 0) - 1] ?? "")), (b4.value[(b0.value | 0) - 1] ?? ""))) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-counter.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-counter.sb3.tw-snapshot index a4d1176a8e7..abbfa97a51e 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-counter.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-counter.sb3.tw-snapshot @@ -32,7 +32,7 @@ runtime.ext_scratch3_control._counter = 0; if ((runtime.ext_scratch3_control._counter === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass clear = 0",}, b0, false, false, "w", null); } -for (var a0 = 10; a0 >= 0.5; a0--) { +for (var a0 = 10; a0 > 0; a0--) { runtime.ext_scratch3_control._counter++; yield; } diff --git a/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot index c8bf63116b7..7676e37b15c 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot @@ -20,7 +20,7 @@ retire(); return; // Sprite1 Zsomething that yields (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_something_that_yield () { -for (var a0 = 2; a0 >= 0.5; a0--) { +for (var a0 = 2; a0 > 0; a0--) { yield; } return ""; @@ -30,7 +30,7 @@ return ""; (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 () { -for (var a0 = 1; a0 >= 0.5; a0--) { +for (var a0 = 1; a0 > 0; a0--) { yield; } b0.value = "random"; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot index a3d93933160..7fe8cccf8ce 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot @@ -26,7 +26,7 @@ retire(); return; const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); return function* genXYZ_no_refresh () { -for (var a0 = 30; a0 >= 0.5; a0--) { +for (var a0 = 30; a0 > 0; a0--) { thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -54,7 +54,7 @@ return ""; const b0 = runtime.getOpcodeFunction("music_restForBeats"); const b1 = runtime.getOpcodeFunction("music_playDrumForBeats"); return function* genXYZ_has_refresh () { -for (var a0 = 30; a0 >= 0.5; a0--) { +for (var a0 = 30; a0 > 0; a0--) { thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot index 5f407d57fb6..8b5d4a41ffa 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot @@ -18,7 +18,7 @@ const b0 = stage.variables["EF^k=u-t@S)w60;RP?dZ-list-list"]; const b1 = stage.variables["rQq!wAuU2T9DV9,S[/s."]; return function* genXYZ_run () { b0.value = []; -for (var a0 = 100; a0 >= 0.5; a0--) { +for (var a0 = 100; a0 > 0; a0--) { b0.value.push((b1.value[(b0.value.length + 1) - 1] ?? "")); b0._monitorUpToDate = false; if (isStuck()) yield; @@ -37,7 +37,7 @@ const b4 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_validate () { b0.value = 1; b1.value = 1; -for (var a0 = b2.value.length; a0 >= 0.5; a0--) { +for (var a0 = b2.value.length; a0 > 0; a0--) { if (!compareEqual(listGet(b2.value, b1.value), listGet(b3.value, b1.value))) { b0.value = 0; yield* executeInCompatibilityLayer({"MESSAGE":("fail mismatch at index " + ("" + b1.value)),}, b4, true, false, ",", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot index e3cf8b7c36e..0f6a49f62b7 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot @@ -9,7 +9,7 @@ const b2 = stage.variables["l^q!%fq]Bv;72dlGf}^Z"]; return function* genXYZ () { b0.value = 0; yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b1, false, false, "}fY]VN(X|v/[G`P0?@s2", null); -for (var a0 = 30; a0 >= 0.5; a0--) { +for (var a0 = 30; a0 > 0; a0--) { b2.value = runtime.ioDevices.clock.projectTimer(); thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot index 6f96f52693d..6d536299287 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot @@ -25,7 +25,7 @@ const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_return_stops_the_scr () { b0.value = 0; -for (var a0 = 100; a0 >= 0.5; a0--) { +for (var a0 = 100; a0 > 0; a0--) { b0.value = ((+b0.value || 0) + 1); if ((b0.value === 25)) { return "stopped!"; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot index d7afc882d25..db6051903b0 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot @@ -38,7 +38,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_non_warp () { b0.value = 0; -for (var a0 = 5; a0 >= 0.5; a0--) { +for (var a0 = 5; a0 > 0; a0--) { thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -56,7 +56,7 @@ if ((("" + (yield* thread.procedures["Wverify runs warp %s"]((yield* thread.proc yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp and warp mix",}, b1, false, false, "S", null); } b0.value = 0; -for (var a2 = 5; a2 >= 0.5; a2--) { +for (var a2 = 5; a2 > 0; a2--) { thread.timer = timer(); var a3 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -79,7 +79,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_verify_runs_warp_ (p0) { b0.value = 0; -for (var a0 = 5; a0 >= 0.5; a0--) { +for (var a0 = 5; a0 > 0; a0--) { thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -102,7 +102,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_verify_runs_non_warp (p0) { b0.value = 0; -for (var a0 = 5; a0 >= 0.5; a0--) { +for (var a0 = 5; a0 > 0; a0--) { thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot index 63559f0dbfb..646fdfd02e4 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot @@ -29,7 +29,7 @@ const b2 = stage.variables["JbF5exWEi*m?-UEmkASS"]; return function* genXYZ () { b0.value = 0; yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b1, false, false, "0/2-)Gp^^=haQ1OMD.xb", null); -for (var a0 = 15; a0 >= 0.5; a0--) { +for (var a0 = 15; a0 > 0; a0--) { if (((+b2.value || 0) === 200)) { b2.value = 50; } else { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot index 2783ca0147a..62e48ec1cae 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot @@ -24,7 +24,7 @@ if (compareEqual(b0.value, 0)) { b0.value = 1; startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); b1.value = 1; -for (var a0 = 1; a0 >= 0.5; a0--) { +for (var a0 = 1; a0 > 0; a0--) { yield; } b1.value = 2; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot index 90a01cba05d..3804c87f6b3 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot @@ -24,7 +24,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass 4",}, b0, false, false, "8]2 if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 5",}, b0, false, false, "ZU^{OfKTg|+Au$$q0[]u", null); } -for (var a0 = 1; a0 >= 0.5; a0--) { +for (var a0 = 1; a0 > 0; a0--) { if (((+b1.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 6",}, b0, false, false, "HB+_IN}6=K[*ksxKXH0`", null); } @@ -47,7 +47,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass 10",}, b0, false, false, "B` if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 11",}, b0, false, false, "TJ:#TkYBys*!RYiKLXb)", null); } -for (var a1 = 1; a1 >= 0.5; a1--) { +for (var a1 = 1; a1 > 0; a1--) { if (((+b2.value || 0) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 12",}, b0, false, false, ",Z,~10Qo~j;(+VL+I3q:", null); } From a2701efdf5d227f499a3d04505a738adea927eb6 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 4 Oct 2025 20:36:46 -0500 Subject: [PATCH 062/106] Use more specific type for round, floor, ceiling --- src/compiler/irgen.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 295fe9df998..73bb2f85aca 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -362,8 +362,8 @@ class ScriptTreeGenerator { const operator = block.fields.OPERATOR.value.toLowerCase(); switch (operator) { case 'abs': return new IntermediateInput(InputOpcode.OP_ABS, InputType.NUMBER_POS | InputType.NUMBER_ZERO, {value}); - case 'floor': return new IntermediateInput(InputOpcode.OP_FLOOR, InputType.NUMBER, {value}); - case 'ceiling': return new IntermediateInput(InputOpcode.OP_CEILING, InputType.NUMBER, {value}); + case 'floor': return new IntermediateInput(InputOpcode.OP_FLOOR, InputType.NUMBER_INT | InputType.NUMBER_INF, {value}); + case 'ceiling': return new IntermediateInput(InputOpcode.OP_CEILING, InputType.NUMBER_INT | InputType.NUMBER_INF, {value}); case 'sqrt': return new IntermediateInput(InputOpcode.OP_SQRT, InputType.NUMBER_OR_NAN, {value}); case 'sin': return new IntermediateInput(InputOpcode.OP_SIN, InputType.NUMBER_OR_NAN, {value}); case 'cos': return new IntermediateInput(InputOpcode.OP_COS, InputType.NUMBER_OR_NAN, {value}); @@ -458,7 +458,7 @@ class ScriptTreeGenerator { }); } case 'operator_round': - return new IntermediateInput(InputOpcode.OP_ROUND, InputType.NUMBER, { + return new IntermediateInput(InputOpcode.OP_ROUND, InputType.NUMBER_INT | InputType.NUMBER_INF, { value: this.descendInputOfBlock(block, 'NUM').toType(InputType.NUMBER) }); case 'operator_subtract': From 2a2d15282b5a74a37cd0676ead4290f4f45f47d1 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 4 Oct 2025 20:37:54 -0500 Subject: [PATCH 063/106] Infinite iteration count can also use simpler condition --- src/compiler/jsgen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index a74c633ec33..65ffe9c42d2 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -610,7 +610,7 @@ class JSGenerator { break; case StackOpcode.CONTROL_REPEAT: { const i = this.localVariables.next(); - if (node.times.isAlwaysType(InputType.NUMBER_INT)) { + if (node.times.isAlwaysType(InputType.NUMBER_INT | InputType.NUMBER_INF)) { this.source += `for (var ${i} = ${this.descendInput(node.times)}; ${i} > 0; ${i}--) {\n`; } else { this.source += `for (var ${i} = ${this.descendInput(node.times)}; ${i} >= 0.5; ${i}--) {\n`; From d848fd0e6ed836efbc1ab4e19746f22f90bec9b2 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Tue, 7 Oct 2025 18:05:38 -0500 Subject: [PATCH 064/106] Convert default extension URLs from dict to object --- .../tw-default-extension-urls.js | 16 ++++++++-------- src/virtual-machine.js | 5 ++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/extension-support/tw-default-extension-urls.js b/src/extension-support/tw-default-extension-urls.js index 7b05eb80ccd..53ed768c65a 100644 --- a/src/extension-support/tw-default-extension-urls.js +++ b/src/extension-support/tw-default-extension-urls.js @@ -1,15 +1,15 @@ // If a project uses an extension but does not specify a URL, it will default to // the URLs given here, if it exists. This is useful for compatibility with other mods. -const defaults = new Map(); +const defaults = { + // Box2D (`griffpatch`) is not listed here because our extension is not actually + // compatible with the original version due to fields vs inputs. -// Box2D (`griffpatch`) is not listed here because our extension is not actually -// compatible with the original version due to fields vs inputs. + // Scratch Lab Animated Text - https://lab.scratch.mit.edu/text/ + text: 'https://extensions.turbowarp.org/lab/text.js', -// Scratch Lab Animated Text - https://lab.scratch.mit.edu/text/ -defaults.set('text', 'https://extensions.turbowarp.org/lab/text.js'); - -// Turboloader's AudioStream -defaults.set('audiostr', 'https://extensions.turbowarp.org/turboloader/audiostream.js'); + // Turboloader's AudioStream + audiostr: 'https://extensions.turbowarp.org/turboloader/audiostream.js' +}; module.exports = defaults; diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 4a8f55cf613..2cc5d260c73 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -779,7 +779,10 @@ class VirtualMachine extends EventEmitter { this.extensionManager.loadExtensionIdSync(extensionID); } else { // Custom extension - const url = extensionURLs.get(extensionID) || defaultExtensionURLs.get(extensionID); + let url = extensionURLs.get(extensionID); + if (!url && Object.prototype.hasOwnProperty.call(defaultExtensionURLs, extensionID)) { + url = defaultExtensionURLs[extensionID]; + } if (!url) { throw new Error(`Unknown extension: ${extensionID}`); } From 4ab24673c9033c4273e8fadbae5bf79ceee64939 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Tue, 7 Oct 2025 18:06:10 -0500 Subject: [PATCH 065/106] Add face sensing to default extension URLs --- src/extension-support/tw-default-extension-urls.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/extension-support/tw-default-extension-urls.js b/src/extension-support/tw-default-extension-urls.js index 53ed768c65a..de3c3ec77d0 100644 --- a/src/extension-support/tw-default-extension-urls.js +++ b/src/extension-support/tw-default-extension-urls.js @@ -9,7 +9,10 @@ const defaults = { text: 'https://extensions.turbowarp.org/lab/text.js', // Turboloader's AudioStream - audiostr: 'https://extensions.turbowarp.org/turboloader/audiostream.js' + audiostr: 'https://extensions.turbowarp.org/turboloader/audiostream.js', + + // https://scratch.mit.edu/discuss/topic/842592/ + faceSensing: 'https://extensions.turbowarp.org/lab/face-sensing.js' }; module.exports = defaults; From d09f82a2fe16f411e93a85a67db6a1c8dcaea7bb Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 8 Oct 2025 17:15:24 -0500 Subject: [PATCH 066/106] Add new test case that does some simple string operations --- .../execute/tw-simple-string-operations.sb3 | Bin 0 -> 3341 bytes ...w-simple-string-operations.sb3.tw-snapshot | 36 +++++++++++++++++ ...w-simple-string-operations.sb3.tw-snapshot | 37 ++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 test/fixtures/execute/tw-simple-string-operations.sb3 create mode 100644 test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot diff --git a/test/fixtures/execute/tw-simple-string-operations.sb3 b/test/fixtures/execute/tw-simple-string-operations.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..0687b08ace3b0b0dcdcbc3819d7a45456d14d858 GIT binary patch literal 3341 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 0.5; a0--) { +if ((((("" + b0.value))[(b2.value | 0) - 1] || "").toLowerCase() === "a".toLowerCase())) { +b1.value = (("" + b1.value) + "b"); +} else { +b1.value = (("" + b1.value) + "a"); +} +b2.value = (b2.value + 1); +} +return ""; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot new file mode 100644 index 00000000000..c48c90242a5 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot @@ -0,0 +1,37 @@ +// TW Snapshot +// Input SHA-256: e6a6f5ea252886949eab2f4b5608526dc3686160d65f6e07c2d864c82db24326 + +// 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["PJl9-2GypE.OstQk*B_*"]; +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); +yield* thread.procedures["Wa"](); +if ((("" + b1.value).toLowerCase() === "babab".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "s", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "q", null); +retire(); return; +}; }) + +// Sprite1 Wa +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["uEt-Ix{%|r3`}-W%+kdm"]; +const b1 = stage.variables["PJl9-2GypE.OstQk*B_*"]; +const b2 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ_a () { +b0.value = "ababa"; +b1.value = ""; +b2.value = 1; +for (var a0 = ("" + b0.value).length; a0 >= 0.5; a0--) { +if ((((("" + b0.value))[((+b2.value) | 0) - 1] || "").toLowerCase() === "a".toLowerCase())) { +b1.value = (("" + b1.value) + "b"); +} else { +b1.value = (("" + b1.value) + "a"); +} +b2.value = ((+b2.value || 0) + 1); +if (isStuck()) yield; +} +return ""; +}; }) From 07309b6ebfd8c2bc21d52139cb859391d1921f20 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 8 Oct 2025 17:15:44 -0500 Subject: [PATCH 067/106] Use more specific type for string length --- src/compiler/irgen.js | 2 +- .../__snapshots__/tw-simple-string-operations.sb3.tw-snapshot | 2 +- .../warp-timer/tw-simple-string-operations.sb3.tw-snapshot | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 73bb2f85aca..4175840ed98 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -344,7 +344,7 @@ class ScriptTreeGenerator { right: this.descendInputOfBlock(block, 'STRING2').toType(InputType.STRING) }); case 'operator_length': - return new IntermediateInput(InputOpcode.OP_LENGTH, InputType.NUMBER_REAL, { + return new IntermediateInput(InputOpcode.OP_LENGTH, InputType.NUMBER_POS_INT | InputType.NUMBER_ZERO, { string: this.descendInputOfBlock(block, 'STRING').toType(InputType.STRING) }); case 'operator_letter_of': diff --git a/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot index b58442515ef..78cdbd86e7f 100644 --- a/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot @@ -24,7 +24,7 @@ return function funXYZ_a () { b0.value = "ababa"; b1.value = ""; b2.value = 1; -for (var a0 = ("" + b0.value).length; a0 >= 0.5; a0--) { +for (var a0 = ("" + b0.value).length; a0 > 0; a0--) { if ((((("" + b0.value))[(b2.value | 0) - 1] || "").toLowerCase() === "a".toLowerCase())) { b1.value = (("" + b1.value) + "b"); } else { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot index c48c90242a5..ec187c5fd8e 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot @@ -24,7 +24,7 @@ return function* genXYZ_a () { b0.value = "ababa"; b1.value = ""; b2.value = 1; -for (var a0 = ("" + b0.value).length; a0 >= 0.5; a0--) { +for (var a0 = ("" + b0.value).length; a0 > 0; a0--) { if ((((("" + b0.value))[((+b2.value) | 0) - 1] || "").toLowerCase() === "a".toLowerCase())) { b1.value = (("" + b1.value) + "b"); } else { From 67cb7cfc5d47a3ca72c173abe3fdc8d07de0d993 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 8 Oct 2025 18:42:43 -0500 Subject: [PATCH 068/106] Remove unnecessary string casts --- src/compiler/iroptimizer.js | 22 +++++++++++++++++-- .../tw-sensing-of.sb3.tw-snapshot | 2 +- ...w-simple-string-operations.sb3.tw-snapshot | 8 +++---- .../warp-timer/tw-sensing-of.sb3.tw-snapshot | 2 +- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index ae7d98e495f..ebd2545b8e1 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -162,12 +162,20 @@ class IROptimizer { const innerType = inputs.target.type; if (innerType & InputType.NUMBER) return innerType; return InputType.NUMBER; - } case InputOpcode.CAST_NUMBER_OR_NAN: { + } + + case InputOpcode.CAST_NUMBER_OR_NAN: { const innerType = inputs.target.type; if (innerType & InputType.NUMBER_OR_NAN) return innerType; return InputType.NUMBER_OR_NAN; } + case InputOpcode.CAST_STRING: { + const innerType = inputs.target.type; + if (innerType & InputType.STRING) return innerType; + return InputType.STRING; + } + case InputOpcode.OP_ADD: { const leftType = inputs.left.type; const rightType = inputs.right.type; @@ -699,13 +707,23 @@ class IROptimizer { return input.inputs.target; } return input; - } case InputOpcode.CAST_NUMBER_OR_NAN: { + } + + case InputOpcode.CAST_NUMBER_OR_NAN: { const targetType = input.inputs.target.type; if ((targetType & InputType.NUMBER_OR_NAN) === targetType) { return input.inputs.target; } return input; } + + case InputOpcode.CAST_STRING: { + const targetType = input.inputs.target.type; + if ((targetType & InputType.STRING) === targetType) { + return input.inputs.target; + } + return input; + } } return input; diff --git a/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot index a370af3e46d..b15bc894fa8 100644 --- a/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot @@ -52,7 +52,7 @@ if (compareEqual((b4 ? b4.value : 0), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent variable",}, b0, false, false, ")nnN?*l+E)dC(fT5(_@q", null); } b5.value = (("" + randomInt(1, 9)) + ("" + randomInt(1, 9))); -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "backdrop #" }), 0)) { +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b5.value, PROPERTY: "backdrop #" }), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop #",}, b0, false, false, "UFr{fbR3@a.u_paq:r]F", null); } if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "backdrop name" }), 0)) { diff --git a/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot index 78cdbd86e7f..a290411e64c 100644 --- a/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot @@ -24,11 +24,11 @@ return function funXYZ_a () { b0.value = "ababa"; b1.value = ""; b2.value = 1; -for (var a0 = ("" + b0.value).length; a0 > 0; a0--) { -if ((((("" + b0.value))[(b2.value | 0) - 1] || "").toLowerCase() === "a".toLowerCase())) { -b1.value = (("" + b1.value) + "b"); +for (var a0 = b0.value.length; a0 > 0; a0--) { +if ((((b0.value)[(b2.value | 0) - 1] || "").toLowerCase() === "a".toLowerCase())) { +b1.value = (b1.value + "b"); } else { -b1.value = (("" + b1.value) + "a"); +b1.value = (b1.value + "a"); } b2.value = (b2.value + 1); } diff --git a/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot index a370af3e46d..b15bc894fa8 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot @@ -52,7 +52,7 @@ if (compareEqual((b4 ? b4.value : 0), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent variable",}, b0, false, false, ")nnN?*l+E)dC(fT5(_@q", null); } b5.value = (("" + randomInt(1, 9)) + ("" + randomInt(1, 9))); -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "backdrop #" }), 0)) { +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b5.value, PROPERTY: "backdrop #" }), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop #",}, b0, false, false, "UFr{fbR3@a.u_paq:r]F", null); } if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "backdrop name" }), 0)) { From 3b947da95e1f35f41881626b9cff793984e2938b Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 8 Oct 2025 18:43:50 -0500 Subject: [PATCH 069/106] Remove unnecessary number index casts --- src/compiler/iroptimizer.js | 14 ++++++++++++++ .../tw-simple-string-operations.sb3.tw-snapshot | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index ebd2545b8e1..d5d284360ab 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -164,6 +164,12 @@ class IROptimizer { return InputType.NUMBER; } + case InputOpcode.CAST_NUMBER_INDEX: { + const innerType = inputs.target.type; + if (innerType & InputType.NUMBER_INDEX) return innerType; + return InputType.NUMBER_INDEX; + } + case InputOpcode.CAST_NUMBER_OR_NAN: { const innerType = inputs.target.type; if (innerType & InputType.NUMBER_OR_NAN) return innerType; @@ -709,6 +715,14 @@ class IROptimizer { return input; } + case InputOpcode.CAST_NUMBER_INDEX: { + const targetType = input.inputs.target.type; + if ((targetType & InputType.NUMBER_INDEX) === targetType) { + return input.inputs.target; + } + return input; + } + case InputOpcode.CAST_NUMBER_OR_NAN: { const targetType = input.inputs.target.type; if ((targetType & InputType.NUMBER_OR_NAN) === targetType) { diff --git a/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot index a290411e64c..7899f9ed374 100644 --- a/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot @@ -25,7 +25,7 @@ b0.value = "ababa"; b1.value = ""; b2.value = 1; for (var a0 = b0.value.length; a0 > 0; a0--) { -if ((((b0.value)[(b2.value | 0) - 1] || "").toLowerCase() === "a".toLowerCase())) { +if ((((b0.value)[b2.value - 1] || "").toLowerCase() === "a".toLowerCase())) { b1.value = (b1.value + "b"); } else { b1.value = (b1.value + "a"); From efb502a8acf320abe40cf173f5def583c64a0014 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 8 Oct 2025 18:44:51 -0500 Subject: [PATCH 070/106] Remove unnecessary boolean casts --- src/compiler/iroptimizer.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index d5d284360ab..481bccd5b7d 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -158,6 +158,12 @@ class IROptimizer { case InputOpcode.ADDON_CALL: break; + case InputOpcode.CAST_BOOLEAN: { + const innerType = inputs.target.type; + if (innerType & InputType.BOOLEAN) return innerType; + return InputType.BOOLEAN; + } + case InputOpcode.CAST_NUMBER: { const innerType = inputs.target.type; if (innerType & InputType.NUMBER) return innerType; @@ -707,6 +713,14 @@ class IROptimizer { } switch (input.opcode) { + case InputOpcode.CAST_BOOLEAN: { + const targetType = input.inputs.target.type; + if ((targetType & InputType.BOOLEAN) === targetType) { + return input.inputs.target; + } + return input; + } + case InputOpcode.CAST_NUMBER: { const targetType = input.inputs.target.type; if ((targetType & InputType.NUMBER) === targetType) { From eb0d67806870c77aacaeadef1a3cd7b30c7db12d Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sun, 12 Oct 2025 11:12:05 -0500 Subject: [PATCH 071/106] Only analyze repeat block inputs at the start of the loop --- src/compiler/iroptimizer.js | 13 ++++++-- .../tw-repeat-analysis-doesnt-reanalyze.sb3 | Bin 0 -> 3073 bytes ...-analysis-doesnt-reanalyze.sb3.tw-snapshot | 28 +++++++++++++++++ ...-analysis-doesnt-reanalyze.sb3.tw-snapshot | 29 ++++++++++++++++++ 4 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/execute/tw-repeat-analysis-doesnt-reanalyze.sb3 create mode 100644 test/snapshot/__snapshots__/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index ae7d98e495f..146aed1e37d 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -559,9 +559,12 @@ class IROptimizer { break; case StackOpcode.CONTROL_WHILE: case StackOpcode.CONTROL_FOR: + modified = this.analyzeInputs(inputs, state) || modified; + modified = this.analyzeLoopedStack(inputs.do, state, stackBlock, true) || modified; + break; case StackOpcode.CONTROL_REPEAT: modified = this.analyzeInputs(inputs, state) || modified; - modified = this.analyzeLoopedStack(inputs.do, state, stackBlock) || modified; + modified = this.analyzeLoopedStack(inputs.do, state, stackBlock, false) || modified; break; case StackOpcode.CONTROL_IF_ELSE: { modified = this.analyzeInputs(inputs, state) || modified; @@ -642,10 +645,11 @@ class IROptimizer { * @param {IntermediateStack} stack * @param {TypeState} state * @param {IntermediateStackBlock} block + * @param {boolean} willReevaluateInputs * @returns {boolean} * @private */ - analyzeLoopedStack (stack, state, block) { + analyzeLoopedStack (stack, state, block, willReevaluateInputs) { if (block.yields && !this.ignoreYields) { let modified = state.clear(); block.entryState = state.clone(); @@ -672,7 +676,10 @@ class IROptimizer { const newState = state.clone(); modified = this.analyzeStack(stack, newState) || modified; modified = (keepLooping = state.or(newState)) || modified; - modified = this.analyzeInputs(block.inputs, state) || modified; + + if (willReevaluateInputs) { + modified = this.analyzeInputs(block.inputs, state) || modified; + } } while (keepLooping); block.entryState = state.clone(); return modified; diff --git a/test/fixtures/execute/tw-repeat-analysis-doesnt-reanalyze.sb3 b/test/fixtures/execute/tw-repeat-analysis-doesnt-reanalyze.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..12d51fb79bc018595d6a1e5fd5572517b0b5a074 GIT binary patch literal 3073 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 bJ4eI6L4uJUHO-%@3+Fw5{sPZ&0s#CM9(G|C literal 0 HcmV?d00001 diff --git a/test/snapshot/__snapshots__/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot new file mode 100644 index 00000000000..020097c50f2 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot @@ -0,0 +1,28 @@ +// TW Snapshot +// Input SHA-256: 38075839898d1ba3d2556f350ff18438a205c5b6b3cb809d07d3f738bd37dad9 + +// 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, "d", null); +thread.procedures["Wa"](); +if ((("" + b1.value).toLowerCase() === "bwah".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "l", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "k", null); +retire(); return; +}; }) + +// Sprite1 Wa +(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["6h7bpiz0`;;x^G1B3(%["]; +return function funXYZ_a () { +b0.value = b1.value.length; +for (var a0 = b0.value; a0 > 0; a0--) { +b0.value = "bwah"; +} +return ""; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot new file mode 100644 index 00000000000..5366b9c9582 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot @@ -0,0 +1,29 @@ +// TW Snapshot +// Input SHA-256: 38075839898d1ba3d2556f350ff18438a205c5b6b3cb809d07d3f738bd37dad9 + +// 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, "d", null); +yield* thread.procedures["Wa"](); +if ((("" + b1.value).toLowerCase() === "bwah".toLowerCase())) { +yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "l", null); +} +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "k", null); +retire(); return; +}; }) + +// Sprite1 Wa +(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["6h7bpiz0`;;x^G1B3(%["]; +return function* genXYZ_a () { +b0.value = b1.value.length; +for (var a0 = (+b0.value || 0); a0 >= 0.5; a0--) { +b0.value = "bwah"; +if (isStuck()) yield; +} +return ""; +}; }) From 8860e2d6027e1d4040a35788c9003b7b6c5a3ad6 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sun, 12 Oct 2025 11:16:25 -0500 Subject: [PATCH 072/106] Fix repeat block iteration count not being optimizable in yielding loops --- src/compiler/iroptimizer.js | 9 ++++++--- .../tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 146aed1e37d..26936134255 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -650,16 +650,19 @@ class IROptimizer { * @private */ analyzeLoopedStack (stack, state, block, willReevaluateInputs) { + let modified = false; + if (block.yields && !this.ignoreYields) { - let modified = state.clear(); + modified = state.clear(); + if (willReevaluateInputs) { + modified = this.analyzeInputs(block.inputs, state) || modified; + } block.entryState = state.clone(); block.exitState = state.clone(); - modified = this.analyzeInputs(block.inputs, state) || modified; return this.analyzeStack(stack, state) || modified; } let iterations = 0; - let modified = false; let keepLooping; do { // If we are stuck in an apparent infinite loop, give up and assume the worst. diff --git a/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot index 5366b9c9582..35a0f59d7b1 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot @@ -21,7 +21,7 @@ const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; const b1 = stage.variables["6h7bpiz0`;;x^G1B3(%["]; return function* genXYZ_a () { b0.value = b1.value.length; -for (var a0 = (+b0.value || 0); a0 >= 0.5; a0--) { +for (var a0 = b0.value; a0 > 0; a0--) { b0.value = "bwah"; if (isStuck()) yield; } From 55674f82eef8d901affdb2e6061d5127020be489 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 18 Oct 2025 23:43:22 -0500 Subject: [PATCH 073/106] Implement Scratch.external - VM part (#308) --- .../tw-extension-api-common.js | 4 +- src/extension-support/tw-external.js | 87 +++++++++++++++++++ test/unit/tw_extension_api_common.js | 10 +++ test/unit/tw_external.js | 58 +++++++++++++ 4 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 src/extension-support/tw-external.js create mode 100644 test/unit/tw_external.js diff --git a/src/extension-support/tw-extension-api-common.js b/src/extension-support/tw-extension-api-common.js index 1f5928fbc0f..82e706de98f 100644 --- a/src/extension-support/tw-extension-api-common.js +++ b/src/extension-support/tw-extension-api-common.js @@ -3,13 +3,15 @@ const BlockType = require('./block-type'); const BlockShape = require('./tw-block-shape'); const TargetType = require('./target-type'); const Cast = require('../util/cast'); +const external = require('./tw-external'); const Scratch = { ArgumentType, BlockType, BlockShape, TargetType, - Cast + Cast, + external }; module.exports = Scratch; diff --git a/src/extension-support/tw-external.js b/src/extension-support/tw-external.js new file mode 100644 index 00000000000..de7b3a9ad47 --- /dev/null +++ b/src/extension-support/tw-external.js @@ -0,0 +1,87 @@ +/** + * @param {string} url + * @returns {void} if URL is supported + * @throws if URL is unsupported + */ +const checkURL = url => { + // URL might be a very long data: URL, so try to avoid fully parsing it if we can. + // The notable requirement here is that the URL must be an absolute URL, not something + // relative to where the extension is loaded from or where the extension is running. + // This ensures that the same extension file will always load resources from the same + // place, regardless of how it is running or packaged or whatever else. + if ( + !url.startsWith('http:') && + !url.startsWith('https:') && + !url.startsWith('data:') && + !url.startsWith('blob:') + ) { + throw new Error(`Unsupported URL: ${url}`); + } +}; + +const external = {}; + +/** + * @param {string} url + * @template T + * @returns {Promise} + */ +external.importModule = url => { + checkURL(url); + // Need to specify webpackIgnore so that webpack compiles this directly to a call to import() + // instead of trying making it try to use the webpack import system. + return import(/* webpackIgnore: true */ url); +}; + +/** + * @param {string} url + * @returns {Promise} + */ +external.fetch = async url => { + checkURL(url); + const res = await fetch(url); + if (!res.ok) { + throw new Error(`HTTP ${res.status} fetching ${url}`); + } + return res; +}; + +/** + * @param {string} url + * @returns {Promise} + */ +external.dataURL = async url => { + const res = await external.fetch(url); + const blob = await res.blob(); + return new Promise((resolve, reject) => { + const fr = new FileReader(); + fr.onload = () => resolve(fr.result); + fr.onerror = () => reject(fr.error); + fr.readAsDataURL(blob); + }); +}; + +/** + * @param {string} url + * @returns {Promise} + */ +external.blob = async url => { + const res = await external.fetch(url); + return res.blob(); +}; + +/** + * @param {string} url + * @param {string} returnExpression + * @template T + * @returns {Promise} + */ +external.evalAndReturn = async (url, returnExpression) => { + const res = await external.fetch(url); + const text = await res.text(); + const js = `${text};return ${returnExpression}`; + const fn = new Function(js); + return fn(); +}; + +module.exports = external; diff --git a/test/unit/tw_extension_api_common.js b/test/unit/tw_extension_api_common.js index 051fcf134fc..cbb1d6bbfa5 100644 --- a/test/unit/tw_extension_api_common.js +++ b/test/unit/tw_extension_api_common.js @@ -32,3 +32,13 @@ test('Cast', t => { t.equal(ScratchCommon.Cast.toListIndex('1.5', 10, false), 1); t.end(); }); + +test('external', t => { + // has more tests in separate file, mostly just making sure that external exists at all + ScratchCommon.external.fetch('data:text/plain;,test').then(r => { + r.text().then(text => { + t.equal(text, 'test'); + t.end(); + }); + }); +}); diff --git a/test/unit/tw_external.js b/test/unit/tw_external.js new file mode 100644 index 00000000000..745c694bcdc --- /dev/null +++ b/test/unit/tw_external.js @@ -0,0 +1,58 @@ +const external = require('../../src/extension-support/tw-external'); +const {test} = require('tap'); + +test('importModule', t => { + external.importModule('data:text/javascript;,export%20default%201').then(mod => { + t.equal(mod.default, 1); + t.end(); + }); +}); + +test('fetch', t => { + external.fetch('data:text/plain;,test').then(res => { + res.text().then(text => { + t.equal(text, 'test'); + t.end(); + }); + }); +}); + +test('dataURL', t => { + global.FileReader = class { + readAsDataURL (blob) { + blob.arrayBuffer().then(arrayBuffer => { + const base64 = Buffer.from(arrayBuffer).toString('base64'); + this.result = `data:${blob.type};base64,${base64}`; + this.onload(); + }); + } + }; + + external.dataURL('data:text/plain;,doesthiswork').then(dataURL => { + t.equal(dataURL, `data:text/plain;base64,${btoa('doesthiswork')}`); + t.end(); + }); +}); + +test('blob', t => { + external.blob('data:text/plain;,test').then(blob => { + blob.text().then(blobText => { + t.equal(blobText, 'test'); + t.end(); + }); + }); +}); + +test('evalAndReturn', t => { + external.evalAndReturn('data:text/plain;,var%20x=20', 'x').then(result => { + t.equal(result, 20); + t.end(); + }); +}); + +test('relative URL throws', t => { + external.fetch('./test.js').catch(err => { + t.equal(err.message, `Unsupported URL: ./test.js`); + t.end(); + }); +}); From 475ffd0cb4f2f614172caec02405d5356c0f678e Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 1 Nov 2025 19:13:23 -0500 Subject: [PATCH 074/106] Update scratch-translate-extension-languages to 1.0.7 --- package-lock.json | 9 +++++---- package.json | 2 +- test/unit/extension_text_to_speech.js | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1bdcb228867..c64871a087e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "immutable": "3.8.2", "scratch-parser": "github:TurboWarp/scratch-parser#master", "scratch-sb1-converter": "0.2.7", - "scratch-translate-extension-languages": "0.0.20191118205314", + "scratch-translate-extension-languages": "^1.0.7", "text-encoding": "0.7.0", "uuid": "8.3.2", "worker-loader": "^1.1.1" @@ -13782,9 +13782,10 @@ } }, "node_modules/scratch-translate-extension-languages": { - "version": "0.0.20191118205314", - "resolved": "https://registry.npmjs.org/scratch-translate-extension-languages/-/scratch-translate-extension-languages-0.0.20191118205314.tgz", - "integrity": "sha512-r0lvpgQjPMjbhI2wROrgoXzBhCvWJdkbAqJMfl2CdNqrwBpUXqLvNNtI3VtNLPJAcp9VfxEylkU9lVZ0gvU46Q==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/scratch-translate-extension-languages/-/scratch-translate-extension-languages-1.0.7.tgz", + "integrity": "sha512-6+bQU9iVYv23T8J0SjpV6MTugm0y8myh/4DPgu1BGfccysdkaWzu3MkNGQyQRUlbqAiW9wM7ctfv3USPEkzTgg==", + "license": "BSD-3-Clause" }, "node_modules/script-loader": { "version": "0.7.2", diff --git a/package.json b/package.json index 2c841260adb..c126de34260 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "immutable": "3.8.2", "scratch-parser": "github:TurboWarp/scratch-parser#master", "scratch-sb1-converter": "0.2.7", - "scratch-translate-extension-languages": "0.0.20191118205314", + "scratch-translate-extension-languages": "^1.0.7", "text-encoding": "0.7.0", "uuid": "8.3.2", "worker-loader": "^1.1.1" diff --git a/test/unit/extension_text_to_speech.js b/test/unit/extension_text_to_speech.js index a6fd9dbfa61..83c065493c1 100644 --- a/test/unit/extension_text_to_speech.js +++ b/test/unit/extension_text_to_speech.js @@ -39,6 +39,6 @@ test('use localized spoken language name in place of localized written language ext.getEditorLanguage = () => 'es'; const languageMenu = ext.getLanguageMenu(); const localizedNameForChineseInSpanish = languageMenu.find(el => el.value === 'zh-cn').text; - t.strictEqual(localizedNameForChineseInSpanish, 'Chino (Mandarín)'); // i.e. should not be 'Chino (simplificado)' + t.strictEqual(localizedNameForChineseInSpanish, 'Chino (mandarín)'); // i.e. should not be 'Chino (simplificado)' t.end(); }); From 4187f550a086c31436dcad94f705671df9d5cb12 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 15 Nov 2025 19:00:09 -0600 Subject: [PATCH 075/106] Record which keys the project has used Related to https://github.com/TurboWarp/scratch-gui/issues/1106 --- src/io/keyboard.js | 13 +++++++++++++ test/unit/io_keyboard_tw.js | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/io/keyboard.js b/src/io/keyboard.js index ed6605feaf8..e2d2f0e93e3 100644 --- a/src/io/keyboard.js +++ b/src/io/keyboard.js @@ -53,6 +53,10 @@ class Keyboard { // tw: track last pressed key this.lastKeyPressed = ''; this._numeralKeyCodesToStringKey = new Map(); + /** + * Set of Scratch keys used by the project. + */ + this._usedKeys = new Set(); } /** @@ -198,6 +202,7 @@ class Keyboard { return this._keysPressed.length > 0; } const scratchKey = this._keyArgToScratchKey(keyArg); + this._usedKeys.add(scratchKey); return this._keysPressed.indexOf(scratchKey) > -1; } @@ -205,6 +210,14 @@ class Keyboard { getLastKeyPressed () { return this.lastKeyPressed; } + + /** + * @param {string} scratchKey Scratch key + * @returns {boolean} true if the project has used this key + */ + hasUsedKey (scratchKey) { + return this._usedKeys.has(scratchKey); + } } module.exports = Keyboard; diff --git a/test/unit/io_keyboard_tw.js b/test/unit/io_keyboard_tw.js index a365d11c5dc..4e76e3e9206 100644 --- a/test/unit/io_keyboard_tw.js +++ b/test/unit/io_keyboard_tw.js @@ -110,3 +110,21 @@ test('holding shift and key, releasing shift, waiting, then releasing key', t => t.end(); }); + +test('hasUsedKey', t => { + const rt = new Runtime(); + const k = new Keyboard(rt); + + t.equal(k.hasUsedKey('backspace'), false); + t.equal(k.hasUsedKey('delete'), false); + + k.getKeyIsDown('backspace'); + t.equal(k.hasUsedKey('backspace'), true); + t.equal(k.hasUsedKey('delete'), false); + + k.getKeyIsDown('delete'); + t.equal(k.hasUsedKey('backspace'), true); + t.equal(k.hasUsedKey('delete'), true); + + t.end(); +}); From 6f6845ba3c769f6bf8c3fa5cb490b314aff61253 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 22 Sep 2025 20:01:24 -0500 Subject: [PATCH 076/106] Fix all remaining negative zero bugs --- src/compiler/jsexecute.js | 11 ++++++++ src/compiler/jsgen.js | 4 +-- .../order-library-reverse.sb3.tw-snapshot | 14 +++++----- .../order-library.sb3.tw-snapshot | 14 +++++----- .../__snapshots__/tw-NaN.sb3.tw-snapshot | 24 ++++++++--------- ...ds-due-to-direct-recursion.sb3.tw-snapshot | 2 +- ...-with-null-for-variable-id.sb3.tw-snapshot | 4 +-- ...-does-not-use-rounded-size.sb3.tw-snapshot | 4 +-- ...-comparison-matrix-runtime.sb3.tw-snapshot | 10 +++---- ...ibility-layer-type-barrier.sb3.tw-snapshot | 2 +- .../tw-custom-report-repeat.sb3.tw-snapshot | 6 ++--- ...s-515-non-finite-direction.sb3.tw-snapshot | 2 +- ...-name-desync-name-fallback.sb3.tw-snapshot | 2 +- ...-zero-seconds-in-warp-mode.sb3.tw-snapshot | 2 +- .../tw-gh-249-quicksort.sb3.tw-snapshot | 24 ++++++++--------- ...dition-optimization-gh-276.sb3.tw-snapshot | 2 +- ...rp-loop-condition-analysis.sb3.tw-snapshot | 4 +-- ...cedure-return-non-existant.sb3.tw-snapshot | 2 +- ...procedure-return-recursion.sb3.tw-snapshot | 16 ++++++------ ...tw-procedure-return-simple.sb3.tw-snapshot | 10 +++---- ...edure-return-stops-scripts.sb3.tw-snapshot | 6 ++--- .../tw-procedure-return-warp.sb3.tw-snapshot | 6 ++--- ...-loop-double-yield-kouzeru.sb3.tw-snapshot | 2 +- ...ter-infinite-analyzer-loop.sb3.tw-snapshot | 4 +-- ...-restart-broadcast-threads.sb3.tw-snapshot | 4 +-- ...procedure-argument-casting.sb3.tw-snapshot | 4 +-- ...-keeps-running-until-yield.sb3.tw-snapshot | 2 +- .../__snapshots__/tw-tangent.sb3.tw-snapshot | 16 ++++++------ .../tw-unsafe-equals.sb3.tw-snapshot | 22 ++++++++-------- ...mbie-cube-escape-284516654.sb3.tw-snapshot | 2 +- .../order-library-reverse.sb3.tw-snapshot | 14 +++++----- .../warp-timer/order-library.sb3.tw-snapshot | 14 +++++----- .../warp-timer/tw-NaN.sb3.tw-snapshot | 24 ++++++++--------- ...ds-due-to-direct-recursion.sb3.tw-snapshot | 2 +- ...-with-null-for-variable-id.sb3.tw-snapshot | 4 +-- ...-does-not-use-rounded-size.sb3.tw-snapshot | 4 +-- ...-comparison-matrix-runtime.sb3.tw-snapshot | 10 +++---- ...ibility-layer-type-barrier.sb3.tw-snapshot | 2 +- .../tw-custom-report-repeat.sb3.tw-snapshot | 6 ++--- ...s-515-non-finite-direction.sb3.tw-snapshot | 2 +- ...-name-desync-name-fallback.sb3.tw-snapshot | 2 +- ...-zero-seconds-in-warp-mode.sb3.tw-snapshot | 2 +- .../tw-gh-249-quicksort.sb3.tw-snapshot | 26 +++++++++---------- ...dition-optimization-gh-276.sb3.tw-snapshot | 2 +- ...rp-loop-condition-analysis.sb3.tw-snapshot | 4 +-- ...cedure-return-non-existant.sb3.tw-snapshot | 2 +- ...procedure-return-recursion.sb3.tw-snapshot | 16 ++++++------ ...tw-procedure-return-simple.sb3.tw-snapshot | 10 +++---- ...edure-return-stops-scripts.sb3.tw-snapshot | 8 +++--- .../tw-procedure-return-warp.sb3.tw-snapshot | 6 ++--- ...-loop-double-yield-kouzeru.sb3.tw-snapshot | 2 +- ...ter-infinite-analyzer-loop.sb3.tw-snapshot | 4 +-- ...-restart-broadcast-threads.sb3.tw-snapshot | 4 +-- ...procedure-argument-casting.sb3.tw-snapshot | 4 +-- ...-keeps-running-until-yield.sb3.tw-snapshot | 2 +- ...w-simple-string-operations.sb3.tw-snapshot | 4 +-- .../warp-timer/tw-tangent.sb3.tw-snapshot | 16 ++++++------ .../tw-unsafe-equals.sb3.tw-snapshot | 22 ++++++++-------- ...rp-loop-condition-analysis.sb3.tw-snapshot | 4 +-- ...mbie-cube-escape-284516654.sb3.tw-snapshot | 2 +- 60 files changed, 231 insertions(+), 220 deletions(-) diff --git a/src/compiler/jsexecute.js b/src/compiler/jsexecute.js index 1f7847a3794..582a4fdb942 100644 --- a/src/compiler/jsexecute.js +++ b/src/compiler/jsexecute.js @@ -223,6 +223,17 @@ runtimeFunctions.retire = `const retire = () => { thread.target.runtime.sequencer.retireThread(thread); }`; +/** + * Converts NaN to zero. Used to match Scratch's string-to-number. + * Unlike (x || 0), -0 stays as -0 and is not converted to 0. + * This function is written in this specific way to make it easy for browsers to inline. + * We've found that calling isNaN() causes slowdowns in Firefox, so instead we utilize the + * fact that NaN is the only JavaScript value that does not equal itself. + * @param {number} value A number. Might be NaN. + * @returns {number} A number. Never NaN. + */ +runtimeFunctions.toNotNaN = `const toNotNaN = value => value === value ? value : 0`; + /** * Scratch cast to boolean. * Similar to Cast.toBoolean() diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 65ffe9c42d2..a79b931e37d 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -185,9 +185,9 @@ class JSGenerator { return `(+${this.descendInput(node.target.toType(InputType.BOOLEAN))})`; } if (node.target.isAlwaysType(InputType.NUMBER_OR_NAN)) { - return `(${this.descendInput(node.target)} || 0)`; + return `toNotNaN(${this.descendInput(node.target)})`; } - return `(+${this.descendInput(node.target)} || 0)`; + return `toNotNaN(+${this.descendInput(node.target)})`; case InputOpcode.CAST_NUMBER_OR_NAN: return `(+${this.descendInput(node.target)})`; case InputOpcode.CAST_NUMBER_INDEX: diff --git a/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot b/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot index 96c7ced79c1..466e9f50eee 100644 --- a/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot @@ -9,14 +9,14 @@ const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "]4hbk*5ix]V00h|!x1oy", null); } else { @@ -32,7 +32,7 @@ const b1 = stage.variables["p]KODv+)+:l=%NT~j3/d-wait"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "1Ba%a0GIK#hwJ46y=WVt", null); thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { @@ -40,7 +40,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a1 = Math.max(0, 1000 * (+b1.value || 0)); +var a1 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a1) { @@ -48,7 +48,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a2 = Math.max(0, 1000 * (+b1.value || 0)); +var a2 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a2) { @@ -67,14 +67,14 @@ const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "0i[-T:vYTt=bi47@byUE", null); } else { diff --git a/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot b/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot index 5145078f7aa..49cfd33b5e1 100644 --- a/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot @@ -8,7 +8,7 @@ const b1 = stage.variables["):/PVGTvoVRvq(ikGwRE-wait"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "s+@:|^WPr8]N1Y9Hk2f5", null); thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { @@ -16,7 +16,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a1 = Math.max(0, 1000 * (+b1.value || 0)); +var a1 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a1) { @@ -24,7 +24,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a2 = Math.max(0, 1000 * (+b1.value || 0)); +var a2 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a2) { @@ -43,14 +43,14 @@ const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "RSQ{nVCc)6E)(`KlnFCF", null); } else { @@ -67,14 +67,14 @@ const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "KP?op(=Vg2#;@]!,C#.~", null); } else { diff --git a/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot index 655a04a4e77..a760bbe3a6b 100644 --- a/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot @@ -12,61 +12,61 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aA", if ((("" + (0 * Infinity)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "/", null); } -if (((((0 * Infinity) || 0) * 1) === 0)) { +if (((toNotNaN((0 * Infinity)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "?", null); } if ((("" + ((Math.acos(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "=", null); } -if ((((((Math.acos(1.01) * 180) / Math.PI) || 0) * 1) === 0)) { +if (((toNotNaN(((Math.acos(1.01) * 180) / Math.PI)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "]", null); } if ((("" + ((Math.asin(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "_", null); } -if ((((((Math.asin(1.01) * 180) / Math.PI) || 0) * 1) === 0)) { +if (((toNotNaN(((Math.asin(1.01) * 180) / Math.PI)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "{", null); } if ((("" + (0 / 0)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "}", null); } -if (((((0 / 0) || 0) * 1) === 0)) { +if (((toNotNaN((0 / 0)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aa", null); } if ((("" + Math.sqrt(-1)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ac", null); } -if ((((Math.sqrt(-1) || 0) * 1) === 0)) { +if (((toNotNaN(Math.sqrt(-1)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ae", null); } if ((("" + mod(0, 0)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ag", null); } -if ((((mod(0, 0) || 0) * 1) === 0)) { +if (((toNotNaN(mod(0, 0)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ai", null); } if ((("" + Math.log(-1)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ak", null); } -if ((((Math.log(-1) || 0) * 1) === 0)) { +if (((toNotNaN(Math.log(-1)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "am", null); } if ((("" + (Math.log(-1) / Math.LN10)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ao", null); } -if (((((Math.log(-1) / Math.LN10) || 0) * 1) === 0)) { +if (((toNotNaN((Math.log(-1) / Math.LN10)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aq", null); } -if (((((Math.round(Math.sin((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) { +if (((toNotNaN((Math.round(Math.sin((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "as", null); } -if (((((Math.round(Math.cos((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) { +if (((toNotNaN((Math.round(Math.cos((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "au", null); } -if ((((tan((1 / 0)) || 0) * 1) === 0)) { +if (((toNotNaN(tan((1 / 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)) { +if (((toNotNaN(runtime.ext_scratch3_operators._random((-1 / 0), (1 / 0))) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ax", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ":", null); diff --git a/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot index 8536858fee5..75de04704b4 100644 --- a/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot @@ -22,7 +22,7 @@ retire(); return; return function* genXYZ_non_warp_recursion_ (p0) { if (compareGreaterThan(p0, 0)) { yield; -yield* thread.procedures["Znon-warp recursion %s"](((+p0 || 0) - 1)); +yield* thread.procedures["Znon-warp recursion %s"]((toNotNaN(+p0) - 1)); } return ""; }; }) 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 index 17631a6dc0a..2e9766c0409 100644 --- 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 @@ -21,7 +21,7 @@ retire(); return; 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)) { +if ((toNotNaN(+b0.value) === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 1",}, b1, false, false, "m", null); } retire(); return; @@ -32,7 +32,7 @@ retire(); return; const b0 = stage.variables[")|GMR5fz;%F_H,c0wGVM"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -if (((+b0.value || 0) === 2)) { +if ((toNotNaN(+b0.value) === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 2",}, b1, false, false, "q", null); } retire(); return; diff --git a/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot index b7f47584e4f..89d78f7e429 100644 --- a/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot @@ -10,11 +10,11 @@ yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "()* target.setSize(96); b1.value = 0; while (!(100 === Math.round(target.size))) { -b1.value = ((+b1.value || 0) + 1); +b1.value = (toNotNaN(+b1.value) + 1); target.setSize(target.size + ((100 - Math.round(target.size)) / 10)); yield; } -if (((+b1.value || 0) === 20)) { +if ((toNotNaN(+b1.value) === 20)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "FPDFR?Wwq)kLj0A$0D{@", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "1,vLoJ4OQBv+Q#$VoYf=", null); diff --git a/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot index 6c6b55de7f5..946a0afb6f6 100644 --- a/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot @@ -24,19 +24,19 @@ thread.procedures["Wsetup values"](); b0.value = 0; b1.value = 0; for (var a0 = b2.value.length; a0 > 0; a0--) { -b1.value = ((+b1.value || 0) + 1); +b1.value = (toNotNaN(+b1.value) + 1); b3.value = 0; for (var a1 = b2.value.length; a1 > 0; a1--) { -b3.value = ((+b3.value || 0) + 1); -b0.value = ((+b0.value || 0) + 1); +b3.value = (toNotNaN(+b3.value) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if (!compareEqual(compareGreaterThan(listGet(b2.value, b1.value), (b2.value[(b3.value | 0) - 1] ?? "")), (b4.value[(b0.value | 0) - 1] ?? ""))) { yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be > " + ("" + (b2.value[(b3.value | 0) - 1] ?? ""))))),}, b5, true, false, "]", null); } -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if (!compareEqual(compareEqual(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be = " + ("" + listGet(b2.value, b3.value))))),}, b5, true, false, "|", null); } -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if (!compareEqual(compareLessThan(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be < " + ("" + listGet(b2.value, b3.value))))),}, b5, true, true, "ab", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} diff --git a/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot index 4f23a53e349..3cc61e9b75d 100644 --- a/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot @@ -10,7 +10,7 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); b1.value = (0 + 0); yield* executeInCompatibilityLayer({"MESSAGE":"Hello!","SECS":0.1,}, b2, false, false, "d", null); -if ((((+b1.value || 0) + 2) === 2)) { +if (((toNotNaN(+b1.value) + 2) === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "i", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "m", null); diff --git a/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot index 060537d67aa..3429d7b3b4d 100644 --- a/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot @@ -8,11 +8,11 @@ const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); b1.value = 0; -for (var a0 = (+thread.procedures["Zblock name"]() || 0); a0 >= 0.5; a0--) { -b1.value = ((+b1.value || 0) + 1); +for (var a0 = toNotNaN(+thread.procedures["Zblock name"]()); a0 >= 0.5; a0--) { +b1.value = (toNotNaN(+b1.value) + 1); yield; } -if (((+b1.value || 0) === 40)) { +if ((toNotNaN(+b1.value) === 40)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "n", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot index 00bb8c4d3e3..87f027a3c1c 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot @@ -15,7 +15,7 @@ target.setDirection((1 / 0)); if ((target.direction === 95)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 2",}, b0, false, false, "r", null); } -target.setDirection(((0 / 0) || 0)); +target.setDirection(toNotNaN((0 / 0))); if ((target.direction === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 3",}, b0, false, false, "u", null); } diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot index d52a998ab3e..4168b881940 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot @@ -15,7 +15,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass variable",}, b0, false, fals b2.value = []; b2.value.push(3); b2._monitorUpToDate = false; -if (((+(b2.value[1 - 1] ?? "") || 0) === 3)) { +if ((toNotNaN(+(b2.value[1 - 1] ?? "")) === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass list",}, b0, false, false, "m", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot index af096a9106d..04776d0d68a 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot @@ -73,7 +73,7 @@ return ""; const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { while (true) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); yield; } retire(); return; 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 1dc2a0741df..df951a5196f 100644 --- a/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot @@ -41,9 +41,9 @@ if (!compareEqual((b2.value[(b1.value | 0) - 1] ?? ""), (b3.value[(b1.value | 0) b0.value = 0; yield* executeInCompatibilityLayer({"MESSAGE":("fail mismatch at index " + ("" + b1.value)),}, b4, true, false, ",", null); } -b1.value = ((+b1.value || 0) + 1); +b1.value = (toNotNaN(+b1.value) + 1); } -if (((+b0.value || 0) === 1)) { +if ((toNotNaN(+b0.value) === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass sorted",}, b4, true, false, "aE", null); } return ""; @@ -62,16 +62,16 @@ const b7 = target.variables["JIHtr29*ug5G;5*`f2.K-min-"]; const b8 = target.variables["JIHtr29*ug5G;5*`f2.K-j-"]; return function funXYZ_qsort__ (p0,p1) { if (compareLessThan(p0, p1)) { -if (!(((+p1 || 0) - (+p0 || 0)) <= 7)) { -b0.value = (b1.value[(((((+p1 || 0) + (+p0 || 0)) || 0) / 2) | 0) - 1] ?? ""); +if (!((toNotNaN(+p1) - toNotNaN(+p0)) <= 7)) { +b0.value = (b1.value[((toNotNaN((toNotNaN(+p1) + toNotNaN(+p0))) / 2) | 0) - 1] ?? ""); b2.value = p0; b3.value = p1; while (true) { while (compareLessThan(listGet(b1.value, b2.value), b0.value)) { -b2.value = ((+b2.value || 0) + 1); +b2.value = (toNotNaN(+b2.value) + 1); } while (compareGreaterThan(listGet(b1.value, b3.value), b0.value)) { -b3.value = ((+b3.value || 0) + -1); +b3.value = (toNotNaN(+b3.value) + -1); } if (compareGreaterThan(b2.value, b3.value)) { thread.procedures["Wqsort %s %s"](p0,b3.value); @@ -81,17 +81,17 @@ return ""; b4.value = listGet(b1.value, b2.value); listReplace(b1, b2.value, listGet(b1.value, b3.value)); listReplace(b1, b3.value, b4.value); -b2.value = ((+b2.value || 0) + 1); -b3.value = ((+b3.value || 0) + -1); +b2.value = (toNotNaN(+b2.value) + 1); +b3.value = (toNotNaN(+b3.value) + -1); } } } else { b5.value = p0; -for (var a0 = (((+p1 || 0) - (+p0 || 0)) || 0); a0 >= 0.5; a0--) { +for (var a0 = toNotNaN((toNotNaN(+p1) - toNotNaN(+p0))); a0 >= 0.5; a0--) { b6.value = b5.value; b7.value = listGet(b1.value, b5.value); -b8.value = ((+b5.value || 0) + 1); -for (var a1 = (((+p1 || 0) - (+b5.value || 0)) || 0); a1 >= 0.5; a1--) { +b8.value = (toNotNaN(+b5.value) + 1); +for (var a1 = toNotNaN((toNotNaN(+p1) - toNotNaN(+b5.value))); a1 >= 0.5; a1--) { if (compareLessThan((b1.value[(b8.value | 0) - 1] ?? ""), b7.value)) { b7.value = (b1.value[(b8.value | 0) - 1] ?? ""); b6.value = b8.value; @@ -104,7 +104,7 @@ b4.value = listGet(b1.value, b5.value); listReplace(b1, b5.value, b7.value); listReplace(b1, b6.value, b4.value); } -b5.value = ((+b5.value || 0) + 1); +b5.value = (toNotNaN(+b5.value) + 1); } } } 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 index 20e23cc6056..424a7c8e5f0 100644 --- 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 @@ -22,7 +22,7 @@ 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); +b0.value = (toNotNaN(+b0.value) + 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 index 018d12fbdc0..1a3fb7c91b1 100644 --- 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 @@ -17,11 +17,11 @@ b1._monitorUpToDate = false; b2.value = 0; b3.value = "bwah"; while (!(("" + b3.value).toLowerCase() === "eof".toLowerCase())) { -b2.value = ((+b2.value || 0) + 1); +b2.value = (toNotNaN(+b2.value) + 1); b3.value = (b1.value[(b2.value | 0) - 1] ?? ""); yield; } -if (((+b2.value || 0) === 2)) { +if ((toNotNaN(+b2.value) === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "q", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null); diff --git a/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot index 2aa9b207d24..d3a12562b1a 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot @@ -7,7 +7,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; return function* genXYZ () { b0.value = 0; while (true) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); thread.timer = timer(); var a0 = Math.max(0, 1000 * -1); runtime.requestRedraw(); 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 c242a148a32..2952a58ecbc 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot @@ -10,7 +10,7 @@ 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 ((toNotNaN(+b1.value) === 4)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp recursion yields",}, b0, false, false, "ao", null); } b1.value = 0; @@ -20,7 +20,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass warp recursion does not yiel } b1.value = 0; b2.value = (yield* thread.procedures["Zfib %s"](7)); -if (((+b1.value || 0) === 20)) { +if ((toNotNaN(+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"); @@ -34,7 +34,7 @@ retire(); return; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_non_warp_recursion_s (p0) { if (compareGreaterThan(p0, 0)) { -return (yield* yieldThenCallGenerator(thread.procedures["Znon warp recursion should yield %s"], ((+p0 || 0) - 1))); +return (yield* yieldThenCallGenerator(thread.procedures["Znon warp recursion should yield %s"], (toNotNaN(+p0) - 1))); } return ""; }; }) @@ -43,7 +43,7 @@ return ""; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_warp_recursion_shoul (p0) { if (compareGreaterThan(p0, 0)) { -return thread.procedures["Wwarp recursion should not yield %s"](((+p0 || 0) - 1)); +return thread.procedures["Wwarp recursion should not yield %s"]((toNotNaN(+p0) - 1)); } return ""; }; }) @@ -54,7 +54,7 @@ return function* genXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { return p0; } else { -return ((+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], ((+p0 || 0) - 1))) || 0) + (+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], ((+p0 || 0) - 2))) || 0)); +return (toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], (toNotNaN(+p0) - 1)))) + toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], (toNotNaN(+p0) - 2))))); } return ""; }; }) @@ -67,8 +67,8 @@ const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_recursing_yields_bet (p0) { if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = 0; -b1.value = ((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0) + (+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0)) || 0)) || 0)) || 0)) || 0)); -if (((+b0.value || 0) === 3)) { +b1.value = (toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3))) + toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)))))))))))); +if ((toNotNaN(+b0.value) === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recursing between calls yields final",}, b2, false, false, "aK", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":"fail recursing between calls yields final",}, b2, false, false, "aL", null); @@ -131,7 +131,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; return function* genXYZ () { b0.value = 0; while (true) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); thread.timer = timer(); var a0 = Math.max(0, 1000 * -1); runtime.requestRedraw(); diff --git a/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot index 3b4a34ac8e8..e356c359bf8 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot @@ -13,10 +13,10 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass simplest",}, b0, false, fals if ((("" + thread.procedures["Znesting 1"]()).toLowerCase() === "42-54".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass nesting1",}, b0, false, false, "=", null); } -if (((+thread.procedures["Wwarp fib %s"](12) || 0) === 144)) { +if ((toNotNaN(+thread.procedures["Wwarp fib %s"](12)) === 144)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass fib 12",}, b0, false, false, "@", null); } -if (((+thread.procedures["Wfactorial %s"](12) || 0) === 479001600)) { +if ((toNotNaN(+thread.procedures["Wfactorial %s"](12)) === 479001600)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass factorial 12",}, b0, false, false, "]", null); } b1.value = (yield* thread.procedures["Zno shadowing 1 %s %s"]("f","g")); @@ -53,7 +53,7 @@ return ""; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_factorial_ (p0) { if (compareGreaterThan(p0, 1)) { -return ((+p0 || 0) * (+thread.procedures["Wfactorial %s"](((+p0 || 0) - 1)) || 0)); +return (toNotNaN(+p0) * toNotNaN(+thread.procedures["Wfactorial %s"]((toNotNaN(+p0) - 1)))); } return 1; return ""; @@ -88,7 +88,7 @@ return ""; // Sprite1 Znesting 3 %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_3__ (p0,p1) { -return ((+p0 || 0) * (+p1 || 0)); +return (toNotNaN(+p0) * toNotNaN(+p1)); return ""; }; }) @@ -98,7 +98,7 @@ return function funXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { return p0; } else { -return ((+thread.procedures["Wfib %s"](((+p0 || 0) - 1)) || 0) + (+thread.procedures["Wfib %s"](((+p0 || 0) - 2)) || 0)); +return (toNotNaN(+thread.procedures["Wfib %s"]((toNotNaN(+p0) - 1))) + toNotNaN(+thread.procedures["Wfib %s"]((toNotNaN(+p0) - 2)))); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot index 9159b5c7232..89a6e4963fb 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot @@ -8,11 +8,11 @@ const b1 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "f", null); yield* thread.procedures["Wreturn stops the script immediately"](); -if (((+b1.value || 0) === 25)) { +if ((toNotNaN(+b1.value) === 25)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass return stopped the script immediately",}, b0, false, false, "u", null); } yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "Test return outside of custom block" })); -if (((+b1.value || 0) === 18)) { +if ((toNotNaN(+b1.value) === 18)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass return worked to stop outside of custom block",}, b0, false, false, "x", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "v", null); @@ -41,7 +41,7 @@ const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; return function* genXYZ () { b0.value = 0; while (true) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 18)) { retire(); return; } diff --git a/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot index d6aad6c51fb..faa31335951 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot @@ -7,7 +7,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; return function* genXYZ () { b0.value = 0; while (true) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); thread.timer = timer(); var a0 = Math.max(0, 1000 * -1); runtime.requestRedraw(); @@ -49,7 +49,7 @@ yield; thread.timer = null; yield; } -if (((+b0.value || 0) === 5)) { +if ((toNotNaN(+b0.value) === 5)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 1",}, b1, false, false, "R", null); } if ((("" + (yield* thread.procedures["Wverify runs warp %s"]((yield* thread.procedures["Zverify runs non warp %s"]((yield* thread.procedures["Wverify runs warp %s"]("abc"))))))).toLowerCase() === "warp: non warp: warp: abc".toLowerCase())) { @@ -67,7 +67,7 @@ yield; thread.timer = null; yield; } -if (((+b0.value || 0) === 5)) { +if ((toNotNaN(+b0.value) === 5)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 2",}, b1, false, false, "W", null); } return ""; diff --git a/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot index 646fdfd02e4..4c166406d91 100644 --- a/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot @@ -30,7 +30,7 @@ return function* genXYZ () { b0.value = 0; yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b1, false, false, "0/2-)Gp^^=haQ1OMD.xb", null); for (var a0 = 15; a0 > 0; a0--) { -if (((+b2.value || 0) === 200)) { +if ((toNotNaN(+b2.value) === 200)) { b2.value = 50; } else { b2.value = 200; diff --git a/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot index 2244a1bfbde..e2ba9156759 100644 --- a/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot @@ -15,8 +15,8 @@ retire(); return; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = target.variables["ts-.PQ{/]mN_9@MbG:m/"]; return function funXYZ_test_1 () { -for (var a0 = (+thread.procedures["Wany procedure reporter"]() || 0); a0 >= 0.5; a0--) { -b0.value = ((+b0.value || 0) + 1); +for (var a0 = toNotNaN(+thread.procedures["Wany procedure reporter"]()); a0 >= 0.5; a0--) { +b0.value = (toNotNaN(+b0.value) + 1); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/tw-restart-broadcast-threads.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-restart-broadcast-threads.sb3.tw-snapshot index 84ea17ea2e8..2356e02f907 100644 --- a/test/snapshot/__snapshots__/tw-restart-broadcast-threads.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-restart-broadcast-threads.sb3.tw-snapshot @@ -18,7 +18,7 @@ while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -if (((+b1.value || 0) === 1)) { +if ((toNotNaN(+b1.value) === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "`SX*FG*Lwo*0_T=box-@", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "|#`zzPA_x%{`FyIAQhb4", null); @@ -29,6 +29,6 @@ retire(); return; (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 = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot index 88f7ab0b015..aff4757d938 100644 --- a/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot @@ -7,11 +7,11 @@ const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "J#qm1yA(@Z6mj%Mgh;0X", null); thread.procedures["Zswitch %s"]("1"); -if ((((target.currentCostume + 1) === 2) && ((+target.getCostumes()[target.currentCostume].name || 0) === 1))) { +if ((((target.currentCostume + 1) === 2) && (toNotNaN(+target.getCostumes()[target.currentCostume].name) === 1))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ";DM$.QW6o-O+T/oBdqt!", null); } thread.procedures["Zswitch %s"]("2"); -if ((((target.currentCostume + 1) === 1) && ((+target.getCostumes()[target.currentCostume].name || 0) === 2))) { +if ((((target.currentCostume + 1) === 1) && (toNotNaN(+target.getCostumes()[target.currentCostume].name) === 2))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "71a9Slk0w=^~x;5T@nw,", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb(Mu?gdTIH^;kC_", null); diff --git a/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot index 62e48ec1cae..ff8ab6ec888 100644 --- a/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot @@ -29,7 +29,7 @@ yield; } b1.value = 2; } else { -if (((+b1.value || 0) === 1)) { +if ((toNotNaN(+b1.value) === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b2, false, false, "p", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b2, false, false, "n", null); diff --git a/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot index b2ccf9ce3a3..41796eb6fd9 100644 --- a/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot @@ -9,46 +9,46 @@ yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b0, false, false, "p" if (compareEqual(tan(0), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 0",}, b0, false, false, "O", null); } -if (((tan(90) || 0) === Infinity)) { +if ((toNotNaN(tan(90)) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 90",}, b0, false, false, "G", null); } if (compareEqual(tan(180), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 180",}, b0, false, false, "I", null); } -if (((tan(270) || 0) === -Infinity)) { +if ((toNotNaN(tan(270)) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 270",}, b0, false, false, "K", null); } if (compareEqual(tan(360), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 360",}, b0, false, false, "M", null); } -if (((tan(450) || 0) === Infinity)) { +if ((toNotNaN(tan(450)) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 450",}, b0, false, false, "Q", null); } if (compareEqual(tan(540), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 540",}, b0, false, false, "S", null); } -if (((tan(630) || 0) === -Infinity)) { +if ((toNotNaN(tan(630)) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 630",}, b0, false, false, "U", null); } if (compareEqual(tan(720), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 720",}, b0, false, false, "W", null); } -if (((tan(810) || 0) === Infinity)) { +if ((toNotNaN(tan(810)) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 810",}, b0, false, false, "Y", null); } -if (((tan(-90) || 0) === -Infinity)) { +if ((toNotNaN(tan(-90)) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -90",}, b0, false, false, "0", null); } if (compareEqual(tan(-180), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -180",}, b0, false, false, "2", null); } -if (((tan(-270) || 0) === Infinity)) { +if ((toNotNaN(tan(-270)) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -270",}, b0, false, false, "4", null); } if (compareEqual(tan(-360), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -360",}, b0, false, false, "6", null); } -if (((tan(-450) || 0) === -Infinity)) { +if ((toNotNaN(tan(-450)) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -450",}, b0, false, false, "9", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "8", null); diff --git a/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot index 3804c87f6b3..014751f5d1e 100644 --- a/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot @@ -18,43 +18,43 @@ b1.value = 10; if ((b1.value === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 3",}, b0, false, false, "Ul:BCck-}Fvdux~x#$${", null); } -if (((+b1.value || 0) === 10)) { +if ((toNotNaN(+b1.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 4",}, b0, false, false, "8]2$7P)o#+#Lo]mFSBbx", null); } -if (((+b1.value || 0) === 10)) { +if ((toNotNaN(+b1.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 5",}, b0, false, false, "ZU^{OfKTg|+Au$$q0[]u", null); } for (var a0 = 1; a0 > 0; a0--) { -if (((+b1.value || 0) === 10)) { +if ((toNotNaN(+b1.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 6",}, b0, false, false, "HB+_IN}6=K[*ksxKXH0`", null); } -if (((+b1.value || 0) === 10)) { +if ((toNotNaN(+b1.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 7",}, b0, false, false, ";73ODiwcp8IthYURTX;S", null); } -if (((+b1.value || 0) === 10)) { +if ((toNotNaN(+b1.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 8",}, b0, false, true, "${[MFmBL-D*1rbas9Q89", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } yield; } b2.value = "010"; -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 9",}, b0, false, false, "#.`@SBj!g-c0:_q/tMZo", null); } -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 10",}, b0, false, false, "B`o?V6/q6g),/2w};a#y", null); } -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 11",}, b0, false, false, "TJ:#TkYBys*!RYiKLXb)", null); } for (var a1 = 1; a1 > 0; a1--) { -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 12",}, b0, false, false, ",Z,~10Qo~j;(+VL+I3q:", null); } -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 13",}, b0, false, false, "|Mqx([(26M%#ggW9)U0s", null); } -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 14",}, b0, false, true, "YvtiKF231lU8p5Qd97RP", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } diff --git a/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot index 5a401185577..229d2814438 100644 --- a/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot @@ -24,7 +24,7 @@ retire(); return; const b0 = stage.variables["7qur6!bGgvC9I(Nd5.HP"]; const b1 = stage.variables["sUOp@-6J4y0PqwiXit4!"]; return function* genXYZ () { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 5)) { b1.value = "end"; } diff --git a/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot index 96c7ced79c1..466e9f50eee 100644 --- a/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot @@ -9,14 +9,14 @@ const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "]4hbk*5ix]V00h|!x1oy", null); } else { @@ -32,7 +32,7 @@ const b1 = stage.variables["p]KODv+)+:l=%NT~j3/d-wait"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "1Ba%a0GIK#hwJ46y=WVt", null); thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { @@ -40,7 +40,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a1 = Math.max(0, 1000 * (+b1.value || 0)); +var a1 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a1) { @@ -48,7 +48,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a2 = Math.max(0, 1000 * (+b1.value || 0)); +var a2 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a2) { @@ -67,14 +67,14 @@ const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "0i[-T:vYTt=bi47@byUE", null); } else { diff --git a/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot index 5145078f7aa..49cfd33b5e1 100644 --- a/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot @@ -8,7 +8,7 @@ const b1 = stage.variables["):/PVGTvoVRvq(ikGwRE-wait"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "s+@:|^WPr8]N1Y9Hk2f5", null); thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { @@ -16,7 +16,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a1 = Math.max(0, 1000 * (+b1.value || 0)); +var a1 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a1) { @@ -24,7 +24,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a2 = Math.max(0, 1000 * (+b1.value || 0)); +var a2 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a2) { @@ -43,14 +43,14 @@ const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "RSQ{nVCc)6E)(`KlnFCF", null); } else { @@ -67,14 +67,14 @@ const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); -var a0 = Math.max(0, 1000 * (+b1.value || 0)); +var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "KP?op(=Vg2#;@]!,C#.~", null); } else { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot index 655a04a4e77..a760bbe3a6b 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot @@ -12,61 +12,61 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aA", if ((("" + (0 * Infinity)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "/", null); } -if (((((0 * Infinity) || 0) * 1) === 0)) { +if (((toNotNaN((0 * Infinity)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "?", null); } if ((("" + ((Math.acos(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "=", null); } -if ((((((Math.acos(1.01) * 180) / Math.PI) || 0) * 1) === 0)) { +if (((toNotNaN(((Math.acos(1.01) * 180) / Math.PI)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "]", null); } if ((("" + ((Math.asin(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "_", null); } -if ((((((Math.asin(1.01) * 180) / Math.PI) || 0) * 1) === 0)) { +if (((toNotNaN(((Math.asin(1.01) * 180) / Math.PI)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "{", null); } if ((("" + (0 / 0)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "}", null); } -if (((((0 / 0) || 0) * 1) === 0)) { +if (((toNotNaN((0 / 0)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aa", null); } if ((("" + Math.sqrt(-1)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ac", null); } -if ((((Math.sqrt(-1) || 0) * 1) === 0)) { +if (((toNotNaN(Math.sqrt(-1)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ae", null); } if ((("" + mod(0, 0)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ag", null); } -if ((((mod(0, 0) || 0) * 1) === 0)) { +if (((toNotNaN(mod(0, 0)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ai", null); } if ((("" + Math.log(-1)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ak", null); } -if ((((Math.log(-1) || 0) * 1) === 0)) { +if (((toNotNaN(Math.log(-1)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "am", null); } if ((("" + (Math.log(-1) / Math.LN10)).toLowerCase() === "NaN".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ao", null); } -if (((((Math.log(-1) / Math.LN10) || 0) * 1) === 0)) { +if (((toNotNaN((Math.log(-1) / Math.LN10)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aq", null); } -if (((((Math.round(Math.sin((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) { +if (((toNotNaN((Math.round(Math.sin((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "as", null); } -if (((((Math.round(Math.cos((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10) || 0) * 1) === 0)) { +if (((toNotNaN((Math.round(Math.cos((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10)) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "au", null); } -if ((((tan((1 / 0)) || 0) * 1) === 0)) { +if (((toNotNaN(tan((1 / 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)) { +if (((toNotNaN(runtime.ext_scratch3_operators._random((-1 / 0), (1 / 0))) * 1) === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ax", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ":", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot index 8536858fee5..75de04704b4 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot @@ -22,7 +22,7 @@ retire(); return; return function* genXYZ_non_warp_recursion_ (p0) { if (compareGreaterThan(p0, 0)) { yield; -yield* thread.procedures["Znon-warp recursion %s"](((+p0 || 0) - 1)); +yield* thread.procedures["Znon-warp recursion %s"]((toNotNaN(+p0) - 1)); } 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 index 17631a6dc0a..2e9766c0409 100644 --- 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 @@ -21,7 +21,7 @@ retire(); return; 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)) { +if ((toNotNaN(+b0.value) === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 1",}, b1, false, false, "m", null); } retire(); return; @@ -32,7 +32,7 @@ retire(); return; const b0 = stage.variables[")|GMR5fz;%F_H,c0wGVM"]; const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -if (((+b0.value || 0) === 2)) { +if ((toNotNaN(+b0.value) === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 2",}, b1, false, false, "q", null); } retire(); return; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot index b7f47584e4f..89d78f7e429 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot @@ -10,11 +10,11 @@ yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "()* target.setSize(96); b1.value = 0; while (!(100 === Math.round(target.size))) { -b1.value = ((+b1.value || 0) + 1); +b1.value = (toNotNaN(+b1.value) + 1); target.setSize(target.size + ((100 - Math.round(target.size)) / 10)); yield; } -if (((+b1.value || 0) === 20)) { +if ((toNotNaN(+b1.value) === 20)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "FPDFR?Wwq)kLj0A$0D{@", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "1,vLoJ4OQBv+Q#$VoYf=", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot index 656fc83d0bc..1f7c3725ee5 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot @@ -24,19 +24,19 @@ thread.procedures["Wsetup values"](); b0.value = 0; b1.value = 0; for (var a0 = b2.value.length; a0 > 0; a0--) { -b1.value = ((+b1.value || 0) + 1); +b1.value = (toNotNaN(+b1.value) + 1); b3.value = 0; for (var a1 = b2.value.length; a1 > 0; a1--) { -b3.value = ((+b3.value || 0) + 1); -b0.value = ((+b0.value || 0) + 1); +b3.value = (toNotNaN(+b3.value) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if (!compareEqual(compareGreaterThan(listGet(b2.value, b1.value), (b2.value[(b3.value | 0) - 1] ?? "")), (b4.value[(b0.value | 0) - 1] ?? ""))) { yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be > " + ("" + (b2.value[(b3.value | 0) - 1] ?? ""))))),}, b5, true, false, "]", null); } -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if (!compareEqual(compareEqual(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be = " + ("" + listGet(b2.value, b3.value))))),}, b5, true, false, "|", null); } -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if (!compareEqual(compareLessThan(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be < " + ("" + listGet(b2.value, b3.value))))),}, b5, true, true, "ab", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} diff --git a/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot index 4f23a53e349..3cc61e9b75d 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot @@ -10,7 +10,7 @@ return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); b1.value = (0 + 0); yield* executeInCompatibilityLayer({"MESSAGE":"Hello!","SECS":0.1,}, b2, false, false, "d", null); -if ((((+b1.value || 0) + 2) === 2)) { +if (((toNotNaN(+b1.value) + 2) === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "i", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "m", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot index 060537d67aa..3429d7b3b4d 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot @@ -8,11 +8,11 @@ const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); b1.value = 0; -for (var a0 = (+thread.procedures["Zblock name"]() || 0); a0 >= 0.5; a0--) { -b1.value = ((+b1.value || 0) + 1); +for (var a0 = toNotNaN(+thread.procedures["Zblock name"]()); a0 >= 0.5; a0--) { +b1.value = (toNotNaN(+b1.value) + 1); yield; } -if (((+b1.value || 0) === 40)) { +if ((toNotNaN(+b1.value) === 40)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "n", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot index 00bb8c4d3e3..87f027a3c1c 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot @@ -15,7 +15,7 @@ target.setDirection((1 / 0)); if ((target.direction === 95)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 2",}, b0, false, false, "r", null); } -target.setDirection(((0 / 0) || 0)); +target.setDirection(toNotNaN((0 / 0))); if ((target.direction === 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 3",}, b0, false, false, "u", null); } diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot index d52a998ab3e..4168b881940 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot @@ -15,7 +15,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass variable",}, b0, false, fals b2.value = []; b2.value.push(3); b2._monitorUpToDate = false; -if (((+(b2.value[1 - 1] ?? "") || 0) === 3)) { +if ((toNotNaN(+(b2.value[1 - 1] ?? "")) === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass list",}, b0, false, false, "m", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot index 7fe8cccf8ce..b963785b05c 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot @@ -75,7 +75,7 @@ return ""; const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { while (true) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); yield; } retire(); return; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot index 8b5d4a41ffa..7021f041aa5 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot @@ -42,10 +42,10 @@ if (!compareEqual(listGet(b2.value, b1.value), listGet(b3.value, b1.value))) { b0.value = 0; yield* executeInCompatibilityLayer({"MESSAGE":("fail mismatch at index " + ("" + b1.value)),}, b4, true, false, ",", null); } -b1.value = ((+b1.value || 0) + 1); +b1.value = (toNotNaN(+b1.value) + 1); if (isStuck()) yield; } -if (((+b0.value || 0) === 1)) { +if ((toNotNaN(+b0.value) === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass sorted",}, b4, true, false, "aE", null); } return ""; @@ -64,17 +64,17 @@ const b7 = target.variables["JIHtr29*ug5G;5*`f2.K-min-"]; const b8 = target.variables["JIHtr29*ug5G;5*`f2.K-j-"]; return function* genXYZ_qsort__ (p0,p1) { if (compareLessThan(p0, p1)) { -if (!(((+p1 || 0) - (+p0 || 0)) <= 7)) { -b0.value = (b1.value[(((((+p1 || 0) + (+p0 || 0)) || 0) / 2) | 0) - 1] ?? ""); +if (!((toNotNaN(+p1) - toNotNaN(+p0)) <= 7)) { +b0.value = (b1.value[((toNotNaN((toNotNaN(+p1) + toNotNaN(+p0))) / 2) | 0) - 1] ?? ""); b2.value = p0; b3.value = p1; while (true) { while (compareLessThan(listGet(b1.value, b2.value), b0.value)) { -b2.value = ((+b2.value || 0) + 1); +b2.value = (toNotNaN(+b2.value) + 1); if (isStuck()) yield; } while (compareGreaterThan(listGet(b1.value, b3.value), b0.value)) { -b3.value = ((+b3.value || 0) + -1); +b3.value = (toNotNaN(+b3.value) + -1); if (isStuck()) yield; } if (compareGreaterThan(b2.value, b3.value)) { @@ -85,23 +85,23 @@ return ""; b4.value = listGet(b1.value, b2.value); listReplace(b1, b2.value, listGet(b1.value, b3.value)); listReplace(b1, b3.value, b4.value); -b2.value = ((+b2.value || 0) + 1); -b3.value = ((+b3.value || 0) + -1); +b2.value = (toNotNaN(+b2.value) + 1); +b3.value = (toNotNaN(+b3.value) + -1); } if (isStuck()) yield; } } else { b5.value = p0; -for (var a0 = (((+p1 || 0) - (+p0 || 0)) || 0); a0 >= 0.5; a0--) { +for (var a0 = toNotNaN((toNotNaN(+p1) - toNotNaN(+p0))); a0 >= 0.5; a0--) { b6.value = b5.value; b7.value = listGet(b1.value, b5.value); -b8.value = ((+b5.value || 0) + 1); -for (var a1 = (((+p1 || 0) - (+b5.value || 0)) || 0); a1 >= 0.5; a1--) { +b8.value = (toNotNaN(+b5.value) + 1); +for (var a1 = toNotNaN((toNotNaN(+p1) - toNotNaN(+b5.value))); a1 >= 0.5; a1--) { if (compareLessThan(listGet(b1.value, b8.value), b7.value)) { b7.value = listGet(b1.value, b8.value); b6.value = b8.value; } -b8.value = ((+b8.value || 0) + 1); +b8.value = (toNotNaN(+b8.value) + 1); if (isStuck()) yield; } if (compareEqual(b6.value, b5.value)) { @@ -110,7 +110,7 @@ b4.value = listGet(b1.value, b5.value); listReplace(b1, b5.value, b7.value); listReplace(b1, b6.value, b4.value); } -b5.value = ((+b5.value || 0) + 1); +b5.value = (toNotNaN(+b5.value) + 1); if (isStuck()) yield; } } 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 index 5cef84247bc..fee655b382a 100644 --- 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 @@ -22,7 +22,7 @@ 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); +b0.value = (toNotNaN(+b0.value) + 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 index 018d12fbdc0..1a3fb7c91b1 100644 --- 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 @@ -17,11 +17,11 @@ b1._monitorUpToDate = false; b2.value = 0; b3.value = "bwah"; while (!(("" + b3.value).toLowerCase() === "eof".toLowerCase())) { -b2.value = ((+b2.value || 0) + 1); +b2.value = (toNotNaN(+b2.value) + 1); b3.value = (b1.value[(b2.value | 0) - 1] ?? ""); yield; } -if (((+b2.value || 0) === 2)) { +if ((toNotNaN(+b2.value) === 2)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "q", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot index 2aa9b207d24..d3a12562b1a 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot @@ -7,7 +7,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; return function* genXYZ () { b0.value = 0; while (true) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); thread.timer = timer(); var a0 = Math.max(0, 1000 * -1); runtime.requestRedraw(); 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 c242a148a32..2952a58ecbc 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,7 +10,7 @@ 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 ((toNotNaN(+b1.value) === 4)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp recursion yields",}, b0, false, false, "ao", null); } b1.value = 0; @@ -20,7 +20,7 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass warp recursion does not yiel } b1.value = 0; b2.value = (yield* thread.procedures["Zfib %s"](7)); -if (((+b1.value || 0) === 20)) { +if ((toNotNaN(+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"); @@ -34,7 +34,7 @@ retire(); return; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function* genXYZ_non_warp_recursion_s (p0) { if (compareGreaterThan(p0, 0)) { -return (yield* yieldThenCallGenerator(thread.procedures["Znon warp recursion should yield %s"], ((+p0 || 0) - 1))); +return (yield* yieldThenCallGenerator(thread.procedures["Znon warp recursion should yield %s"], (toNotNaN(+p0) - 1))); } return ""; }; }) @@ -43,7 +43,7 @@ return ""; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_warp_recursion_shoul (p0) { if (compareGreaterThan(p0, 0)) { -return thread.procedures["Wwarp recursion should not yield %s"](((+p0 || 0) - 1)); +return thread.procedures["Wwarp recursion should not yield %s"]((toNotNaN(+p0) - 1)); } return ""; }; }) @@ -54,7 +54,7 @@ return function* genXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { return p0; } else { -return ((+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], ((+p0 || 0) - 1))) || 0) + (+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], ((+p0 || 0) - 2))) || 0)); +return (toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], (toNotNaN(+p0) - 1)))) + toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zfib %s"], (toNotNaN(+p0) - 2))))); } return ""; }; }) @@ -67,8 +67,8 @@ const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_recursing_yields_bet (p0) { if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = 0; -b1.value = ((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2)) || 0) + (((+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0) + (+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)) || 0)) || 0)) || 0)) || 0)) || 0)); -if (((+b0.value || 0) === 3)) { +b1.value = (toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3))) + toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)))))))))))); +if ((toNotNaN(+b0.value) === 3)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass recursing between calls yields final",}, b2, false, false, "aK", null); } else { yield* executeInCompatibilityLayer({"MESSAGE":"fail recursing between calls yields final",}, b2, false, false, "aL", null); @@ -131,7 +131,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; return function* genXYZ () { b0.value = 0; while (true) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); thread.timer = timer(); var a0 = Math.max(0, 1000 * -1); runtime.requestRedraw(); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot index 3b4a34ac8e8..e356c359bf8 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot @@ -13,10 +13,10 @@ yield* executeInCompatibilityLayer({"MESSAGE":"pass simplest",}, b0, false, fals if ((("" + thread.procedures["Znesting 1"]()).toLowerCase() === "42-54".toLowerCase())) { yield* executeInCompatibilityLayer({"MESSAGE":"pass nesting1",}, b0, false, false, "=", null); } -if (((+thread.procedures["Wwarp fib %s"](12) || 0) === 144)) { +if ((toNotNaN(+thread.procedures["Wwarp fib %s"](12)) === 144)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass fib 12",}, b0, false, false, "@", null); } -if (((+thread.procedures["Wfactorial %s"](12) || 0) === 479001600)) { +if ((toNotNaN(+thread.procedures["Wfactorial %s"](12)) === 479001600)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass factorial 12",}, b0, false, false, "]", null); } b1.value = (yield* thread.procedures["Zno shadowing 1 %s %s"]("f","g")); @@ -53,7 +53,7 @@ return ""; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_factorial_ (p0) { if (compareGreaterThan(p0, 1)) { -return ((+p0 || 0) * (+thread.procedures["Wfactorial %s"](((+p0 || 0) - 1)) || 0)); +return (toNotNaN(+p0) * toNotNaN(+thread.procedures["Wfactorial %s"]((toNotNaN(+p0) - 1)))); } return 1; return ""; @@ -88,7 +88,7 @@ return ""; // Sprite1 Znesting 3 %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); return function funXYZ_nesting_3__ (p0,p1) { -return ((+p0 || 0) * (+p1 || 0)); +return (toNotNaN(+p0) * toNotNaN(+p1)); return ""; }; }) @@ -98,7 +98,7 @@ return function funXYZ_fib_ (p0) { if (compareLessThan(p0, 2)) { return p0; } else { -return ((+thread.procedures["Wfib %s"](((+p0 || 0) - 1)) || 0) + (+thread.procedures["Wfib %s"](((+p0 || 0) - 2)) || 0)); +return (toNotNaN(+thread.procedures["Wfib %s"]((toNotNaN(+p0) - 1))) + toNotNaN(+thread.procedures["Wfib %s"]((toNotNaN(+p0) - 2)))); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot index 6d536299287..5de5f025e88 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot @@ -8,11 +8,11 @@ const b1 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "f", null); yield* thread.procedures["Wreturn stops the script immediately"](); -if (((+b1.value || 0) === 25)) { +if ((toNotNaN(+b1.value) === 25)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass return stopped the script immediately",}, b0, false, false, "u", null); } yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "Test return outside of custom block" })); -if (((+b1.value || 0) === 18)) { +if ((toNotNaN(+b1.value) === 18)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass return worked to stop outside of custom block",}, b0, false, false, "x", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "v", null); @@ -26,7 +26,7 @@ const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_return_stops_the_scr () { b0.value = 0; for (var a0 = 100; a0 > 0; a0--) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 25)) { return "stopped!"; } @@ -42,7 +42,7 @@ const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; return function* genXYZ () { b0.value = 0; while (true) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 18)) { retire(); return; } diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot index db6051903b0..289eeb63e3c 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot @@ -7,7 +7,7 @@ const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; return function* genXYZ () { b0.value = 0; while (true) { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); thread.timer = timer(); var a0 = Math.max(0, 1000 * -1); runtime.requestRedraw(); @@ -49,7 +49,7 @@ yield; thread.timer = null; yield; } -if (((+b0.value || 0) === 5)) { +if ((toNotNaN(+b0.value) === 5)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 1",}, b1, false, false, "R", null); } if ((("" + (yield* thread.procedures["Wverify runs warp %s"]((yield* thread.procedures["Zverify runs non warp %s"]((yield* thread.procedures["Wverify runs warp %s"]("abc"))))))).toLowerCase() === "warp: non warp: warp: abc".toLowerCase())) { @@ -67,7 +67,7 @@ yield; thread.timer = null; yield; } -if (((+b0.value || 0) === 5)) { +if ((toNotNaN(+b0.value) === 5)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 2",}, b1, false, false, "W", null); } return ""; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot index 646fdfd02e4..4c166406d91 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot @@ -30,7 +30,7 @@ return function* genXYZ () { b0.value = 0; yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b1, false, false, "0/2-)Gp^^=haQ1OMD.xb", null); for (var a0 = 15; a0 > 0; a0--) { -if (((+b2.value || 0) === 200)) { +if ((toNotNaN(+b2.value) === 200)) { b2.value = 50; } else { b2.value = 200; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot index f3b5937c508..08bf6005e3c 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot @@ -15,8 +15,8 @@ retire(); return; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = target.variables["ts-.PQ{/]mN_9@MbG:m/"]; return function* genXYZ_test_1 () { -for (var a0 = (+thread.procedures["Wany procedure reporter"]() || 0); a0 >= 0.5; a0--) { -b0.value = ((+b0.value || 0) + 1); +for (var a0 = toNotNaN(+thread.procedures["Wany procedure reporter"]()); a0 >= 0.5; a0--) { +b0.value = (toNotNaN(+b0.value) + 1); if (isStuck()) yield; } return ""; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-restart-broadcast-threads.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-restart-broadcast-threads.sb3.tw-snapshot index 84ea17ea2e8..2356e02f907 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-restart-broadcast-threads.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-restart-broadcast-threads.sb3.tw-snapshot @@ -18,7 +18,7 @@ while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -if (((+b1.value || 0) === 1)) { +if ((toNotNaN(+b1.value) === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "`SX*FG*Lwo*0_T=box-@", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "|#`zzPA_x%{`FyIAQhb4", null); @@ -29,6 +29,6 @@ retire(); return; (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 = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot index 88f7ab0b015..aff4757d938 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot @@ -7,11 +7,11 @@ const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "J#qm1yA(@Z6mj%Mgh;0X", null); thread.procedures["Zswitch %s"]("1"); -if ((((target.currentCostume + 1) === 2) && ((+target.getCostumes()[target.currentCostume].name || 0) === 1))) { +if ((((target.currentCostume + 1) === 2) && (toNotNaN(+target.getCostumes()[target.currentCostume].name) === 1))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ";DM$.QW6o-O+T/oBdqt!", null); } thread.procedures["Zswitch %s"]("2"); -if ((((target.currentCostume + 1) === 1) && ((+target.getCostumes()[target.currentCostume].name || 0) === 2))) { +if ((((target.currentCostume + 1) === 1) && (toNotNaN(+target.getCostumes()[target.currentCostume].name) === 2))) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "71a9Slk0w=^~x;5T@nw,", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb(Mu?gdTIH^;kC_", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot index 62e48ec1cae..ff8ab6ec888 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot @@ -29,7 +29,7 @@ yield; } b1.value = 2; } else { -if (((+b1.value || 0) === 1)) { +if ((toNotNaN(+b1.value) === 1)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b2, false, false, "p", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b2, false, false, "n", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot index ec187c5fd8e..12e9d04658b 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot @@ -24,13 +24,13 @@ return function* genXYZ_a () { b0.value = "ababa"; b1.value = ""; b2.value = 1; -for (var a0 = ("" + b0.value).length; a0 > 0; a0--) { +for (var a0 = b0.value.length; a0 > 0; a0--) { if ((((("" + b0.value))[((+b2.value) | 0) - 1] || "").toLowerCase() === "a".toLowerCase())) { b1.value = (("" + b1.value) + "b"); } else { b1.value = (("" + b1.value) + "a"); } -b2.value = ((+b2.value || 0) + 1); +b2.value = (toNotNaN(+b2.value) + 1); if (isStuck()) yield; } return ""; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot index b2ccf9ce3a3..41796eb6fd9 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot @@ -9,46 +9,46 @@ yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b0, false, false, "p" if (compareEqual(tan(0), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 0",}, b0, false, false, "O", null); } -if (((tan(90) || 0) === Infinity)) { +if ((toNotNaN(tan(90)) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 90",}, b0, false, false, "G", null); } if (compareEqual(tan(180), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 180",}, b0, false, false, "I", null); } -if (((tan(270) || 0) === -Infinity)) { +if ((toNotNaN(tan(270)) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 270",}, b0, false, false, "K", null); } if (compareEqual(tan(360), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 360",}, b0, false, false, "M", null); } -if (((tan(450) || 0) === Infinity)) { +if ((toNotNaN(tan(450)) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 450",}, b0, false, false, "Q", null); } if (compareEqual(tan(540), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 540",}, b0, false, false, "S", null); } -if (((tan(630) || 0) === -Infinity)) { +if ((toNotNaN(tan(630)) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 630",}, b0, false, false, "U", null); } if (compareEqual(tan(720), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 720",}, b0, false, false, "W", null); } -if (((tan(810) || 0) === Infinity)) { +if ((toNotNaN(tan(810)) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 810",}, b0, false, false, "Y", null); } -if (((tan(-90) || 0) === -Infinity)) { +if ((toNotNaN(tan(-90)) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -90",}, b0, false, false, "0", null); } if (compareEqual(tan(-180), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -180",}, b0, false, false, "2", null); } -if (((tan(-270) || 0) === Infinity)) { +if ((toNotNaN(tan(-270)) === Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -270",}, b0, false, false, "4", null); } if (compareEqual(tan(-360), 0)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -360",}, b0, false, false, "6", null); } -if (((tan(-450) || 0) === -Infinity)) { +if ((toNotNaN(tan(-450)) === -Infinity)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass -450",}, b0, false, false, "9", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "8", null); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot index 3804c87f6b3..014751f5d1e 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot @@ -18,43 +18,43 @@ b1.value = 10; if ((b1.value === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 3",}, b0, false, false, "Ul:BCck-}Fvdux~x#$${", null); } -if (((+b1.value || 0) === 10)) { +if ((toNotNaN(+b1.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 4",}, b0, false, false, "8]2$7P)o#+#Lo]mFSBbx", null); } -if (((+b1.value || 0) === 10)) { +if ((toNotNaN(+b1.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 5",}, b0, false, false, "ZU^{OfKTg|+Au$$q0[]u", null); } for (var a0 = 1; a0 > 0; a0--) { -if (((+b1.value || 0) === 10)) { +if ((toNotNaN(+b1.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 6",}, b0, false, false, "HB+_IN}6=K[*ksxKXH0`", null); } -if (((+b1.value || 0) === 10)) { +if ((toNotNaN(+b1.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 7",}, b0, false, false, ";73ODiwcp8IthYURTX;S", null); } -if (((+b1.value || 0) === 10)) { +if ((toNotNaN(+b1.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 8",}, b0, false, true, "${[MFmBL-D*1rbas9Q89", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } yield; } b2.value = "010"; -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 9",}, b0, false, false, "#.`@SBj!g-c0:_q/tMZo", null); } -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 10",}, b0, false, false, "B`o?V6/q6g),/2w};a#y", null); } -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 11",}, b0, false, false, "TJ:#TkYBys*!RYiKLXb)", null); } for (var a1 = 1; a1 > 0; a1--) { -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 12",}, b0, false, false, ",Z,~10Qo~j;(+VL+I3q:", null); } -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 13",}, b0, false, false, "|Mqx([(26M%#ggW9)U0s", null); } -if (((+b2.value || 0) === 10)) { +if ((toNotNaN(+b2.value) === 10)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass 14",}, b0, false, true, "YvtiKF231lU8p5Qd97RP", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } 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 index e5b718730e8..68a39552235 100644 --- 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 @@ -16,7 +16,7 @@ b1._monitorUpToDate = false; b1.value.push("final"); b1._monitorUpToDate = false; yield* thread.procedures["Wtest"](); -if (((+b2.value || 0) === 4)) { +if ((toNotNaN(+b2.value) === 4)) { yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "u", null); } yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "t", null); @@ -33,7 +33,7 @@ b0.value = ""; b1.value = 1; while (!(("" + b0.value).toLowerCase() === "final".toLowerCase())) { b0.value = listGet(b2.value, b1.value); -b1.value = ((+b1.value || 0) + 1); +b1.value = (toNotNaN(+b1.value) + 1); if (isStuck()) yield; } return ""; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot index 5a401185577..229d2814438 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot @@ -24,7 +24,7 @@ retire(); return; const b0 = stage.variables["7qur6!bGgvC9I(Nd5.HP"]; const b1 = stage.variables["sUOp@-6J4y0PqwiXit4!"]; return function* genXYZ () { -b0.value = ((+b0.value || 0) + 1); +b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 5)) { b1.value = "end"; } From 06dbe65a9859139f8643c8c84f02d82a63c0e5b0 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 24 Sep 2025 17:16:08 -0500 Subject: [PATCH 077/106] Use Number.isNaN instead --- src/compiler/jsexecute.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/compiler/jsexecute.js b/src/compiler/jsexecute.js index 582a4fdb942..61d69cd3cc4 100644 --- a/src/compiler/jsexecute.js +++ b/src/compiler/jsexecute.js @@ -226,13 +226,11 @@ runtimeFunctions.retire = `const retire = () => { /** * Converts NaN to zero. Used to match Scratch's string-to-number. * Unlike (x || 0), -0 stays as -0 and is not converted to 0. - * This function is written in this specific way to make it easy for browsers to inline. - * We've found that calling isNaN() causes slowdowns in Firefox, so instead we utilize the - * fact that NaN is the only JavaScript value that does not equal itself. + * This function needs to be written such that it's very easy for browsers to inline it. * @param {number} value A number. Might be NaN. * @returns {number} A number. Never NaN. */ -runtimeFunctions.toNotNaN = `const toNotNaN = value => value === value ? value : 0`; +runtimeFunctions.toNotNaN = `const toNotNaN = value => Number.isNaN(value) ? 0 : value`; /** * Scratch cast to boolean. From 9624ea5456a35b3143df271696c5f1837f99426d Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Thu, 9 Oct 2025 17:18:23 -0500 Subject: [PATCH 078/106] Compile looks_say and looks_think without compatibility layer --- src/blocks/scratch3_looks.js | 5 +- src/compiler/compat-blocks.js | 2 - src/compiler/enums.js | 2 + src/compiler/irgen.js | 8 + src/compiler/jsgen.js | 6 + .../order-library-reverse.sb3.tw-snapshot | 23 +- .../order-library.sb3.tw-snapshot | 23 +- .../__snapshots__/tw-NaN.sb3.tw-snapshot | 47 +- .../tw-add-can-return-nan.sb3.tw-snapshot | 7 +- .../tw-all-at-once.sb3.tw-snapshot | 7 +- ...ds-due-to-direct-recursion.sb3.tw-snapshot | 15 +- ...e-creation-literal-null-id.sb3.tw-snapshot | 9 +- ...-with-null-for-variable-id.sb3.tw-snapshot | 19 +- ...ean-arguments-are-not-cast.sb3.tw-snapshot | 14 +- ...oadcast-id-and-name-desync.sb3.tw-snapshot | 8 +- ...-does-not-use-rounded-size.sb3.tw-snapshot | 15 +- ...tw-color-input-returns-hex.sb3.tw-snapshot | 13 +- ...w-comparison-matrix-inline.sb3.tw-snapshot | 1181 ++++++++--------- ...-comparison-matrix-runtime.sb3.tw-snapshot | 33 +- ...ibility-layer-type-barrier.sb3.tw-snapshot | 17 +- .../tw-coordinate-precision.sb3.tw-snapshot | 25 +- .../__snapshots__/tw-counter.sb3.tw-snapshot | 16 +- .../tw-custom-report-repeat.sb3.tw-snapshot | 15 +- ...s-for-yields-in-procedures.sb3.tw-snapshot | 15 +- ...-boolean-number-comparison.sb3.tw-snapshot | 13 +- ...s-515-non-finite-direction.sb3.tw-snapshot | 17 +- ...invalid-number-with-period.sb3.tw-snapshot | 35 +- ...-name-desync-name-fallback.sb3.tw-snapshot | 25 +- ...-zero-seconds-in-warp-mode.sb3.tw-snapshot | 7 +- ...s-not-reevaluate-arguments.sb3.tw-snapshot | 5 +- .../tw-gh-249-quicksort.sb3.tw-snapshot | 20 +- .../__snapshots__/tw-list-any.sb3.tw-snapshot | 45 +- ...dition-optimization-gh-276.sb3.tw-snapshot | 11 +- ...rp-loop-condition-analysis.sb3.tw-snapshot | 35 +- .../tw-obsolete-blocks.sb3.tw-snapshot | 49 +- ...w-one-divide-negative-zero.sb3.tw-snapshot | 7 +- ...ojectTimer-drift-453118719.sb3.tw-snapshot | 12 +- ...nce-of-procedure-387608267.sb3.tw-snapshot | 12 +- ...e-arguments-with-same-name.sb3.tw-snapshot | 19 +- ...able-input-types-430811055.sb3.tw-snapshot | 13 +- ...t-not-definition-549160843.sb3.tw-snapshot | 5 +- ...cedure-return-non-existant.sb3.tw-snapshot | 13 +- ...cedure-return-non-existent.sb3.tw-snapshot | 15 +- ...procedure-return-recursion.sb3.tw-snapshot | 59 +- ...tw-procedure-return-simple.sb3.tw-snapshot | 36 +- ...edure-return-stops-scripts.sb3.tw-snapshot | 22 +- .../tw-procedure-return-warp.sb3.tw-snapshot | 18 +- ...-loop-double-yield-kouzeru.sb3.tw-snapshot | 20 +- ...-analysis-doesnt-reanalyze.sb3.tw-snapshot | 11 +- ...ter-infinite-analyzer-loop.sb3.tw-snapshot | 5 +- ...-restart-broadcast-threads.sb3.tw-snapshot | 13 +- ...cimal-without-leading-zero.sb3.tw-snapshot | 7 +- ...procedure-argument-casting.sb3.tw-snapshot | 9 +- ...-keeps-running-until-yield.sb3.tw-snapshot | 14 +- .../tw-sensing-of.sb3.tw-snapshot | 141 +- ...w-simple-string-operations.sb3.tw-snapshot | 11 +- ...r-literal-if-name-conflict.sb3.tw-snapshot | 15 +- ...w-stage-cannot-move-layers.sb3.tw-snapshot | 12 +- ...derstands-stop-this-script.sb3.tw-snapshot | 13 +- ...tw-subtract-can-return-nan.sb3.tw-snapshot | 7 +- .../tw-tab-equals-zero.sb3.tw-snapshot | 22 +- .../__snapshots__/tw-tangent.sb3.tw-snapshot | 35 +- .../tw-unsafe-equals.sb3.tw-snapshot | 81 +- ...ait-until-condition-gh-277.sb3.tw-snapshot | 11 +- ...rp-loop-condition-analysis.sb3.tw-snapshot | 27 +- ...t-until-timer-greater-than.sb3.tw-snapshot | 8 +- ...-switches-to-next-backdrop.sb3.tw-snapshot | 6 +- ...ches-to-switch-backdrop-to.sb3.tw-snapshot | 6 +- ...mbie-cube-escape-284516654.sb3.tw-snapshot | 17 +- .../order-library-reverse.sb3.tw-snapshot | 23 +- .../warp-timer/order-library.sb3.tw-snapshot | 23 +- .../warp-timer/tw-NaN.sb3.tw-snapshot | 47 +- .../tw-add-can-return-nan.sb3.tw-snapshot | 7 +- .../warp-timer/tw-all-at-once.sb3.tw-snapshot | 7 +- ...ds-due-to-direct-recursion.sb3.tw-snapshot | 15 +- ...e-creation-literal-null-id.sb3.tw-snapshot | 9 +- ...-with-null-for-variable-id.sb3.tw-snapshot | 19 +- ...ean-arguments-are-not-cast.sb3.tw-snapshot | 14 +- ...oadcast-id-and-name-desync.sb3.tw-snapshot | 8 +- ...-does-not-use-rounded-size.sb3.tw-snapshot | 15 +- ...tw-color-input-returns-hex.sb3.tw-snapshot | 13 +- ...w-comparison-matrix-inline.sb3.tw-snapshot | 1181 ++++++++--------- ...-comparison-matrix-runtime.sb3.tw-snapshot | 21 +- ...ibility-layer-type-barrier.sb3.tw-snapshot | 17 +- .../tw-coordinate-precision.sb3.tw-snapshot | 25 +- .../warp-timer/tw-counter.sb3.tw-snapshot | 16 +- .../tw-custom-report-repeat.sb3.tw-snapshot | 15 +- ...s-for-yields-in-procedures.sb3.tw-snapshot | 15 +- ...-boolean-number-comparison.sb3.tw-snapshot | 13 +- ...s-515-non-finite-direction.sb3.tw-snapshot | 17 +- ...invalid-number-with-period.sb3.tw-snapshot | 35 +- ...-name-desync-name-fallback.sb3.tw-snapshot | 25 +- ...-zero-seconds-in-warp-mode.sb3.tw-snapshot | 7 +- ...s-not-reevaluate-arguments.sb3.tw-snapshot | 5 +- .../tw-gh-249-quicksort.sb3.tw-snapshot | 10 +- .../warp-timer/tw-list-any.sb3.tw-snapshot | 45 +- ...dition-optimization-gh-276.sb3.tw-snapshot | 11 +- ...rp-loop-condition-analysis.sb3.tw-snapshot | 35 +- .../tw-obsolete-blocks.sb3.tw-snapshot | 49 +- ...w-one-divide-negative-zero.sb3.tw-snapshot | 7 +- ...ojectTimer-drift-453118719.sb3.tw-snapshot | 12 +- ...nce-of-procedure-387608267.sb3.tw-snapshot | 12 +- ...e-arguments-with-same-name.sb3.tw-snapshot | 19 +- ...able-input-types-430811055.sb3.tw-snapshot | 13 +- ...t-not-definition-549160843.sb3.tw-snapshot | 5 +- ...cedure-return-non-existant.sb3.tw-snapshot | 13 +- ...cedure-return-non-existent.sb3.tw-snapshot | 15 +- ...procedure-return-recursion.sb3.tw-snapshot | 59 +- ...tw-procedure-return-simple.sb3.tw-snapshot | 36 +- ...edure-return-stops-scripts.sb3.tw-snapshot | 18 +- .../tw-procedure-return-warp.sb3.tw-snapshot | 18 +- ...-loop-double-yield-kouzeru.sb3.tw-snapshot | 20 +- ...-analysis-doesnt-reanalyze.sb3.tw-snapshot | 11 +- ...ter-infinite-analyzer-loop.sb3.tw-snapshot | 5 +- ...-restart-broadcast-threads.sb3.tw-snapshot | 13 +- ...cimal-without-leading-zero.sb3.tw-snapshot | 7 +- ...procedure-argument-casting.sb3.tw-snapshot | 9 +- ...-keeps-running-until-yield.sb3.tw-snapshot | 14 +- .../warp-timer/tw-sensing-of.sb3.tw-snapshot | 141 +- ...w-simple-string-operations.sb3.tw-snapshot | 11 +- ...r-literal-if-name-conflict.sb3.tw-snapshot | 15 +- ...w-stage-cannot-move-layers.sb3.tw-snapshot | 12 +- ...derstands-stop-this-script.sb3.tw-snapshot | 13 +- ...tw-subtract-can-return-nan.sb3.tw-snapshot | 7 +- .../tw-tab-equals-zero.sb3.tw-snapshot | 22 +- .../warp-timer/tw-tangent.sb3.tw-snapshot | 35 +- .../tw-unsafe-equals.sb3.tw-snapshot | 81 +- ...ait-until-condition-gh-277.sb3.tw-snapshot | 11 +- ...rp-loop-condition-analysis.sb3.tw-snapshot | 27 +- ...t-until-timer-greater-than.sb3.tw-snapshot | 8 +- ...-switches-to-next-backdrop.sb3.tw-snapshot | 6 +- ...ches-to-switch-backdrop-to.sb3.tw-snapshot | 6 +- ...mbie-cube-escape-284516654.sb3.tw-snapshot | 17 +- 133 files changed, 2397 insertions(+), 2572 deletions(-) diff --git a/src/blocks/scratch3_looks.js b/src/blocks/scratch3_looks.js index e84e0f83893..c9c4b1fad19 100644 --- a/src/blocks/scratch3_looks.js +++ b/src/blocks/scratch3_looks.js @@ -352,7 +352,10 @@ class Scratch3LooksBlocks { } think (args, util) { - this.runtime.emit(Scratch3LooksBlocks.SAY_OR_THINK, util.target, 'think', args.MESSAGE); + this._think(args.MESSAGE, util.target); + } + _think (message, target) { // used by compiler + this.runtime.emit(Scratch3LooksBlocks.SAY_OR_THINK, target, 'think', message); } thinkforsecs (args, util) { diff --git a/src/compiler/compat-blocks.js b/src/compiler/compat-blocks.js index ba9d5b88bb8..2174a58c4a7 100644 --- a/src/compiler/compat-blocks.js +++ b/src/compiler/compat-blocks.js @@ -10,11 +10,9 @@ const stacked = [ 'looks_changestretchby', 'looks_hideallsprites', - 'looks_say', 'looks_sayforsecs', 'looks_setstretchto', 'looks_switchbackdroptoandwait', - 'looks_think', 'looks_thinkforsecs', 'motion_align_scene', 'motion_glidesecstoxy', diff --git a/src/compiler/enums.js b/src/compiler/enums.js index 53b311886b2..1d493bf4884 100644 --- a/src/compiler/enums.js +++ b/src/compiler/enums.js @@ -152,6 +152,8 @@ const StackOpcode = { LOOKS_BACKDROP_SET: 'looks.switchBackdrop', LOOKS_COSTUME_NEXT: 'looks.nextCostume', LOOKS_COSTUME_SET: 'looks.switchCostume', + LOOKS_SAY: 'looks.say', + LOOKS_THINK: 'looks.think', MOTION_X_SET: 'motion.setX', MOTION_X_CHANGE: 'motion.changeX', diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 4175840ed98..52411ac9765 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -806,6 +806,10 @@ class ScriptTreeGenerator { return new IntermediateStackBlock(StackOpcode.LOOKS_BACKDROP_NEXT); case 'looks_nextcostume': return new IntermediateStackBlock(StackOpcode.LOOKS_COSTUME_NEXT); + case 'looks_say': + return new IntermediateStackBlock(StackOpcode.LOOKS_SAY, { + message: this.descendInputOfBlock(block, 'MESSAGE') + }); case 'looks_seteffectto': return new IntermediateStackBlock(StackOpcode.LOOKS_EFFECT_SET, { effect: block.fields.EFFECT.value.toLowerCase(), @@ -825,6 +829,10 @@ class ScriptTreeGenerator { return new IntermediateStackBlock(StackOpcode.LOOKS_COSTUME_SET, { costume: this.descendInputOfBlock(block, 'COSTUME', true) }); + case 'looks_think': + return new IntermediateStackBlock(StackOpcode.LOOKS_THINK, { + message: this.descendInputOfBlock(block, 'MESSAGE') + }); case 'motion_changexby': return new IntermediateStackBlock(StackOpcode.MOTION_X_CHANGE, { diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index a79b931e37d..abc492bf19e 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -779,6 +779,12 @@ class JSGenerator { case StackOpcode.LOOKS_COSTUME_SET: this.source += `runtime.ext_scratch3_looks._setCostume(target, ${this.descendInput(node.costume)});\n`; break; + case StackOpcode.LOOKS_SAY: + this.source += `runtime.ext_scratch3_looks._say(${this.descendInput(node.message)}, target);\n`; + break; + case StackOpcode.LOOKS_THINK: + this.source += `runtime.ext_scratch3_looks._think(${this.descendInput(node.message)}, target);\n`; + break; case StackOpcode.MOTION_X_CHANGE: this.source += `target.setXY(target.x + ${this.descendInput(node.dx)}, target.y);\n`; diff --git a/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot b/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot index 466e9f50eee..dc849cf46e2 100644 --- a/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/order-library-reverse.sb3.tw-snapshot @@ -5,7 +5,6 @@ (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["p]KODv+)+:l=%NT~j3/d-order"]; const b1 = stage.variables["p]KODv+)+:l=%NT~j3/d-wait"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); @@ -18,21 +17,20 @@ yield; thread.timer = null; b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "]4hbk*5ix]V00h|!x1oy", null); +runtime.ext_scratch3_looks._say("pass order is correct (1)", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 1 != " + ("" + b0.value)),}, b2, false, false, "H=x@7SpNJeX|!}8x5y4,", null); +runtime.ext_scratch3_looks._say(("fail order is incorrect 1 != " + ("" + b0.value)), target); } retire(); return; }; }) // Sprite3 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["p]KODv+)+:l=%NT~j3/d-wait"]; +const b0 = stage.variables["p]KODv+)+:l=%NT~j3/d-wait"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "1Ba%a0GIK#hwJ46y=WVt", null); +runtime.ext_scratch3_looks._say("plan 2", target); thread.timer = timer(); -var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a0 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { @@ -40,7 +38,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a1 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a1 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a1) { @@ -48,14 +46,14 @@ yield; } thread.timer = null; thread.timer = timer(); -var a2 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a2 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a2) { yield; } thread.timer = null; -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "}-I/zE+.RSi`:h[RxMvQ", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -63,7 +61,6 @@ retire(); return; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["p]KODv+)+:l=%NT~j3/d-order"]; const b1 = stage.variables["p]KODv+)+:l=%NT~j3/d-wait"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); @@ -76,9 +73,9 @@ yield; thread.timer = null; b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "0i[-T:vYTt=bi47@byUE", null); +runtime.ext_scratch3_looks._say("pass order is correct (2)", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 2 != " + ("" + b0.value)),}, b2, false, false, "Coc1aZ;L9M-RyEt`syps", null); +runtime.ext_scratch3_looks._say(("fail order is incorrect 2 != " + ("" + b0.value)), target); } retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot b/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot index 49cfd33b5e1..c2b537cdcd5 100644 --- a/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/order-library.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite3 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["):/PVGTvoVRvq(ikGwRE-wait"]; +const b0 = stage.variables["):/PVGTvoVRvq(ikGwRE-wait"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "s+@:|^WPr8]N1Y9Hk2f5", null); +runtime.ext_scratch3_looks._say("plan 2", target); thread.timer = timer(); -var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a0 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { @@ -16,7 +15,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a1 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a1 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a1) { @@ -24,14 +23,14 @@ yield; } thread.timer = null; thread.timer = timer(); -var a2 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a2 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a2) { yield; } thread.timer = null; -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "7e7aA!PF-sxf1uka+sh2", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -39,7 +38,6 @@ retire(); return; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["):/PVGTvoVRvq(ikGwRE-order"]; const b1 = stage.variables["):/PVGTvoVRvq(ikGwRE-wait"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); @@ -52,9 +50,9 @@ yield; thread.timer = null; b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "RSQ{nVCc)6E)(`KlnFCF", null); +runtime.ext_scratch3_looks._say("pass order is correct (1)", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 1 != " + ("" + b0.value)),}, b2, false, false, "8k^j~`c^|YO@hkFd?~2d", null); +runtime.ext_scratch3_looks._say(("fail order is incorrect 1 != " + ("" + b0.value)), target); } retire(); return; }; }) @@ -63,7 +61,6 @@ retire(); return; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["):/PVGTvoVRvq(ikGwRE-order"]; const b1 = stage.variables["):/PVGTvoVRvq(ikGwRE-wait"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); @@ -76,9 +73,9 @@ yield; thread.timer = null; b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "KP?op(=Vg2#;@]!,C#.~", null); +runtime.ext_scratch3_looks._say("pass order is correct (2)", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 2 != " + ("" + b0.value)),}, b2, false, false, "=]|}L~4uQXTNtwJKw_;R", null); +runtime.ext_scratch3_looks._say(("fail order is incorrect 2 != " + ("" + b0.value)), target); } retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot index a760bbe3a6b..19888e5845d 100644 --- a/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-NaN.sb3.tw-snapshot @@ -3,72 +3,71 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 21",}, b0, false, false, "B", null); +runtime.ext_scratch3_looks._say("plan 21", target); if (!(("" + (0 / 0)).toLowerCase() === "0".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aA", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + (0 * Infinity)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "/", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN((0 * Infinity)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "?", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + ((Math.acos(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "=", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(((Math.acos(1.01) * 180) / Math.PI)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "]", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + ((Math.asin(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "_", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(((Math.asin(1.01) * 180) / Math.PI)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "{", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + (0 / 0)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "}", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN((0 / 0)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aa", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + Math.sqrt(-1)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ac", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(Math.sqrt(-1)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ae", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + mod(0, 0)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ag", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(mod(0, 0)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ai", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + Math.log(-1)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ak", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(Math.log(-1)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "am", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + (Math.log(-1) / Math.LN10)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ao", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN((Math.log(-1) / Math.LN10)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aq", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN((Math.round(Math.sin((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "as", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN((Math.round(Math.cos((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "au", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(tan((1 / 0))) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aw", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(runtime.ext_scratch3_operators._random((-1 / 0), (1 / 0))) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ax", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ":", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-add-can-return-nan.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-add-can-return-nan.sb3.tw-snapshot index 3652f132f3d..7ce7b186e9b 100644 --- a/test/snapshot/__snapshots__/tw-add-can-return-nan.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-add-can-return-nan.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "6_?4sPB-|g:DtjdOm5Q-", null); +runtime.ext_scratch3_looks._say("plan 1", target); if (!((Infinity + -Infinity) <= 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ")-u2YbbMb;gXMPOidjPj", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "zqE}hdaes.b)@mO1{R;X", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-all-at-once.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-all-at-once.sb3.tw-snapshot index 7baf88d8f09..beca8936c7b 100644 --- a/test/snapshot/__snapshots__/tw-all-at-once.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-all-at-once.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "1TRvh{mBarwY!BX8`o$R", null); +runtime.ext_scratch3_looks._say("plan 1", target); if (true) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "K|r`QjC126S.93lMawiD", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "QaZ%(g:;bB~D+24z:U?l", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot index 75de04704b4..32435b0af57 100644 --- a/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot @@ -3,17 +3,16 @@ // 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["FpLI$ida6)qR,q~y`1|*"]; +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = stage.variables["FpLI$ida6)qR,q~y`1|*"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "j", null); -b1.value = (1 + 2); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = (1 + 2); yield* thread.procedures["Znon-warp recursion %s"](2); -if ((("" + listGet(b2.value, b1.value)).toLowerCase() === "the only thing".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "t", null); +if ((("" + listGet(b1.value, b0.value)).toLowerCase() === "the only thing".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "s", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot index ac6f722391f..d3a2c80cab3 100644 --- a/test/snapshot/__snapshots__/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot @@ -3,11 +3,10 @@ // 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 = target.variables["null"]; +const b0 = target.variables["null"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a", null); -b1.value = 5; -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "d", null); +runtime.ext_scratch3_looks._say("plan 0", target); +b0.value = 5; +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) 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 index 2e9766c0409..153276f7b89 100644 --- 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 @@ -3,26 +3,24 @@ // 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"]; +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = 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; +runtime.ext_scratch3_looks._say("plan 2", target); +b0.value = 1; +b1.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); +runtime.ext_scratch3_looks._say("end", target); 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 ((toNotNaN(+b0.value) === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 1",}, b1, false, false, "m", null); +runtime.ext_scratch3_looks._say("pass variable 1", target); } retire(); return; }; }) @@ -30,10 +28,9 @@ 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 ((toNotNaN(+b0.value) === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 2",}, b1, false, false, "q", null); +runtime.ext_scratch3_looks._say("pass variable 2", target); } retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-boolean-arguments-are-not-cast.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-boolean-arguments-are-not-cast.sb3.tw-snapshot index bb3be7cad38..b7aca7680ef 100644 --- a/test/snapshot/__snapshots__/tw-boolean-arguments-are-not-cast.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-boolean-arguments-are-not-cast.sb3.tw-snapshot @@ -3,22 +3,20 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "f", null); -yield* thread.procedures["ZBlock A %s"]("Hai!!!"); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "k", null); +runtime.ext_scratch3_looks._say("plan 1", target); +thread.procedures["ZBlock A %s"]("Hai!!!"); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 ZBlock A %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_Block_A_ (p0) { +return function funXYZ_Block_A_ (p0) { if ((("" + p0).toLowerCase() === "Hai!!!".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass did not cast",}, b0, false, false, "m", null); +runtime.ext_scratch3_looks._say("pass did not cast", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":"fail was casted",}, b0, false, false, "n", null); +runtime.ext_scratch3_looks._say("fail was casted", target); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/tw-broadcast-id-and-name-desync.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-broadcast-id-and-name-desync.sb3.tw-snapshot index e08c111f3db..42f3cd396bf 100644 --- a/test/snapshot/__snapshots__/tw-broadcast-id-and-name-desync.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-broadcast-id-and-name-desync.sb3.tw-snapshot @@ -3,18 +3,16 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "?@x?KlY[GHB#^le;O^;Z", null); +runtime.ext_scratch3_looks._say("pass", target); retire(); return; }; }) // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "*S!`s:/sOEm#Bd%7=h7E", null); +runtime.ext_scratch3_looks._say("plan 1", target); yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" })); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g#w*ISI)$Wi.45AszY|1", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot index 89d78f7e429..4d1afe46852 100644 --- a/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot @@ -3,20 +3,19 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "()*H*UE)$Jc!c}qb{,O)", null); +runtime.ext_scratch3_looks._say("plan 1", target); target.setSize(96); -b1.value = 0; +b0.value = 0; while (!(100 === Math.round(target.size))) { -b1.value = (toNotNaN(+b1.value) + 1); +b0.value = (toNotNaN(+b0.value) + 1); target.setSize(target.size + ((100 - Math.round(target.size)) / 10)); yield; } -if ((toNotNaN(+b1.value) === 20)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "FPDFR?Wwq)kLj0A$0D{@", null); +if ((toNotNaN(+b0.value) === 20)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "1,vLoJ4OQBv+Q#$VoYf=", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-color-input-returns-hex.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-color-input-returns-hex.sb3.tw-snapshot index 070b355da4a..56b3817737b 100644 --- a/test/snapshot/__snapshots__/tw-color-input-returns-hex.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-color-input-returns-hex.sb3.tw-snapshot @@ -3,14 +3,13 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); -b1.value = "#22388a"; -if ((b1.value.toLowerCase() === "#22388a".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "f", null); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = "#22388a"; +if ((b0.value.toLowerCase() === "#22388a".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "e", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot index 741ccca8ae7..cb8e0dfefbd 100644 --- a/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot @@ -3,1773 +3,1772 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "f)", null); +runtime.ext_scratch3_looks._say("plan 0", target); if (!(("" + (0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 1: 0 should be < 0",}, b0, false, false, "tB", null); +runtime.ext_scratch3_looks._say("fail 1: 0 should be < 0", target); } if (!(("" + (0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 2: 0 should be = 0",}, b0, false, false, "tD", null); +runtime.ext_scratch3_looks._say("fail 2: 0 should be = 0", target); } if (!(("" + (0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 3: 0 should be > 0",}, b0, false, false, "tF", null); +runtime.ext_scratch3_looks._say("fail 3: 0 should be > 0", target); } if (!(("" + (0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 4: 0 should be < 0.0",}, b0, false, false, "tH", null); +runtime.ext_scratch3_looks._say("fail 4: 0 should be < 0.0", target); } if (!(("" + (0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 5: 0 should be = 0.0",}, b0, false, false, "tJ", null); +runtime.ext_scratch3_looks._say("fail 5: 0 should be = 0.0", target); } if (!(("" + (0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 6: 0 should be > 0.0",}, b0, false, false, "tL", null); +runtime.ext_scratch3_looks._say("fail 6: 0 should be > 0.0", target); } if (!(("" + (0 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 7: 0 should be < 1.23",}, b0, false, false, "tN", null); +runtime.ext_scratch3_looks._say("fail 7: 0 should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 8: 0 should be = 1.23",}, b0, false, false, "tP", null); +runtime.ext_scratch3_looks._say("fail 8: 0 should be = 1.23", target); } if (!(("" + (0 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 9: 0 should be > 1.23",}, b0, false, false, "tR", null); +runtime.ext_scratch3_looks._say("fail 9: 0 should be > 1.23", target); } if (!(("" + (0 < 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 10: 0 should be < .23",}, b0, false, false, "tT", null); +runtime.ext_scratch3_looks._say("fail 10: 0 should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 11: 0 should be = .23",}, b0, false, false, "tV", null); +runtime.ext_scratch3_looks._say("fail 11: 0 should be = .23", target); } if (!(("" + (0 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 12: 0 should be > .23",}, b0, false, false, "tX", null); +runtime.ext_scratch3_looks._say("fail 12: 0 should be > .23", target); } if (!(("" + (0 < 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 13: 0 should be < 0.123",}, b0, false, false, "tZ", null); +runtime.ext_scratch3_looks._say("fail 13: 0 should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 14: 0 should be = 0.123",}, b0, false, false, "t1", null); +runtime.ext_scratch3_looks._say("fail 14: 0 should be = 0.123", target); } if (!(("" + (0 > 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 15: 0 should be > 0.123",}, b0, false, false, "t3", null); +runtime.ext_scratch3_looks._say("fail 15: 0 should be > 0.123", target); } if (!(("" + (0 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 16: 0 should be < -0",}, b0, false, false, "t5", null); +runtime.ext_scratch3_looks._say("fail 16: 0 should be < -0", target); } if (!(("" + (0 === -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 17: 0 should be = -0",}, b0, false, false, "t7", null); +runtime.ext_scratch3_looks._say("fail 17: 0 should be = -0", target); } if (!(("" + (0 > -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 18: 0 should be > -0",}, b0, false, false, "t9", null); +runtime.ext_scratch3_looks._say("fail 18: 0 should be > -0", target); } if (!(("" + (0 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 19: 0 should be < -1",}, b0, false, false, "t#", null); +runtime.ext_scratch3_looks._say("fail 19: 0 should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 20: 0 should be = -1",}, b0, false, false, "t(", null); +runtime.ext_scratch3_looks._say("fail 20: 0 should be = -1", target); } if (!(("" + (0 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 21: 0 should be > -1",}, b0, false, false, "t*", null); +runtime.ext_scratch3_looks._say("fail 21: 0 should be > -1", target); } if (!(("" + ("0".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 22: 0 should be < true",}, b0, false, false, "t,", null); +runtime.ext_scratch3_looks._say("fail 22: 0 should be < true", target); } if (!(("" + ("0".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 23: 0 should be = true",}, b0, false, false, "t.", null); +runtime.ext_scratch3_looks._say("fail 23: 0 should be = true", target); } if (!(("" + ("0".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 24: 0 should be > true",}, b0, false, false, "t:", null); +runtime.ext_scratch3_looks._say("fail 24: 0 should be > true", target); } if (!(("" + ("0".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 25: 0 should be < false",}, b0, false, false, "t=", null); +runtime.ext_scratch3_looks._say("fail 25: 0 should be < false", target); } if (!(("" + ("0".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 26: 0 should be = false",}, b0, false, false, "t@", null); +runtime.ext_scratch3_looks._say("fail 26: 0 should be = false", target); } if (!(("" + ("0".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 27: 0 should be > false",}, b0, false, false, "t]", null); +runtime.ext_scratch3_looks._say("fail 27: 0 should be > false", target); } if (!(("" + ("0".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 28: 0 should be < NaN",}, b0, false, false, "t_", null); +runtime.ext_scratch3_looks._say("fail 28: 0 should be < NaN", target); } if (!(("" + ("0".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 29: 0 should be = NaN",}, b0, false, false, "t{", null); +runtime.ext_scratch3_looks._say("fail 29: 0 should be = NaN", target); } if (!(("" + ("0".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 30: 0 should be > NaN",}, b0, false, false, "t}", null); +runtime.ext_scratch3_looks._say("fail 30: 0 should be > NaN", target); } if (!(("" + (0 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 31: 0 should be < Infinity",}, b0, false, false, "ua", null); +runtime.ext_scratch3_looks._say("fail 31: 0 should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 32: 0 should be = Infinity",}, b0, false, false, "uc", null); +runtime.ext_scratch3_looks._say("fail 32: 0 should be = Infinity", target); } if (!(("" + (0 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 33: 0 should be > Infinity",}, b0, false, false, "ue", null); +runtime.ext_scratch3_looks._say("fail 33: 0 should be > Infinity", target); } if (!(("" + ("0".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 34: 0 should be < banana",}, b0, false, false, "ug", null); +runtime.ext_scratch3_looks._say("fail 34: 0 should be < banana", target); } if (!(("" + ("0".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 35: 0 should be = banana",}, b0, false, false, "ui", null); +runtime.ext_scratch3_looks._say("fail 35: 0 should be = banana", target); } if (!(("" + ("0".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 36: 0 should be > banana",}, b0, false, false, "uk", null); +runtime.ext_scratch3_looks._say("fail 36: 0 should be > banana", target); } if (!(("" + ("0".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 37: 0 should be < 🎉",}, b0, false, false, "um", null); +runtime.ext_scratch3_looks._say("fail 37: 0 should be < 🎉", target); } if (!(("" + ("0".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 38: 0 should be = 🎉",}, b0, false, false, "uo", null); +runtime.ext_scratch3_looks._say("fail 38: 0 should be = 🎉", target); } if (!(("" + ("0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 39: 0 should be > 🎉",}, b0, false, false, "uq", null); +runtime.ext_scratch3_looks._say("fail 39: 0 should be > 🎉", target); } if (!(("" + ("0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 40: 0 should be < ",}, b0, false, false, "us", null); +runtime.ext_scratch3_looks._say("fail 40: 0 should be < ", target); } if (!(("" + ("0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 41: 0 should be = ",}, b0, false, false, "uu", null); +runtime.ext_scratch3_looks._say("fail 41: 0 should be = ", target); } if (!(("" + ("0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 42: 0 should be > ",}, b0, false, false, "uw", null); +runtime.ext_scratch3_looks._say("fail 42: 0 should be > ", target); } if (!(("" + (0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 43: 0.0 should be < 0",}, b0, false, false, "uy", null); +runtime.ext_scratch3_looks._say("fail 43: 0.0 should be < 0", target); } if (!(("" + (0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 44: 0.0 should be = 0",}, b0, false, false, "uA", null); +runtime.ext_scratch3_looks._say("fail 44: 0.0 should be = 0", target); } if (!(("" + (0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 45: 0.0 should be > 0",}, b0, false, false, "uC", null); +runtime.ext_scratch3_looks._say("fail 45: 0.0 should be > 0", target); } if (!(("" + (0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 46: 0.0 should be < 0.0",}, b0, false, false, "uE", null); +runtime.ext_scratch3_looks._say("fail 46: 0.0 should be < 0.0", target); } if (!(("" + (0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 47: 0.0 should be = 0.0",}, b0, false, false, "uG", null); +runtime.ext_scratch3_looks._say("fail 47: 0.0 should be = 0.0", target); } if (!(("" + (0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 48: 0.0 should be > 0.0",}, b0, false, false, "uI", null); +runtime.ext_scratch3_looks._say("fail 48: 0.0 should be > 0.0", target); } if (!(("" + (0 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 49: 0.0 should be < 1.23",}, b0, false, false, "uK", null); +runtime.ext_scratch3_looks._say("fail 49: 0.0 should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 50: 0.0 should be = 1.23",}, b0, false, false, "uM", null); +runtime.ext_scratch3_looks._say("fail 50: 0.0 should be = 1.23", target); } if (!(("" + (0 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 51: 0.0 should be > 1.23",}, b0, false, false, "uO", null); +runtime.ext_scratch3_looks._say("fail 51: 0.0 should be > 1.23", target); } if (!(("" + (0 < 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 52: 0.0 should be < .23",}, b0, false, false, "uQ", null); +runtime.ext_scratch3_looks._say("fail 52: 0.0 should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 53: 0.0 should be = .23",}, b0, false, false, "uS", null); +runtime.ext_scratch3_looks._say("fail 53: 0.0 should be = .23", target); } if (!(("" + (0 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 54: 0.0 should be > .23",}, b0, false, false, "uU", null); +runtime.ext_scratch3_looks._say("fail 54: 0.0 should be > .23", target); } if (!(("" + (0 < 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 55: 0.0 should be < 0.123",}, b0, false, false, "uW", null); +runtime.ext_scratch3_looks._say("fail 55: 0.0 should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 56: 0.0 should be = 0.123",}, b0, false, false, "uY", null); +runtime.ext_scratch3_looks._say("fail 56: 0.0 should be = 0.123", target); } if (!(("" + (0 > 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 57: 0.0 should be > 0.123",}, b0, false, false, "u0", null); +runtime.ext_scratch3_looks._say("fail 57: 0.0 should be > 0.123", target); } if (!(("" + (0 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 58: 0.0 should be < -0",}, b0, false, false, "u2", null); +runtime.ext_scratch3_looks._say("fail 58: 0.0 should be < -0", target); } if (!(("" + (0 === -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 59: 0.0 should be = -0",}, b0, false, false, "u4", null); +runtime.ext_scratch3_looks._say("fail 59: 0.0 should be = -0", target); } if (!(("" + (0 > -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 60: 0.0 should be > -0",}, b0, false, false, "u6", null); +runtime.ext_scratch3_looks._say("fail 60: 0.0 should be > -0", target); } if (!(("" + (0 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 61: 0.0 should be < -1",}, b0, false, false, "u8", null); +runtime.ext_scratch3_looks._say("fail 61: 0.0 should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 62: 0.0 should be = -1",}, b0, false, false, "u!", null); +runtime.ext_scratch3_looks._say("fail 62: 0.0 should be = -1", target); } if (!(("" + (0 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 63: 0.0 should be > -1",}, b0, false, false, "u%", null); +runtime.ext_scratch3_looks._say("fail 63: 0.0 should be > -1", target); } if (!(("" + ("0.0".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 64: 0.0 should be < true",}, b0, false, false, "u)", null); +runtime.ext_scratch3_looks._say("fail 64: 0.0 should be < true", target); } if (!(("" + ("0.0".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 65: 0.0 should be = true",}, b0, false, false, "u+", null); +runtime.ext_scratch3_looks._say("fail 65: 0.0 should be = true", target); } if (!(("" + ("0.0".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 66: 0.0 should be > true",}, b0, false, false, "u-", null); +runtime.ext_scratch3_looks._say("fail 66: 0.0 should be > true", target); } if (!(("" + ("0.0".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 67: 0.0 should be < false",}, b0, false, false, "u/", null); +runtime.ext_scratch3_looks._say("fail 67: 0.0 should be < false", target); } if (!(("" + ("0.0".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 68: 0.0 should be = false",}, b0, false, false, "u;", null); +runtime.ext_scratch3_looks._say("fail 68: 0.0 should be = false", target); } if (!(("" + ("0.0".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 69: 0.0 should be > false",}, b0, false, false, "u?", null); +runtime.ext_scratch3_looks._say("fail 69: 0.0 should be > false", target); } if (!(("" + ("0.0".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 70: 0.0 should be < NaN",}, b0, false, false, "u[", null); +runtime.ext_scratch3_looks._say("fail 70: 0.0 should be < NaN", target); } if (!(("" + ("0.0".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 71: 0.0 should be = NaN",}, b0, false, false, "u^", null); +runtime.ext_scratch3_looks._say("fail 71: 0.0 should be = NaN", target); } if (!(("" + ("0.0".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 72: 0.0 should be > NaN",}, b0, false, false, "u`", null); +runtime.ext_scratch3_looks._say("fail 72: 0.0 should be > NaN", target); } if (!(("" + (0 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 73: 0.0 should be < Infinity",}, b0, false, false, "u|", null); +runtime.ext_scratch3_looks._say("fail 73: 0.0 should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 74: 0.0 should be = Infinity",}, b0, false, false, "u~", null); +runtime.ext_scratch3_looks._say("fail 74: 0.0 should be = Infinity", target); } if (!(("" + (0 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 75: 0.0 should be > Infinity",}, b0, false, false, "vb", null); +runtime.ext_scratch3_looks._say("fail 75: 0.0 should be > Infinity", target); } if (!(("" + ("0.0".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 76: 0.0 should be < banana",}, b0, false, false, "vd", null); +runtime.ext_scratch3_looks._say("fail 76: 0.0 should be < banana", target); } if (!(("" + ("0.0".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 77: 0.0 should be = banana",}, b0, false, false, "vf", null); +runtime.ext_scratch3_looks._say("fail 77: 0.0 should be = banana", target); } if (!(("" + ("0.0".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 78: 0.0 should be > banana",}, b0, false, false, "vh", null); +runtime.ext_scratch3_looks._say("fail 78: 0.0 should be > banana", target); } if (!(("" + ("0.0".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 79: 0.0 should be < 🎉",}, b0, false, false, "vj", null); +runtime.ext_scratch3_looks._say("fail 79: 0.0 should be < 🎉", target); } if (!(("" + ("0.0".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 80: 0.0 should be = 🎉",}, b0, false, false, "vl", null); +runtime.ext_scratch3_looks._say("fail 80: 0.0 should be = 🎉", target); } if (!(("" + ("0.0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 81: 0.0 should be > 🎉",}, b0, false, false, "vn", null); +runtime.ext_scratch3_looks._say("fail 81: 0.0 should be > 🎉", target); } if (!(("" + ("0.0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 82: 0.0 should be < ",}, b0, false, false, "vp", null); +runtime.ext_scratch3_looks._say("fail 82: 0.0 should be < ", target); } if (!(("" + ("0.0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 83: 0.0 should be = ",}, b0, false, false, "vr", null); +runtime.ext_scratch3_looks._say("fail 83: 0.0 should be = ", target); } if (!(("" + ("0.0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 84: 0.0 should be > ",}, b0, false, false, "vt", null); +runtime.ext_scratch3_looks._say("fail 84: 0.0 should be > ", target); } if (!(("" + (1.23 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 85: 1.23 should be < 0",}, b0, false, false, "vv", null); +runtime.ext_scratch3_looks._say("fail 85: 1.23 should be < 0", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 86: 1.23 should be = 0",}, b0, false, false, "vx", null); +runtime.ext_scratch3_looks._say("fail 86: 1.23 should be = 0", target); } if (!(("" + (1.23 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 87: 1.23 should be > 0",}, b0, false, false, "vz", null); +runtime.ext_scratch3_looks._say("fail 87: 1.23 should be > 0", target); } if (!(("" + (1.23 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 88: 1.23 should be < 0.0",}, b0, false, false, "vB", null); +runtime.ext_scratch3_looks._say("fail 88: 1.23 should be < 0.0", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 89: 1.23 should be = 0.0",}, b0, false, false, "vD", null); +runtime.ext_scratch3_looks._say("fail 89: 1.23 should be = 0.0", target); } if (!(("" + (1.23 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 90: 1.23 should be > 0.0",}, b0, false, false, "vF", null); +runtime.ext_scratch3_looks._say("fail 90: 1.23 should be > 0.0", target); } if (!(("" + (1.23 < 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 91: 1.23 should be < 1.23",}, b0, false, false, "vH", null); +runtime.ext_scratch3_looks._say("fail 91: 1.23 should be < 1.23", target); } if (!(("" + (1.23 === 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 92: 1.23 should be = 1.23",}, b0, false, false, "vJ", null); +runtime.ext_scratch3_looks._say("fail 92: 1.23 should be = 1.23", target); } if (!(("" + (1.23 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 93: 1.23 should be > 1.23",}, b0, false, false, "vL", null); +runtime.ext_scratch3_looks._say("fail 93: 1.23 should be > 1.23", target); } if (!(("" + (1.23 < 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 94: 1.23 should be < .23",}, b0, false, false, "vN", null); +runtime.ext_scratch3_looks._say("fail 94: 1.23 should be < .23", target); } if (!(("" + (1.23 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 95: 1.23 should be = .23",}, b0, false, false, "vP", null); +runtime.ext_scratch3_looks._say("fail 95: 1.23 should be = .23", target); } if (!(("" + (1.23 > 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 96: 1.23 should be > .23",}, b0, false, false, "vR", null); +runtime.ext_scratch3_looks._say("fail 96: 1.23 should be > .23", target); } if (!(("" + (1.23 < 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 97: 1.23 should be < 0.123",}, b0, false, false, "vT", null); +runtime.ext_scratch3_looks._say("fail 97: 1.23 should be < 0.123", target); } if (!(("" + (1.23 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 98: 1.23 should be = 0.123",}, b0, false, false, "vV", null); +runtime.ext_scratch3_looks._say("fail 98: 1.23 should be = 0.123", target); } if (!(("" + (1.23 > 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 99: 1.23 should be > 0.123",}, b0, false, false, "vX", null); +runtime.ext_scratch3_looks._say("fail 99: 1.23 should be > 0.123", target); } if (!(("" + (1.23 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 100: 1.23 should be < -0",}, b0, false, false, "vZ", null); +runtime.ext_scratch3_looks._say("fail 100: 1.23 should be < -0", target); } if (!(("" + (1.23 === -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 101: 1.23 should be = -0",}, b0, false, false, "v1", null); +runtime.ext_scratch3_looks._say("fail 101: 1.23 should be = -0", target); } if (!(("" + (1.23 > -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 102: 1.23 should be > -0",}, b0, false, false, "v3", null); +runtime.ext_scratch3_looks._say("fail 102: 1.23 should be > -0", target); } if (!(("" + (1.23 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 103: 1.23 should be < -1",}, b0, false, false, "v5", null); +runtime.ext_scratch3_looks._say("fail 103: 1.23 should be < -1", target); } if (!(("" + (1.23 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 104: 1.23 should be = -1",}, b0, false, false, "v7", null); +runtime.ext_scratch3_looks._say("fail 104: 1.23 should be = -1", target); } if (!(("" + (1.23 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 105: 1.23 should be > -1",}, b0, false, false, "v9", null); +runtime.ext_scratch3_looks._say("fail 105: 1.23 should be > -1", target); } if (!(("" + ("1.23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 106: 1.23 should be < true",}, b0, false, false, "v#", null); +runtime.ext_scratch3_looks._say("fail 106: 1.23 should be < true", target); } if (!(("" + (1.23 === 1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 107: 1.23 should be = true",}, b0, false, false, "v(", null); +runtime.ext_scratch3_looks._say("fail 107: 1.23 should be = true", target); } if (!(("" + ("1.23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 108: 1.23 should be > true",}, b0, false, false, "v*", null); +runtime.ext_scratch3_looks._say("fail 108: 1.23 should be > true", target); } if (!(("" + ("1.23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 109: 1.23 should be < false",}, b0, false, false, "v,", null); +runtime.ext_scratch3_looks._say("fail 109: 1.23 should be < false", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 110: 1.23 should be = false",}, b0, false, false, "v.", null); +runtime.ext_scratch3_looks._say("fail 110: 1.23 should be = false", target); } if (!(("" + ("1.23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 111: 1.23 should be > false",}, b0, false, false, "v:", null); +runtime.ext_scratch3_looks._say("fail 111: 1.23 should be > false", target); } if (!(("" + ("1.23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 112: 1.23 should be < NaN",}, b0, false, false, "v=", null); +runtime.ext_scratch3_looks._say("fail 112: 1.23 should be < NaN", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 113: 1.23 should be = NaN",}, b0, false, false, "v@", null); +runtime.ext_scratch3_looks._say("fail 113: 1.23 should be = NaN", target); } if (!(("" + ("1.23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 114: 1.23 should be > NaN",}, b0, false, false, "v]", null); +runtime.ext_scratch3_looks._say("fail 114: 1.23 should be > NaN", target); } if (!(("" + (1.23 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 115: 1.23 should be < Infinity",}, b0, false, false, "v_", null); +runtime.ext_scratch3_looks._say("fail 115: 1.23 should be < Infinity", target); } if (!(("" + (1.23 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 116: 1.23 should be = Infinity",}, b0, false, false, "v{", null); +runtime.ext_scratch3_looks._say("fail 116: 1.23 should be = Infinity", target); } if (!(("" + (1.23 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 117: 1.23 should be > Infinity",}, b0, false, false, "v}", null); +runtime.ext_scratch3_looks._say("fail 117: 1.23 should be > Infinity", target); } if (!(("" + ("1.23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 118: 1.23 should be < banana",}, b0, false, false, "wa", null); +runtime.ext_scratch3_looks._say("fail 118: 1.23 should be < banana", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 119: 1.23 should be = banana",}, b0, false, false, "wc", null); +runtime.ext_scratch3_looks._say("fail 119: 1.23 should be = banana", target); } if (!(("" + ("1.23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 120: 1.23 should be > banana",}, b0, false, false, "we", null); +runtime.ext_scratch3_looks._say("fail 120: 1.23 should be > banana", target); } if (!(("" + ("1.23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 121: 1.23 should be < 🎉",}, b0, false, false, "wg", null); +runtime.ext_scratch3_looks._say("fail 121: 1.23 should be < 🎉", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 122: 1.23 should be = 🎉",}, b0, false, false, "wi", null); +runtime.ext_scratch3_looks._say("fail 122: 1.23 should be = 🎉", target); } if (!(("" + ("1.23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 123: 1.23 should be > 🎉",}, b0, false, false, "wk", null); +runtime.ext_scratch3_looks._say("fail 123: 1.23 should be > 🎉", target); } if (!(("" + ("1.23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 124: 1.23 should be < ",}, b0, false, false, "wm", null); +runtime.ext_scratch3_looks._say("fail 124: 1.23 should be < ", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 125: 1.23 should be = ",}, b0, false, false, "wo", null); +runtime.ext_scratch3_looks._say("fail 125: 1.23 should be = ", target); } if (!(("" + ("1.23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 126: 1.23 should be > ",}, b0, false, false, "wq", null); +runtime.ext_scratch3_looks._say("fail 126: 1.23 should be > ", target); } if (!(("" + (0.23 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 127: .23 should be < 0",}, b0, false, false, "ws", null); +runtime.ext_scratch3_looks._say("fail 127: .23 should be < 0", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 128: .23 should be = 0",}, b0, false, false, "wu", null); +runtime.ext_scratch3_looks._say("fail 128: .23 should be = 0", target); } if (!(("" + (0.23 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 129: .23 should be > 0",}, b0, false, false, "ww", null); +runtime.ext_scratch3_looks._say("fail 129: .23 should be > 0", target); } if (!(("" + (0.23 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 130: .23 should be < 0.0",}, b0, false, false, "wy", null); +runtime.ext_scratch3_looks._say("fail 130: .23 should be < 0.0", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 131: .23 should be = 0.0",}, b0, false, false, "wA", null); +runtime.ext_scratch3_looks._say("fail 131: .23 should be = 0.0", target); } if (!(("" + (0.23 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 132: .23 should be > 0.0",}, b0, false, false, "wC", null); +runtime.ext_scratch3_looks._say("fail 132: .23 should be > 0.0", target); } if (!(("" + (0.23 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 133: .23 should be < 1.23",}, b0, false, false, "wE", null); +runtime.ext_scratch3_looks._say("fail 133: .23 should be < 1.23", target); } if (!(("" + (0.23 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 134: .23 should be = 1.23",}, b0, false, false, "wG", null); +runtime.ext_scratch3_looks._say("fail 134: .23 should be = 1.23", target); } if (!(("" + (0.23 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 135: .23 should be > 1.23",}, b0, false, false, "wI", null); +runtime.ext_scratch3_looks._say("fail 135: .23 should be > 1.23", target); } if (!(("" + (0.23 < 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 136: .23 should be < .23",}, b0, false, false, "wK", null); +runtime.ext_scratch3_looks._say("fail 136: .23 should be < .23", target); } if (!(("" + (0.23 === 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 137: .23 should be = .23",}, b0, false, false, "wM", null); +runtime.ext_scratch3_looks._say("fail 137: .23 should be = .23", target); } if (!(("" + (0.23 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 138: .23 should be > .23",}, b0, false, false, "wO", null); +runtime.ext_scratch3_looks._say("fail 138: .23 should be > .23", target); } if (!(("" + (0.23 < 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 139: .23 should be < 0.123",}, b0, false, false, "wQ", null); +runtime.ext_scratch3_looks._say("fail 139: .23 should be < 0.123", target); } if (!(("" + (0.23 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 140: .23 should be = 0.123",}, b0, false, false, "wS", null); +runtime.ext_scratch3_looks._say("fail 140: .23 should be = 0.123", target); } if (!(("" + (0.23 > 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 141: .23 should be > 0.123",}, b0, false, false, "wU", null); +runtime.ext_scratch3_looks._say("fail 141: .23 should be > 0.123", target); } if (!(("" + (0.23 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 142: .23 should be < -0",}, b0, false, false, "wW", null); +runtime.ext_scratch3_looks._say("fail 142: .23 should be < -0", target); } if (!(("" + (0.23 === -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 143: .23 should be = -0",}, b0, false, false, "wY", null); +runtime.ext_scratch3_looks._say("fail 143: .23 should be = -0", target); } if (!(("" + (0.23 > -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 144: .23 should be > -0",}, b0, false, false, "w0", null); +runtime.ext_scratch3_looks._say("fail 144: .23 should be > -0", target); } if (!(("" + (0.23 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 145: .23 should be < -1",}, b0, false, false, "w2", null); +runtime.ext_scratch3_looks._say("fail 145: .23 should be < -1", target); } if (!(("" + (0.23 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 146: .23 should be = -1",}, b0, false, false, "w4", null); +runtime.ext_scratch3_looks._say("fail 146: .23 should be = -1", target); } if (!(("" + (0.23 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 147: .23 should be > -1",}, b0, false, false, "w6", null); +runtime.ext_scratch3_looks._say("fail 147: .23 should be > -1", target); } if (!(("" + (".23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 148: .23 should be < true",}, b0, false, false, "w8", null); +runtime.ext_scratch3_looks._say("fail 148: .23 should be < true", target); } if (!(("" + (0.23 === 1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 149: .23 should be = true",}, b0, false, false, "w!", null); +runtime.ext_scratch3_looks._say("fail 149: .23 should be = true", target); } if (!(("" + (".23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 150: .23 should be > true",}, b0, false, false, "w%", null); +runtime.ext_scratch3_looks._say("fail 150: .23 should be > true", target); } if (!(("" + (".23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 151: .23 should be < false",}, b0, false, false, "w)", null); +runtime.ext_scratch3_looks._say("fail 151: .23 should be < false", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 152: .23 should be = false",}, b0, false, false, "w+", null); +runtime.ext_scratch3_looks._say("fail 152: .23 should be = false", target); } if (!(("" + (".23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 153: .23 should be > false",}, b0, false, false, "w-", null); +runtime.ext_scratch3_looks._say("fail 153: .23 should be > false", target); } if (!(("" + (".23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 154: .23 should be < NaN",}, b0, false, false, "w/", null); +runtime.ext_scratch3_looks._say("fail 154: .23 should be < NaN", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 155: .23 should be = NaN",}, b0, false, false, "w;", null); +runtime.ext_scratch3_looks._say("fail 155: .23 should be = NaN", target); } if (!(("" + (".23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 156: .23 should be > NaN",}, b0, false, false, "w?", null); +runtime.ext_scratch3_looks._say("fail 156: .23 should be > NaN", target); } if (!(("" + (0.23 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 157: .23 should be < Infinity",}, b0, false, false, "w[", null); +runtime.ext_scratch3_looks._say("fail 157: .23 should be < Infinity", target); } if (!(("" + (0.23 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 158: .23 should be = Infinity",}, b0, false, false, "w^", null); +runtime.ext_scratch3_looks._say("fail 158: .23 should be = Infinity", target); } if (!(("" + (0.23 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 159: .23 should be > Infinity",}, b0, false, false, "w`", null); +runtime.ext_scratch3_looks._say("fail 159: .23 should be > Infinity", target); } if (!(("" + (".23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 160: .23 should be < banana",}, b0, false, false, "w|", null); +runtime.ext_scratch3_looks._say("fail 160: .23 should be < banana", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 161: .23 should be = banana",}, b0, false, false, "w~", null); +runtime.ext_scratch3_looks._say("fail 161: .23 should be = banana", target); } if (!(("" + (".23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 162: .23 should be > banana",}, b0, false, false, "xb", null); +runtime.ext_scratch3_looks._say("fail 162: .23 should be > banana", target); } if (!(("" + (".23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 163: .23 should be < 🎉",}, b0, false, false, "xd", null); +runtime.ext_scratch3_looks._say("fail 163: .23 should be < 🎉", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 164: .23 should be = 🎉",}, b0, false, false, "xf", null); +runtime.ext_scratch3_looks._say("fail 164: .23 should be = 🎉", target); } if (!(("" + (".23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 165: .23 should be > 🎉",}, b0, false, false, "xh", null); +runtime.ext_scratch3_looks._say("fail 165: .23 should be > 🎉", target); } if (!(("" + (".23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 166: .23 should be < ",}, b0, false, false, "xj", null); +runtime.ext_scratch3_looks._say("fail 166: .23 should be < ", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 167: .23 should be = ",}, b0, false, false, "xl", null); +runtime.ext_scratch3_looks._say("fail 167: .23 should be = ", target); } if (!(("" + (".23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 168: .23 should be > ",}, b0, false, false, "xn", null); +runtime.ext_scratch3_looks._say("fail 168: .23 should be > ", target); } if (!(("" + (0.123 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 169: 0.123 should be < 0",}, b0, false, false, "xp", null); +runtime.ext_scratch3_looks._say("fail 169: 0.123 should be < 0", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 170: 0.123 should be = 0",}, b0, false, false, "xr", null); +runtime.ext_scratch3_looks._say("fail 170: 0.123 should be = 0", target); } if (!(("" + (0.123 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 171: 0.123 should be > 0",}, b0, false, false, "xt", null); +runtime.ext_scratch3_looks._say("fail 171: 0.123 should be > 0", target); } if (!(("" + (0.123 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 172: 0.123 should be < 0.0",}, b0, false, false, "xv", null); +runtime.ext_scratch3_looks._say("fail 172: 0.123 should be < 0.0", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 173: 0.123 should be = 0.0",}, b0, false, false, "xx", null); +runtime.ext_scratch3_looks._say("fail 173: 0.123 should be = 0.0", target); } if (!(("" + (0.123 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 174: 0.123 should be > 0.0",}, b0, false, false, "xz", null); +runtime.ext_scratch3_looks._say("fail 174: 0.123 should be > 0.0", target); } if (!(("" + (0.123 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 175: 0.123 should be < 1.23",}, b0, false, false, "xB", null); +runtime.ext_scratch3_looks._say("fail 175: 0.123 should be < 1.23", target); } if (!(("" + (0.123 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 176: 0.123 should be = 1.23",}, b0, false, false, "xD", null); +runtime.ext_scratch3_looks._say("fail 176: 0.123 should be = 1.23", target); } if (!(("" + (0.123 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 177: 0.123 should be > 1.23",}, b0, false, false, "xF", null); +runtime.ext_scratch3_looks._say("fail 177: 0.123 should be > 1.23", target); } if (!(("" + (0.123 < 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 178: 0.123 should be < .23",}, b0, false, false, "xH", null); +runtime.ext_scratch3_looks._say("fail 178: 0.123 should be < .23", target); } if (!(("" + (0.123 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 179: 0.123 should be = .23",}, b0, false, false, "xJ", null); +runtime.ext_scratch3_looks._say("fail 179: 0.123 should be = .23", target); } if (!(("" + (0.123 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 180: 0.123 should be > .23",}, b0, false, false, "xL", null); +runtime.ext_scratch3_looks._say("fail 180: 0.123 should be > .23", target); } if (!(("" + (0.123 < 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 181: 0.123 should be < 0.123",}, b0, false, false, "xN", null); +runtime.ext_scratch3_looks._say("fail 181: 0.123 should be < 0.123", target); } if (!(("" + (0.123 === 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 182: 0.123 should be = 0.123",}, b0, false, false, "xP", null); +runtime.ext_scratch3_looks._say("fail 182: 0.123 should be = 0.123", target); } if (!(("" + (0.123 > 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 183: 0.123 should be > 0.123",}, b0, false, false, "xR", null); +runtime.ext_scratch3_looks._say("fail 183: 0.123 should be > 0.123", target); } if (!(("" + (0.123 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 184: 0.123 should be < -0",}, b0, false, false, "xT", null); +runtime.ext_scratch3_looks._say("fail 184: 0.123 should be < -0", target); } if (!(("" + (0.123 === -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 185: 0.123 should be = -0",}, b0, false, false, "xV", null); +runtime.ext_scratch3_looks._say("fail 185: 0.123 should be = -0", target); } if (!(("" + (0.123 > -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 186: 0.123 should be > -0",}, b0, false, false, "xX", null); +runtime.ext_scratch3_looks._say("fail 186: 0.123 should be > -0", target); } if (!(("" + (0.123 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 187: 0.123 should be < -1",}, b0, false, false, "xZ", null); +runtime.ext_scratch3_looks._say("fail 187: 0.123 should be < -1", target); } if (!(("" + (0.123 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 188: 0.123 should be = -1",}, b0, false, false, "x1", null); +runtime.ext_scratch3_looks._say("fail 188: 0.123 should be = -1", target); } if (!(("" + (0.123 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 189: 0.123 should be > -1",}, b0, false, false, "x3", null); +runtime.ext_scratch3_looks._say("fail 189: 0.123 should be > -1", target); } if (!(("" + ("0.123".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 190: 0.123 should be < true",}, b0, false, false, "x5", null); +runtime.ext_scratch3_looks._say("fail 190: 0.123 should be < true", target); } if (!(("" + (0.123 === 1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 191: 0.123 should be = true",}, b0, false, false, "x7", null); +runtime.ext_scratch3_looks._say("fail 191: 0.123 should be = true", target); } if (!(("" + ("0.123".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 192: 0.123 should be > true",}, b0, false, false, "x9", null); +runtime.ext_scratch3_looks._say("fail 192: 0.123 should be > true", target); } if (!(("" + ("0.123".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 193: 0.123 should be < false",}, b0, false, false, "x#", null); +runtime.ext_scratch3_looks._say("fail 193: 0.123 should be < false", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 194: 0.123 should be = false",}, b0, false, false, "x(", null); +runtime.ext_scratch3_looks._say("fail 194: 0.123 should be = false", target); } if (!(("" + ("0.123".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 195: 0.123 should be > false",}, b0, false, false, "x*", null); +runtime.ext_scratch3_looks._say("fail 195: 0.123 should be > false", target); } if (!(("" + ("0.123".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 196: 0.123 should be < NaN",}, b0, false, false, "x,", null); +runtime.ext_scratch3_looks._say("fail 196: 0.123 should be < NaN", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 197: 0.123 should be = NaN",}, b0, false, false, "x.", null); +runtime.ext_scratch3_looks._say("fail 197: 0.123 should be = NaN", target); } if (!(("" + ("0.123".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 198: 0.123 should be > NaN",}, b0, false, false, "x:", null); +runtime.ext_scratch3_looks._say("fail 198: 0.123 should be > NaN", target); } if (!(("" + (0.123 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 199: 0.123 should be < Infinity",}, b0, false, false, "x=", null); +runtime.ext_scratch3_looks._say("fail 199: 0.123 should be < Infinity", target); } if (!(("" + (0.123 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 200: 0.123 should be = Infinity",}, b0, false, false, "x@", null); +runtime.ext_scratch3_looks._say("fail 200: 0.123 should be = Infinity", target); } if (!(("" + (0.123 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 201: 0.123 should be > Infinity",}, b0, false, false, "x]", null); +runtime.ext_scratch3_looks._say("fail 201: 0.123 should be > Infinity", target); } if (!(("" + ("0.123".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 202: 0.123 should be < banana",}, b0, false, false, "x_", null); +runtime.ext_scratch3_looks._say("fail 202: 0.123 should be < banana", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 203: 0.123 should be = banana",}, b0, false, false, "x{", null); +runtime.ext_scratch3_looks._say("fail 203: 0.123 should be = banana", target); } if (!(("" + ("0.123".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 204: 0.123 should be > banana",}, b0, false, false, "x}", null); +runtime.ext_scratch3_looks._say("fail 204: 0.123 should be > banana", target); } if (!(("" + ("0.123".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 205: 0.123 should be < 🎉",}, b0, false, false, "ya", null); +runtime.ext_scratch3_looks._say("fail 205: 0.123 should be < 🎉", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 206: 0.123 should be = 🎉",}, b0, false, false, "yc", null); +runtime.ext_scratch3_looks._say("fail 206: 0.123 should be = 🎉", target); } if (!(("" + ("0.123".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 207: 0.123 should be > 🎉",}, b0, false, false, "ye", null); +runtime.ext_scratch3_looks._say("fail 207: 0.123 should be > 🎉", target); } if (!(("" + ("0.123".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 208: 0.123 should be < ",}, b0, false, false, "yg", null); +runtime.ext_scratch3_looks._say("fail 208: 0.123 should be < ", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 209: 0.123 should be = ",}, b0, false, false, "yi", null); +runtime.ext_scratch3_looks._say("fail 209: 0.123 should be = ", target); } if (!(("" + ("0.123".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 210: 0.123 should be > ",}, b0, false, false, "yk", null); +runtime.ext_scratch3_looks._say("fail 210: 0.123 should be > ", target); } if (!(("" + (-0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 211: -0 should be < 0",}, b0, false, false, "ym", null); +runtime.ext_scratch3_looks._say("fail 211: -0 should be < 0", target); } if (!(("" + (-0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 212: -0 should be = 0",}, b0, false, false, "yo", null); +runtime.ext_scratch3_looks._say("fail 212: -0 should be = 0", target); } if (!(("" + (-0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 213: -0 should be > 0",}, b0, false, false, "yq", null); +runtime.ext_scratch3_looks._say("fail 213: -0 should be > 0", target); } if (!(("" + (-0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 214: -0 should be < 0.0",}, b0, false, false, "ys", null); +runtime.ext_scratch3_looks._say("fail 214: -0 should be < 0.0", target); } if (!(("" + (-0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 215: -0 should be = 0.0",}, b0, false, false, "yu", null); +runtime.ext_scratch3_looks._say("fail 215: -0 should be = 0.0", target); } if (!(("" + (-0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 216: -0 should be > 0.0",}, b0, false, false, "yw", null); +runtime.ext_scratch3_looks._say("fail 216: -0 should be > 0.0", target); } if (!(("" + (-0 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 217: -0 should be < 1.23",}, b0, false, false, "yy", null); +runtime.ext_scratch3_looks._say("fail 217: -0 should be < 1.23", target); } if (!(("" + (-0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 218: -0 should be = 1.23",}, b0, false, false, "yA", null); +runtime.ext_scratch3_looks._say("fail 218: -0 should be = 1.23", target); } if (!(("" + (-0 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 219: -0 should be > 1.23",}, b0, false, false, "yC", null); +runtime.ext_scratch3_looks._say("fail 219: -0 should be > 1.23", target); } if (!(("" + (-0 < 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 220: -0 should be < .23",}, b0, false, false, "yE", null); +runtime.ext_scratch3_looks._say("fail 220: -0 should be < .23", target); } if (!(("" + (-0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 221: -0 should be = .23",}, b0, false, false, "yG", null); +runtime.ext_scratch3_looks._say("fail 221: -0 should be = .23", target); } if (!(("" + (-0 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 222: -0 should be > .23",}, b0, false, false, "yI", null); +runtime.ext_scratch3_looks._say("fail 222: -0 should be > .23", target); } if (!(("" + (-0 < 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 223: -0 should be < 0.123",}, b0, false, false, "yK", null); +runtime.ext_scratch3_looks._say("fail 223: -0 should be < 0.123", target); } if (!(("" + (-0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 224: -0 should be = 0.123",}, b0, false, false, "yM", null); +runtime.ext_scratch3_looks._say("fail 224: -0 should be = 0.123", target); } if (!(("" + (-0 > 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 225: -0 should be > 0.123",}, b0, false, false, "yO", null); +runtime.ext_scratch3_looks._say("fail 225: -0 should be > 0.123", target); } if (!(("" + (-0 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 226: -0 should be < -0",}, b0, false, false, "yQ", null); +runtime.ext_scratch3_looks._say("fail 226: -0 should be < -0", target); } if (!(("" + (-0 === -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 227: -0 should be = -0",}, b0, false, false, "yS", null); +runtime.ext_scratch3_looks._say("fail 227: -0 should be = -0", target); } if (!(("" + (-0 > -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 228: -0 should be > -0",}, b0, false, false, "yU", null); +runtime.ext_scratch3_looks._say("fail 228: -0 should be > -0", target); } if (!(("" + (-0 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 229: -0 should be < -1",}, b0, false, false, "yW", null); +runtime.ext_scratch3_looks._say("fail 229: -0 should be < -1", target); } if (!(("" + (-0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 230: -0 should be = -1",}, b0, false, false, "yY", null); +runtime.ext_scratch3_looks._say("fail 230: -0 should be = -1", target); } if (!(("" + (-0 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 231: -0 should be > -1",}, b0, false, false, "y0", null); +runtime.ext_scratch3_looks._say("fail 231: -0 should be > -1", target); } if (!(("" + ("-0".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 232: -0 should be < true",}, b0, false, false, "y2", null); +runtime.ext_scratch3_looks._say("fail 232: -0 should be < true", target); } if (!(("" + ("-0".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 233: -0 should be = true",}, b0, false, false, "y4", null); +runtime.ext_scratch3_looks._say("fail 233: -0 should be = true", target); } if (!(("" + ("-0".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 234: -0 should be > true",}, b0, false, false, "y6", null); +runtime.ext_scratch3_looks._say("fail 234: -0 should be > true", target); } if (!(("" + ("-0".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 235: -0 should be < false",}, b0, false, false, "y8", null); +runtime.ext_scratch3_looks._say("fail 235: -0 should be < false", target); } if (!(("" + ("-0".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 236: -0 should be = false",}, b0, false, false, "y!", null); +runtime.ext_scratch3_looks._say("fail 236: -0 should be = false", target); } if (!(("" + ("-0".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 237: -0 should be > false",}, b0, false, false, "y%", null); +runtime.ext_scratch3_looks._say("fail 237: -0 should be > false", target); } if (!(("" + ("-0".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 238: -0 should be < NaN",}, b0, false, false, "y)", null); +runtime.ext_scratch3_looks._say("fail 238: -0 should be < NaN", target); } if (!(("" + ("-0".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 239: -0 should be = NaN",}, b0, false, false, "y+", null); +runtime.ext_scratch3_looks._say("fail 239: -0 should be = NaN", target); } if (!(("" + ("-0".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 240: -0 should be > NaN",}, b0, false, false, "y-", null); +runtime.ext_scratch3_looks._say("fail 240: -0 should be > NaN", target); } if (!(("" + (-0 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 241: -0 should be < Infinity",}, b0, false, false, "y/", null); +runtime.ext_scratch3_looks._say("fail 241: -0 should be < Infinity", target); } if (!(("" + (-0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 242: -0 should be = Infinity",}, b0, false, false, "y;", null); +runtime.ext_scratch3_looks._say("fail 242: -0 should be = Infinity", target); } if (!(("" + (-0 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 243: -0 should be > Infinity",}, b0, false, false, "y?", null); +runtime.ext_scratch3_looks._say("fail 243: -0 should be > Infinity", target); } if (!(("" + ("-0".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 244: -0 should be < banana",}, b0, false, false, "y[", null); +runtime.ext_scratch3_looks._say("fail 244: -0 should be < banana", target); } if (!(("" + ("-0".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 245: -0 should be = banana",}, b0, false, false, "y^", null); +runtime.ext_scratch3_looks._say("fail 245: -0 should be = banana", target); } if (!(("" + ("-0".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 246: -0 should be > banana",}, b0, false, false, "y`", null); +runtime.ext_scratch3_looks._say("fail 246: -0 should be > banana", target); } if (!(("" + ("-0".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 247: -0 should be < 🎉",}, b0, false, false, "y|", null); +runtime.ext_scratch3_looks._say("fail 247: -0 should be < 🎉", target); } if (!(("" + ("-0".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 248: -0 should be = 🎉",}, b0, false, false, "y~", null); +runtime.ext_scratch3_looks._say("fail 248: -0 should be = 🎉", target); } if (!(("" + ("-0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 249: -0 should be > 🎉",}, b0, false, false, "zb", null); +runtime.ext_scratch3_looks._say("fail 249: -0 should be > 🎉", target); } if (!(("" + ("-0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 250: -0 should be < ",}, b0, false, false, "zd", null); +runtime.ext_scratch3_looks._say("fail 250: -0 should be < ", target); } if (!(("" + ("-0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 251: -0 should be = ",}, b0, false, false, "zf", null); +runtime.ext_scratch3_looks._say("fail 251: -0 should be = ", target); } if (!(("" + ("-0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 252: -0 should be > ",}, b0, false, false, "zh", null); +runtime.ext_scratch3_looks._say("fail 252: -0 should be > ", target); } if (!(("" + (-1 < 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 253: -1 should be < 0",}, b0, false, false, "zj", null); +runtime.ext_scratch3_looks._say("fail 253: -1 should be < 0", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 254: -1 should be = 0",}, b0, false, false, "zl", null); +runtime.ext_scratch3_looks._say("fail 254: -1 should be = 0", target); } if (!(("" + (-1 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 255: -1 should be > 0",}, b0, false, false, "zn", null); +runtime.ext_scratch3_looks._say("fail 255: -1 should be > 0", target); } if (!(("" + (-1 < 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 256: -1 should be < 0.0",}, b0, false, false, "zp", null); +runtime.ext_scratch3_looks._say("fail 256: -1 should be < 0.0", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 257: -1 should be = 0.0",}, b0, false, false, "zr", null); +runtime.ext_scratch3_looks._say("fail 257: -1 should be = 0.0", target); } if (!(("" + (-1 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 258: -1 should be > 0.0",}, b0, false, false, "zt", null); +runtime.ext_scratch3_looks._say("fail 258: -1 should be > 0.0", target); } if (!(("" + (-1 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 259: -1 should be < 1.23",}, b0, false, false, "zv", null); +runtime.ext_scratch3_looks._say("fail 259: -1 should be < 1.23", target); } if (!(("" + (-1 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 260: -1 should be = 1.23",}, b0, false, false, "zx", null); +runtime.ext_scratch3_looks._say("fail 260: -1 should be = 1.23", target); } if (!(("" + (-1 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 261: -1 should be > 1.23",}, b0, false, false, "zz", null); +runtime.ext_scratch3_looks._say("fail 261: -1 should be > 1.23", target); } if (!(("" + (-1 < 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 262: -1 should be < .23",}, b0, false, false, "zB", null); +runtime.ext_scratch3_looks._say("fail 262: -1 should be < .23", target); } if (!(("" + (-1 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 263: -1 should be = .23",}, b0, false, false, "zD", null); +runtime.ext_scratch3_looks._say("fail 263: -1 should be = .23", target); } if (!(("" + (-1 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 264: -1 should be > .23",}, b0, false, false, "zF", null); +runtime.ext_scratch3_looks._say("fail 264: -1 should be > .23", target); } if (!(("" + (-1 < 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 265: -1 should be < 0.123",}, b0, false, false, "zH", null); +runtime.ext_scratch3_looks._say("fail 265: -1 should be < 0.123", target); } if (!(("" + (-1 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 266: -1 should be = 0.123",}, b0, false, false, "zJ", null); +runtime.ext_scratch3_looks._say("fail 266: -1 should be = 0.123", target); } if (!(("" + (-1 > 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 267: -1 should be > 0.123",}, b0, false, false, "zL", null); +runtime.ext_scratch3_looks._say("fail 267: -1 should be > 0.123", target); } if (!(("" + (-1 < -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 268: -1 should be < -0",}, b0, false, false, "zN", null); +runtime.ext_scratch3_looks._say("fail 268: -1 should be < -0", target); } if (!(("" + (-1 === -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 269: -1 should be = -0",}, b0, false, false, "zP", null); +runtime.ext_scratch3_looks._say("fail 269: -1 should be = -0", target); } if (!(("" + (-1 > -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 270: -1 should be > -0",}, b0, false, false, "zR", null); +runtime.ext_scratch3_looks._say("fail 270: -1 should be > -0", target); } if (!(("" + (-1 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 271: -1 should be < -1",}, b0, false, false, "zT", null); +runtime.ext_scratch3_looks._say("fail 271: -1 should be < -1", target); } if (!(("" + (-1 === -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 272: -1 should be = -1",}, b0, false, false, "zV", null); +runtime.ext_scratch3_looks._say("fail 272: -1 should be = -1", target); } if (!(("" + (-1 > -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 273: -1 should be > -1",}, b0, false, false, "zX", null); +runtime.ext_scratch3_looks._say("fail 273: -1 should be > -1", target); } if (!(("" + ("-1".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 274: -1 should be < true",}, b0, false, false, "zZ", null); +runtime.ext_scratch3_looks._say("fail 274: -1 should be < true", target); } if (!(("" + (-1 === 1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 275: -1 should be = true",}, b0, false, false, "z1", null); +runtime.ext_scratch3_looks._say("fail 275: -1 should be = true", target); } if (!(("" + ("-1".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 276: -1 should be > true",}, b0, false, false, "z3", null); +runtime.ext_scratch3_looks._say("fail 276: -1 should be > true", target); } if (!(("" + ("-1".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 277: -1 should be < false",}, b0, false, false, "z5", null); +runtime.ext_scratch3_looks._say("fail 277: -1 should be < false", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 278: -1 should be = false",}, b0, false, false, "z7", null); +runtime.ext_scratch3_looks._say("fail 278: -1 should be = false", target); } if (!(("" + ("-1".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 279: -1 should be > false",}, b0, false, false, "z9", null); +runtime.ext_scratch3_looks._say("fail 279: -1 should be > false", target); } if (!(("" + ("-1".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 280: -1 should be < NaN",}, b0, false, false, "z#", null); +runtime.ext_scratch3_looks._say("fail 280: -1 should be < NaN", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 281: -1 should be = NaN",}, b0, false, false, "z(", null); +runtime.ext_scratch3_looks._say("fail 281: -1 should be = NaN", target); } if (!(("" + ("-1".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 282: -1 should be > NaN",}, b0, false, false, "z*", null); +runtime.ext_scratch3_looks._say("fail 282: -1 should be > NaN", target); } if (!(("" + (-1 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 283: -1 should be < Infinity",}, b0, false, false, "z,", null); +runtime.ext_scratch3_looks._say("fail 283: -1 should be < Infinity", target); } if (!(("" + (-1 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 284: -1 should be = Infinity",}, b0, false, false, "z.", null); +runtime.ext_scratch3_looks._say("fail 284: -1 should be = Infinity", target); } if (!(("" + (-1 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 285: -1 should be > Infinity",}, b0, false, false, "z:", null); +runtime.ext_scratch3_looks._say("fail 285: -1 should be > Infinity", target); } if (!(("" + ("-1".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 286: -1 should be < banana",}, b0, false, false, "z=", null); +runtime.ext_scratch3_looks._say("fail 286: -1 should be < banana", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 287: -1 should be = banana",}, b0, false, false, "z@", null); +runtime.ext_scratch3_looks._say("fail 287: -1 should be = banana", target); } if (!(("" + ("-1".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 288: -1 should be > banana",}, b0, false, false, "z]", null); +runtime.ext_scratch3_looks._say("fail 288: -1 should be > banana", target); } if (!(("" + ("-1".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 289: -1 should be < 🎉",}, b0, false, false, "z_", null); +runtime.ext_scratch3_looks._say("fail 289: -1 should be < 🎉", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 290: -1 should be = 🎉",}, b0, false, false, "z{", null); +runtime.ext_scratch3_looks._say("fail 290: -1 should be = 🎉", target); } if (!(("" + ("-1".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 291: -1 should be > 🎉",}, b0, false, false, "z}", null); +runtime.ext_scratch3_looks._say("fail 291: -1 should be > 🎉", target); } if (!(("" + ("-1".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 292: -1 should be < ",}, b0, false, false, "Aa", null); +runtime.ext_scratch3_looks._say("fail 292: -1 should be < ", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 293: -1 should be = ",}, b0, false, false, "Ac", null); +runtime.ext_scratch3_looks._say("fail 293: -1 should be = ", target); } if (!(("" + ("-1".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 294: -1 should be > ",}, b0, false, false, "Ae", null); +runtime.ext_scratch3_looks._say("fail 294: -1 should be > ", target); } if (!(("" + ("true".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 295: true should be < 0",}, b0, false, false, "Ag", null); +runtime.ext_scratch3_looks._say("fail 295: true should be < 0", target); } if (!(("" + ("true".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 296: true should be = 0",}, b0, false, false, "Ai", null); +runtime.ext_scratch3_looks._say("fail 296: true should be = 0", target); } if (!(("" + ("true".toLowerCase() > "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 297: true should be > 0",}, b0, false, false, "Ak", null); +runtime.ext_scratch3_looks._say("fail 297: true should be > 0", target); } if (!(("" + ("true".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 298: true should be < 0.0",}, b0, false, false, "Am", null); +runtime.ext_scratch3_looks._say("fail 298: true should be < 0.0", target); } if (!(("" + ("true".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 299: true should be = 0.0",}, b0, false, false, "Ao", null); +runtime.ext_scratch3_looks._say("fail 299: true should be = 0.0", target); } if (!(("" + ("true".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 300: true should be > 0.0",}, b0, false, false, "Aq", null); +runtime.ext_scratch3_looks._say("fail 300: true should be > 0.0", target); } if (!(("" + ("true".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 301: true should be < 1.23",}, b0, false, false, "As", null); +runtime.ext_scratch3_looks._say("fail 301: true should be < 1.23", target); } if (!(("" + (1 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 302: true should be = 1.23",}, b0, false, false, "Au", null); +runtime.ext_scratch3_looks._say("fail 302: true should be = 1.23", target); } if (!(("" + ("true".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 303: true should be > 1.23",}, b0, false, false, "Aw", null); +runtime.ext_scratch3_looks._say("fail 303: true should be > 1.23", target); } if (!(("" + ("true".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 304: true should be < .23",}, b0, false, false, "Ay", null); +runtime.ext_scratch3_looks._say("fail 304: true should be < .23", target); } if (!(("" + (1 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 305: true should be = .23",}, b0, false, false, "AA", null); +runtime.ext_scratch3_looks._say("fail 305: true should be = .23", target); } if (!(("" + ("true".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 306: true should be > .23",}, b0, false, false, "AC", null); +runtime.ext_scratch3_looks._say("fail 306: true should be > .23", target); } if (!(("" + ("true".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 307: true should be < 0.123",}, b0, false, false, "AE", null); +runtime.ext_scratch3_looks._say("fail 307: true should be < 0.123", target); } if (!(("" + (1 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 308: true should be = 0.123",}, b0, false, false, "AG", null); +runtime.ext_scratch3_looks._say("fail 308: true should be = 0.123", target); } if (!(("" + ("true".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 309: true should be > 0.123",}, b0, false, false, "AI", null); +runtime.ext_scratch3_looks._say("fail 309: true should be > 0.123", target); } if (!(("" + ("true".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 310: true should be < -0",}, b0, false, false, "AK", null); +runtime.ext_scratch3_looks._say("fail 310: true should be < -0", target); } if (!(("" + ("true".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 311: true should be = -0",}, b0, false, false, "AM", null); +runtime.ext_scratch3_looks._say("fail 311: true should be = -0", target); } if (!(("" + ("true".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 312: true should be > -0",}, b0, false, false, "AO", null); +runtime.ext_scratch3_looks._say("fail 312: true should be > -0", target); } if (!(("" + ("true".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 313: true should be < -1",}, b0, false, false, "AQ", null); +runtime.ext_scratch3_looks._say("fail 313: true should be < -1", target); } if (!(("" + (1 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 314: true should be = -1",}, b0, false, false, "AS", null); +runtime.ext_scratch3_looks._say("fail 314: true should be = -1", target); } if (!(("" + ("true".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 315: true should be > -1",}, b0, false, false, "AU", null); +runtime.ext_scratch3_looks._say("fail 315: true should be > -1", target); } if (!(("" + ("true".toLowerCase() < "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 316: true should be < true",}, b0, false, false, "AW", null); +runtime.ext_scratch3_looks._say("fail 316: true should be < true", target); } if (!(("" + ("true".toLowerCase() === "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 317: true should be = true",}, b0, false, false, "AY", null); +runtime.ext_scratch3_looks._say("fail 317: true should be = true", target); } if (!(("" + ("true".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 318: true should be > true",}, b0, false, false, "A0", null); +runtime.ext_scratch3_looks._say("fail 318: true should be > true", target); } if (!(("" + ("true".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 319: true should be < false",}, b0, false, false, "A2", null); +runtime.ext_scratch3_looks._say("fail 319: true should be < false", target); } if (!(("" + ("true".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 320: true should be = false",}, b0, false, false, "A4", null); +runtime.ext_scratch3_looks._say("fail 320: true should be = false", target); } if (!(("" + ("true".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 321: true should be > false",}, b0, false, false, "A6", null); +runtime.ext_scratch3_looks._say("fail 321: true should be > false", target); } if (!(("" + ("true".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 322: true should be < NaN",}, b0, false, false, "A8", null); +runtime.ext_scratch3_looks._say("fail 322: true should be < NaN", target); } if (!(("" + ("true".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 323: true should be = NaN",}, b0, false, false, "A!", null); +runtime.ext_scratch3_looks._say("fail 323: true should be = NaN", target); } if (!(("" + ("true".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 324: true should be > NaN",}, b0, false, false, "A%", null); +runtime.ext_scratch3_looks._say("fail 324: true should be > NaN", target); } if (!(("" + ("true".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 325: true should be < Infinity",}, b0, false, false, "A)", null); +runtime.ext_scratch3_looks._say("fail 325: true should be < Infinity", target); } if (!(("" + (1 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 326: true should be = Infinity",}, b0, false, false, "A+", null); +runtime.ext_scratch3_looks._say("fail 326: true should be = Infinity", target); } if (!(("" + ("true".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 327: true should be > Infinity",}, b0, false, false, "A-", null); +runtime.ext_scratch3_looks._say("fail 327: true should be > Infinity", target); } if (!(("" + ("true".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 328: true should be < banana",}, b0, false, false, "A/", null); +runtime.ext_scratch3_looks._say("fail 328: true should be < banana", target); } if (!(("" + ("true".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 329: true should be = banana",}, b0, false, false, "A;", null); +runtime.ext_scratch3_looks._say("fail 329: true should be = banana", target); } if (!(("" + ("true".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 330: true should be > banana",}, b0, false, false, "A?", null); +runtime.ext_scratch3_looks._say("fail 330: true should be > banana", target); } if (!(("" + ("true".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 331: true should be < 🎉",}, b0, false, false, "A[", null); +runtime.ext_scratch3_looks._say("fail 331: true should be < 🎉", target); } if (!(("" + ("true".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 332: true should be = 🎉",}, b0, false, false, "A^", null); +runtime.ext_scratch3_looks._say("fail 332: true should be = 🎉", target); } if (!(("" + ("true".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 333: true should be > 🎉",}, b0, false, false, "A`", null); +runtime.ext_scratch3_looks._say("fail 333: true should be > 🎉", target); } if (!(("" + ("true".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 334: true should be < ",}, b0, false, false, "A|", null); +runtime.ext_scratch3_looks._say("fail 334: true should be < ", target); } if (!(("" + ("true".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 335: true should be = ",}, b0, false, false, "A~", null); +runtime.ext_scratch3_looks._say("fail 335: true should be = ", target); } if (!(("" + ("true".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 336: true should be > ",}, b0, false, false, "Bb", null); +runtime.ext_scratch3_looks._say("fail 336: true should be > ", target); } if (!(("" + ("false".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 337: false should be < 0",}, b0, false, false, "Bd", null); +runtime.ext_scratch3_looks._say("fail 337: false should be < 0", target); } if (!(("" + ("false".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 338: false should be = 0",}, b0, false, false, "Bf", null); +runtime.ext_scratch3_looks._say("fail 338: false should be = 0", target); } if (!(("" + ("false".toLowerCase() > "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 339: false should be > 0",}, b0, false, false, "Bh", null); +runtime.ext_scratch3_looks._say("fail 339: false should be > 0", target); } if (!(("" + ("false".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 340: false should be < 0.0",}, b0, false, false, "Bj", null); +runtime.ext_scratch3_looks._say("fail 340: false should be < 0.0", target); } if (!(("" + ("false".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 341: false should be = 0.0",}, b0, false, false, "Bl", null); +runtime.ext_scratch3_looks._say("fail 341: false should be = 0.0", target); } if (!(("" + ("false".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 342: false should be > 0.0",}, b0, false, false, "Bn", null); +runtime.ext_scratch3_looks._say("fail 342: false should be > 0.0", target); } if (!(("" + ("false".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 343: false should be < 1.23",}, b0, false, false, "Bp", null); +runtime.ext_scratch3_looks._say("fail 343: false should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 344: false should be = 1.23",}, b0, false, false, "Br", null); +runtime.ext_scratch3_looks._say("fail 344: false should be = 1.23", target); } if (!(("" + ("false".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 345: false should be > 1.23",}, b0, false, false, "Bt", null); +runtime.ext_scratch3_looks._say("fail 345: false should be > 1.23", target); } if (!(("" + ("false".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 346: false should be < .23",}, b0, false, false, "Bv", null); +runtime.ext_scratch3_looks._say("fail 346: false should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 347: false should be = .23",}, b0, false, false, "Bx", null); +runtime.ext_scratch3_looks._say("fail 347: false should be = .23", target); } if (!(("" + ("false".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 348: false should be > .23",}, b0, false, false, "Bz", null); +runtime.ext_scratch3_looks._say("fail 348: false should be > .23", target); } if (!(("" + ("false".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 349: false should be < 0.123",}, b0, false, false, "BB", null); +runtime.ext_scratch3_looks._say("fail 349: false should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 350: false should be = 0.123",}, b0, false, false, "BD", null); +runtime.ext_scratch3_looks._say("fail 350: false should be = 0.123", target); } if (!(("" + ("false".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 351: false should be > 0.123",}, b0, false, false, "BF", null); +runtime.ext_scratch3_looks._say("fail 351: false should be > 0.123", target); } if (!(("" + ("false".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 352: false should be < -0",}, b0, false, false, "BH", null); +runtime.ext_scratch3_looks._say("fail 352: false should be < -0", target); } if (!(("" + ("false".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 353: false should be = -0",}, b0, false, false, "BJ", null); +runtime.ext_scratch3_looks._say("fail 353: false should be = -0", target); } if (!(("" + ("false".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 354: false should be > -0",}, b0, false, false, "BL", null); +runtime.ext_scratch3_looks._say("fail 354: false should be > -0", target); } if (!(("" + ("false".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 355: false should be < -1",}, b0, false, false, "BN", null); +runtime.ext_scratch3_looks._say("fail 355: false should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 356: false should be = -1",}, b0, false, false, "BP", null); +runtime.ext_scratch3_looks._say("fail 356: false should be = -1", target); } if (!(("" + ("false".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 357: false should be > -1",}, b0, false, false, "BR", null); +runtime.ext_scratch3_looks._say("fail 357: false should be > -1", target); } if (!(("" + ("false".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 358: false should be < true",}, b0, false, false, "BT", null); +runtime.ext_scratch3_looks._say("fail 358: false should be < true", target); } if (!(("" + ("false".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 359: false should be = true",}, b0, false, false, "BV", null); +runtime.ext_scratch3_looks._say("fail 359: false should be = true", target); } if (!(("" + ("false".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 360: false should be > true",}, b0, false, false, "BX", null); +runtime.ext_scratch3_looks._say("fail 360: false should be > true", target); } if (!(("" + ("false".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 361: false should be < false",}, b0, false, false, "BZ", null); +runtime.ext_scratch3_looks._say("fail 361: false should be < false", target); } if (!(("" + ("false".toLowerCase() === "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 362: false should be = false",}, b0, false, false, "B1", null); +runtime.ext_scratch3_looks._say("fail 362: false should be = false", target); } if (!(("" + ("false".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 363: false should be > false",}, b0, false, false, "B3", null); +runtime.ext_scratch3_looks._say("fail 363: false should be > false", target); } if (!(("" + ("false".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 364: false should be < NaN",}, b0, false, false, "B5", null); +runtime.ext_scratch3_looks._say("fail 364: false should be < NaN", target); } if (!(("" + ("false".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 365: false should be = NaN",}, b0, false, false, "B7", null); +runtime.ext_scratch3_looks._say("fail 365: false should be = NaN", target); } if (!(("" + ("false".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 366: false should be > NaN",}, b0, false, false, "B9", null); +runtime.ext_scratch3_looks._say("fail 366: false should be > NaN", target); } if (!(("" + ("false".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 367: false should be < Infinity",}, b0, false, false, "B#", null); +runtime.ext_scratch3_looks._say("fail 367: false should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 368: false should be = Infinity",}, b0, false, false, "B(", null); +runtime.ext_scratch3_looks._say("fail 368: false should be = Infinity", target); } if (!(("" + ("false".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 369: false should be > Infinity",}, b0, false, false, "B*", null); +runtime.ext_scratch3_looks._say("fail 369: false should be > Infinity", target); } if (!(("" + ("false".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 370: false should be < banana",}, b0, false, false, "B,", null); +runtime.ext_scratch3_looks._say("fail 370: false should be < banana", target); } if (!(("" + ("false".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 371: false should be = banana",}, b0, false, false, "B.", null); +runtime.ext_scratch3_looks._say("fail 371: false should be = banana", target); } if (!(("" + ("false".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 372: false should be > banana",}, b0, false, false, "B:", null); +runtime.ext_scratch3_looks._say("fail 372: false should be > banana", target); } if (!(("" + ("false".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 373: false should be < 🎉",}, b0, false, false, "B=", null); +runtime.ext_scratch3_looks._say("fail 373: false should be < 🎉", target); } if (!(("" + ("false".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 374: false should be = 🎉",}, b0, false, false, "B@", null); +runtime.ext_scratch3_looks._say("fail 374: false should be = 🎉", target); } if (!(("" + ("false".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 375: false should be > 🎉",}, b0, false, false, "B]", null); +runtime.ext_scratch3_looks._say("fail 375: false should be > 🎉", target); } if (!(("" + ("false".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 376: false should be < ",}, b0, false, false, "B_", null); +runtime.ext_scratch3_looks._say("fail 376: false should be < ", target); } if (!(("" + ("false".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 377: false should be = ",}, b0, false, false, "B{", null); +runtime.ext_scratch3_looks._say("fail 377: false should be = ", target); } if (!(("" + ("false".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 378: false should be > ",}, b0, false, false, "B}", null); +runtime.ext_scratch3_looks._say("fail 378: false should be > ", target); } if (!(("" + ("NaN".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 379: NaN should be < 0",}, b0, false, false, "Ca", null); +runtime.ext_scratch3_looks._say("fail 379: NaN should be < 0", target); } if (!(("" + ("NaN".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 380: NaN should be = 0",}, b0, false, false, "Cc", null); +runtime.ext_scratch3_looks._say("fail 380: NaN should be = 0", target); } if (!(("" + ("NaN".toLowerCase() > "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 381: NaN should be > 0",}, b0, false, false, "Ce", null); +runtime.ext_scratch3_looks._say("fail 381: NaN should be > 0", target); } if (!(("" + ("NaN".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 382: NaN should be < 0.0",}, b0, false, false, "Cg", null); +runtime.ext_scratch3_looks._say("fail 382: NaN should be < 0.0", target); } if (!(("" + ("NaN".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 383: NaN should be = 0.0",}, b0, false, false, "Ci", null); +runtime.ext_scratch3_looks._say("fail 383: NaN should be = 0.0", target); } if (!(("" + ("NaN".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 384: NaN should be > 0.0",}, b0, false, false, "Ck", null); +runtime.ext_scratch3_looks._say("fail 384: NaN should be > 0.0", target); } if (!(("" + ("NaN".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 385: NaN should be < 1.23",}, b0, false, false, "Cm", null); +runtime.ext_scratch3_looks._say("fail 385: NaN should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 386: NaN should be = 1.23",}, b0, false, false, "Co", null); +runtime.ext_scratch3_looks._say("fail 386: NaN should be = 1.23", target); } if (!(("" + ("NaN".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 387: NaN should be > 1.23",}, b0, false, false, "Cq", null); +runtime.ext_scratch3_looks._say("fail 387: NaN should be > 1.23", target); } if (!(("" + ("NaN".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 388: NaN should be < .23",}, b0, false, false, "Cs", null); +runtime.ext_scratch3_looks._say("fail 388: NaN should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 389: NaN should be = .23",}, b0, false, false, "Cu", null); +runtime.ext_scratch3_looks._say("fail 389: NaN should be = .23", target); } if (!(("" + ("NaN".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 390: NaN should be > .23",}, b0, false, false, "Cw", null); +runtime.ext_scratch3_looks._say("fail 390: NaN should be > .23", target); } if (!(("" + ("NaN".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 391: NaN should be < 0.123",}, b0, false, false, "Cy", null); +runtime.ext_scratch3_looks._say("fail 391: NaN should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 392: NaN should be = 0.123",}, b0, false, false, "CA", null); +runtime.ext_scratch3_looks._say("fail 392: NaN should be = 0.123", target); } if (!(("" + ("NaN".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 393: NaN should be > 0.123",}, b0, false, false, "CC", null); +runtime.ext_scratch3_looks._say("fail 393: NaN should be > 0.123", target); } if (!(("" + ("NaN".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 394: NaN should be < -0",}, b0, false, false, "CE", null); +runtime.ext_scratch3_looks._say("fail 394: NaN should be < -0", target); } if (!(("" + ("NaN".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 395: NaN should be = -0",}, b0, false, false, "CG", null); +runtime.ext_scratch3_looks._say("fail 395: NaN should be = -0", target); } if (!(("" + ("NaN".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 396: NaN should be > -0",}, b0, false, false, "CI", null); +runtime.ext_scratch3_looks._say("fail 396: NaN should be > -0", target); } if (!(("" + ("NaN".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 397: NaN should be < -1",}, b0, false, false, "CK", null); +runtime.ext_scratch3_looks._say("fail 397: NaN should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 398: NaN should be = -1",}, b0, false, false, "CM", null); +runtime.ext_scratch3_looks._say("fail 398: NaN should be = -1", target); } if (!(("" + ("NaN".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 399: NaN should be > -1",}, b0, false, false, "CO", null); +runtime.ext_scratch3_looks._say("fail 399: NaN should be > -1", target); } if (!(("" + ("NaN".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 400: NaN should be < true",}, b0, false, false, "CQ", null); +runtime.ext_scratch3_looks._say("fail 400: NaN should be < true", target); } if (!(("" + ("NaN".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 401: NaN should be = true",}, b0, false, false, "CS", null); +runtime.ext_scratch3_looks._say("fail 401: NaN should be = true", target); } if (!(("" + ("NaN".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 402: NaN should be > true",}, b0, false, false, "CU", null); +runtime.ext_scratch3_looks._say("fail 402: NaN should be > true", target); } if (!(("" + ("NaN".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 403: NaN should be < false",}, b0, false, false, "CW", null); +runtime.ext_scratch3_looks._say("fail 403: NaN should be < false", target); } if (!(("" + ("NaN".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 404: NaN should be = false",}, b0, false, false, "CY", null); +runtime.ext_scratch3_looks._say("fail 404: NaN should be = false", target); } if (!(("" + ("NaN".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 405: NaN should be > false",}, b0, false, false, "C0", null); +runtime.ext_scratch3_looks._say("fail 405: NaN should be > false", target); } if (!(("" + ("NaN".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 406: NaN should be < NaN",}, b0, false, false, "C2", null); +runtime.ext_scratch3_looks._say("fail 406: NaN should be < NaN", target); } if (!(("" + ("NaN".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 407: NaN should be = NaN",}, b0, false, false, "C4", null); +runtime.ext_scratch3_looks._say("fail 407: NaN should be = NaN", target); } if (!(("" + ("NaN".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 408: NaN should be > NaN",}, b0, false, false, "C6", null); +runtime.ext_scratch3_looks._say("fail 408: NaN should be > NaN", target); } if (!(("" + ("NaN".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 409: NaN should be < Infinity",}, b0, false, false, "C8", null); +runtime.ext_scratch3_looks._say("fail 409: NaN should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 410: NaN should be = Infinity",}, b0, false, false, "C!", null); +runtime.ext_scratch3_looks._say("fail 410: NaN should be = Infinity", target); } if (!(("" + ("NaN".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 411: NaN should be > Infinity",}, b0, false, false, "C%", null); +runtime.ext_scratch3_looks._say("fail 411: NaN should be > Infinity", target); } if (!(("" + ("NaN".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 412: NaN should be < banana",}, b0, false, false, "C)", null); +runtime.ext_scratch3_looks._say("fail 412: NaN should be < banana", target); } if (!(("" + ("NaN".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 413: NaN should be = banana",}, b0, false, false, "C+", null); +runtime.ext_scratch3_looks._say("fail 413: NaN should be = banana", target); } if (!(("" + ("NaN".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 414: NaN should be > banana",}, b0, false, false, "C-", null); +runtime.ext_scratch3_looks._say("fail 414: NaN should be > banana", target); } if (!(("" + ("NaN".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 415: NaN should be < 🎉",}, b0, false, false, "C/", null); +runtime.ext_scratch3_looks._say("fail 415: NaN should be < 🎉", target); } if (!(("" + ("NaN".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 416: NaN should be = 🎉",}, b0, false, false, "C;", null); +runtime.ext_scratch3_looks._say("fail 416: NaN should be = 🎉", target); } if (!(("" + ("NaN".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 417: NaN should be > 🎉",}, b0, false, false, "C?", null); +runtime.ext_scratch3_looks._say("fail 417: NaN should be > 🎉", target); } if (!(("" + ("NaN".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 418: NaN should be < ",}, b0, false, false, "C[", null); +runtime.ext_scratch3_looks._say("fail 418: NaN should be < ", target); } if (!(("" + ("NaN".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 419: NaN should be = ",}, b0, false, false, "C^", null); +runtime.ext_scratch3_looks._say("fail 419: NaN should be = ", target); } if (!(("" + ("NaN".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 420: NaN should be > ",}, b0, false, false, "C`", null); +runtime.ext_scratch3_looks._say("fail 420: NaN should be > ", target); } if (!(("" + (Infinity < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 421: Infinity should be < 0",}, b0, false, false, "C|", null); +runtime.ext_scratch3_looks._say("fail 421: Infinity should be < 0", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 422: Infinity should be = 0",}, b0, false, false, "C~", null); +runtime.ext_scratch3_looks._say("fail 422: Infinity should be = 0", target); } if (!(("" + (Infinity > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 423: Infinity should be > 0",}, b0, false, false, "Db", null); +runtime.ext_scratch3_looks._say("fail 423: Infinity should be > 0", target); } if (!(("" + (Infinity < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 424: Infinity should be < 0.0",}, b0, false, false, "Dd", null); +runtime.ext_scratch3_looks._say("fail 424: Infinity should be < 0.0", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 425: Infinity should be = 0.0",}, b0, false, false, "Df", null); +runtime.ext_scratch3_looks._say("fail 425: Infinity should be = 0.0", target); } if (!(("" + (Infinity > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 426: Infinity should be > 0.0",}, b0, false, false, "Dh", null); +runtime.ext_scratch3_looks._say("fail 426: Infinity should be > 0.0", target); } if (!(("" + (Infinity < 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 427: Infinity should be < 1.23",}, b0, false, false, "Dj", null); +runtime.ext_scratch3_looks._say("fail 427: Infinity should be < 1.23", target); } if (!(("" + (Infinity === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 428: Infinity should be = 1.23",}, b0, false, false, "Dl", null); +runtime.ext_scratch3_looks._say("fail 428: Infinity should be = 1.23", target); } if (!(("" + (Infinity > 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 429: Infinity should be > 1.23",}, b0, false, false, "Dn", null); +runtime.ext_scratch3_looks._say("fail 429: Infinity should be > 1.23", target); } if (!(("" + (Infinity < 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 430: Infinity should be < .23",}, b0, false, false, "Dp", null); +runtime.ext_scratch3_looks._say("fail 430: Infinity should be < .23", target); } if (!(("" + (Infinity === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 431: Infinity should be = .23",}, b0, false, false, "Dr", null); +runtime.ext_scratch3_looks._say("fail 431: Infinity should be = .23", target); } if (!(("" + (Infinity > 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 432: Infinity should be > .23",}, b0, false, false, "Dt", null); +runtime.ext_scratch3_looks._say("fail 432: Infinity should be > .23", target); } if (!(("" + (Infinity < 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 433: Infinity should be < 0.123",}, b0, false, false, "Dv", null); +runtime.ext_scratch3_looks._say("fail 433: Infinity should be < 0.123", target); } if (!(("" + (Infinity === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 434: Infinity should be = 0.123",}, b0, false, false, "Dx", null); +runtime.ext_scratch3_looks._say("fail 434: Infinity should be = 0.123", target); } if (!(("" + (Infinity > 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 435: Infinity should be > 0.123",}, b0, false, false, "Dz", null); +runtime.ext_scratch3_looks._say("fail 435: Infinity should be > 0.123", target); } if (!(("" + (Infinity < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 436: Infinity should be < -0",}, b0, false, false, "DB", null); +runtime.ext_scratch3_looks._say("fail 436: Infinity should be < -0", target); } if (!(("" + (Infinity === -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 437: Infinity should be = -0",}, b0, false, false, "DD", null); +runtime.ext_scratch3_looks._say("fail 437: Infinity should be = -0", target); } if (!(("" + (Infinity > -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 438: Infinity should be > -0",}, b0, false, false, "DF", null); +runtime.ext_scratch3_looks._say("fail 438: Infinity should be > -0", target); } if (!(("" + (Infinity < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 439: Infinity should be < -1",}, b0, false, false, "DH", null); +runtime.ext_scratch3_looks._say("fail 439: Infinity should be < -1", target); } if (!(("" + (Infinity === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 440: Infinity should be = -1",}, b0, false, false, "DJ", null); +runtime.ext_scratch3_looks._say("fail 440: Infinity should be = -1", target); } if (!(("" + (Infinity > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 441: Infinity should be > -1",}, b0, false, false, "DL", null); +runtime.ext_scratch3_looks._say("fail 441: Infinity should be > -1", target); } if (!(("" + ("Infinity".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 442: Infinity should be < true",}, b0, false, false, "DN", null); +runtime.ext_scratch3_looks._say("fail 442: Infinity should be < true", target); } if (!(("" + (Infinity === 1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 443: Infinity should be = true",}, b0, false, false, "DP", null); +runtime.ext_scratch3_looks._say("fail 443: Infinity should be = true", target); } if (!(("" + ("Infinity".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 444: Infinity should be > true",}, b0, false, false, "DR", null); +runtime.ext_scratch3_looks._say("fail 444: Infinity should be > true", target); } if (!(("" + ("Infinity".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 445: Infinity should be < false",}, b0, false, false, "DT", null); +runtime.ext_scratch3_looks._say("fail 445: Infinity should be < false", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 446: Infinity should be = false",}, b0, false, false, "DV", null); +runtime.ext_scratch3_looks._say("fail 446: Infinity should be = false", target); } if (!(("" + ("Infinity".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 447: Infinity should be > false",}, b0, false, false, "DX", null); +runtime.ext_scratch3_looks._say("fail 447: Infinity should be > false", target); } if (!(("" + ("Infinity".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 448: Infinity should be < NaN",}, b0, false, false, "DZ", null); +runtime.ext_scratch3_looks._say("fail 448: Infinity should be < NaN", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 449: Infinity should be = NaN",}, b0, false, false, "D1", null); +runtime.ext_scratch3_looks._say("fail 449: Infinity should be = NaN", target); } if (!(("" + ("Infinity".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 450: Infinity should be > NaN",}, b0, false, false, "D3", null); +runtime.ext_scratch3_looks._say("fail 450: Infinity should be > NaN", target); } if (!(("" + (Infinity < Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 451: Infinity should be < Infinity",}, b0, false, false, "D5", null); +runtime.ext_scratch3_looks._say("fail 451: Infinity should be < Infinity", target); } if (!(("" + (Infinity === Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 452: Infinity should be = Infinity",}, b0, false, false, "D7", null); +runtime.ext_scratch3_looks._say("fail 452: Infinity should be = Infinity", target); } if (!(("" + (Infinity > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 453: Infinity should be > Infinity",}, b0, false, false, "D9", null); +runtime.ext_scratch3_looks._say("fail 453: Infinity should be > Infinity", target); } if (!(("" + ("Infinity".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 454: Infinity should be < banana",}, b0, false, false, "D#", null); +runtime.ext_scratch3_looks._say("fail 454: Infinity should be < banana", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 455: Infinity should be = banana",}, b0, false, false, "D(", null); +runtime.ext_scratch3_looks._say("fail 455: Infinity should be = banana", target); } if (!(("" + ("Infinity".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 456: Infinity should be > banana",}, b0, false, false, "D*", null); +runtime.ext_scratch3_looks._say("fail 456: Infinity should be > banana", target); } if (!(("" + ("Infinity".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 457: Infinity should be < 🎉",}, b0, false, false, "D,", null); +runtime.ext_scratch3_looks._say("fail 457: Infinity should be < 🎉", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 458: Infinity should be = 🎉",}, b0, false, false, "D.", null); +runtime.ext_scratch3_looks._say("fail 458: Infinity should be = 🎉", target); } if (!(("" + ("Infinity".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 459: Infinity should be > 🎉",}, b0, false, false, "D:", null); +runtime.ext_scratch3_looks._say("fail 459: Infinity should be > 🎉", target); } if (!(("" + ("Infinity".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 460: Infinity should be < ",}, b0, false, false, "D=", null); +runtime.ext_scratch3_looks._say("fail 460: Infinity should be < ", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 461: Infinity should be = ",}, b0, false, false, "D@", null); +runtime.ext_scratch3_looks._say("fail 461: Infinity should be = ", target); } if (!(("" + ("Infinity".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 462: Infinity should be > ",}, b0, false, false, "D]", null); +runtime.ext_scratch3_looks._say("fail 462: Infinity should be > ", target); } if (!(("" + ("banana".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 463: banana should be < 0",}, b0, false, false, "D_", null); +runtime.ext_scratch3_looks._say("fail 463: banana should be < 0", target); } if (!(("" + ("banana".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 464: banana should be = 0",}, b0, false, false, "D{", null); +runtime.ext_scratch3_looks._say("fail 464: banana should be = 0", target); } if (!(("" + ("banana".toLowerCase() > "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 465: banana should be > 0",}, b0, false, false, "D}", null); +runtime.ext_scratch3_looks._say("fail 465: banana should be > 0", target); } if (!(("" + ("banana".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 466: banana should be < 0.0",}, b0, false, false, "Ea", null); +runtime.ext_scratch3_looks._say("fail 466: banana should be < 0.0", target); } if (!(("" + ("banana".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 467: banana should be = 0.0",}, b0, false, false, "Ec", null); +runtime.ext_scratch3_looks._say("fail 467: banana should be = 0.0", target); } if (!(("" + ("banana".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 468: banana should be > 0.0",}, b0, false, false, "Ee", null); +runtime.ext_scratch3_looks._say("fail 468: banana should be > 0.0", target); } if (!(("" + ("banana".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 469: banana should be < 1.23",}, b0, false, false, "Eg", null); +runtime.ext_scratch3_looks._say("fail 469: banana should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 470: banana should be = 1.23",}, b0, false, false, "Ei", null); +runtime.ext_scratch3_looks._say("fail 470: banana should be = 1.23", target); } if (!(("" + ("banana".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 471: banana should be > 1.23",}, b0, false, false, "Ek", null); +runtime.ext_scratch3_looks._say("fail 471: banana should be > 1.23", target); } if (!(("" + ("banana".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 472: banana should be < .23",}, b0, false, false, "Em", null); +runtime.ext_scratch3_looks._say("fail 472: banana should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 473: banana should be = .23",}, b0, false, false, "Eo", null); +runtime.ext_scratch3_looks._say("fail 473: banana should be = .23", target); } if (!(("" + ("banana".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 474: banana should be > .23",}, b0, false, false, "Eq", null); +runtime.ext_scratch3_looks._say("fail 474: banana should be > .23", target); } if (!(("" + ("banana".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 475: banana should be < 0.123",}, b0, false, false, "Es", null); +runtime.ext_scratch3_looks._say("fail 475: banana should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 476: banana should be = 0.123",}, b0, false, false, "Eu", null); +runtime.ext_scratch3_looks._say("fail 476: banana should be = 0.123", target); } if (!(("" + ("banana".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 477: banana should be > 0.123",}, b0, false, false, "Ew", null); +runtime.ext_scratch3_looks._say("fail 477: banana should be > 0.123", target); } if (!(("" + ("banana".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 478: banana should be < -0",}, b0, false, false, "Ey", null); +runtime.ext_scratch3_looks._say("fail 478: banana should be < -0", target); } if (!(("" + ("banana".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 479: banana should be = -0",}, b0, false, false, "EA", null); +runtime.ext_scratch3_looks._say("fail 479: banana should be = -0", target); } if (!(("" + ("banana".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 480: banana should be > -0",}, b0, false, false, "EC", null); +runtime.ext_scratch3_looks._say("fail 480: banana should be > -0", target); } if (!(("" + ("banana".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 481: banana should be < -1",}, b0, false, false, "EE", null); +runtime.ext_scratch3_looks._say("fail 481: banana should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 482: banana should be = -1",}, b0, false, false, "EG", null); +runtime.ext_scratch3_looks._say("fail 482: banana should be = -1", target); } if (!(("" + ("banana".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 483: banana should be > -1",}, b0, false, false, "EI", null); +runtime.ext_scratch3_looks._say("fail 483: banana should be > -1", target); } if (!(("" + ("banana".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 484: banana should be < true",}, b0, false, false, "EK", null); +runtime.ext_scratch3_looks._say("fail 484: banana should be < true", target); } if (!(("" + ("banana".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 485: banana should be = true",}, b0, false, false, "EM", null); +runtime.ext_scratch3_looks._say("fail 485: banana should be = true", target); } if (!(("" + ("banana".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 486: banana should be > true",}, b0, false, false, "EO", null); +runtime.ext_scratch3_looks._say("fail 486: banana should be > true", target); } if (!(("" + ("banana".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 487: banana should be < false",}, b0, false, false, "EQ", null); +runtime.ext_scratch3_looks._say("fail 487: banana should be < false", target); } if (!(("" + ("banana".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 488: banana should be = false",}, b0, false, false, "ES", null); +runtime.ext_scratch3_looks._say("fail 488: banana should be = false", target); } if (!(("" + ("banana".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 489: banana should be > false",}, b0, false, false, "EU", null); +runtime.ext_scratch3_looks._say("fail 489: banana should be > false", target); } if (!(("" + ("banana".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 490: banana should be < NaN",}, b0, false, false, "EW", null); +runtime.ext_scratch3_looks._say("fail 490: banana should be < NaN", target); } if (!(("" + ("banana".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 491: banana should be = NaN",}, b0, false, false, "EY", null); +runtime.ext_scratch3_looks._say("fail 491: banana should be = NaN", target); } if (!(("" + ("banana".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 492: banana should be > NaN",}, b0, false, false, "E0", null); +runtime.ext_scratch3_looks._say("fail 492: banana should be > NaN", target); } if (!(("" + ("banana".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 493: banana should be < Infinity",}, b0, false, false, "E2", null); +runtime.ext_scratch3_looks._say("fail 493: banana should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 494: banana should be = Infinity",}, b0, false, false, "E4", null); +runtime.ext_scratch3_looks._say("fail 494: banana should be = Infinity", target); } if (!(("" + ("banana".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 495: banana should be > Infinity",}, b0, false, false, "E6", null); +runtime.ext_scratch3_looks._say("fail 495: banana should be > Infinity", target); } if (!(("" + ("banana".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 496: banana should be < banana",}, b0, false, false, "E8", null); +runtime.ext_scratch3_looks._say("fail 496: banana should be < banana", target); } if (!(("" + ("banana".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 497: banana should be = banana",}, b0, false, false, "E!", null); +runtime.ext_scratch3_looks._say("fail 497: banana should be = banana", target); } if (!(("" + ("banana".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 498: banana should be > banana",}, b0, false, false, "E%", null); +runtime.ext_scratch3_looks._say("fail 498: banana should be > banana", target); } if (!(("" + ("banana".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 499: banana should be < 🎉",}, b0, false, false, "E)", null); +runtime.ext_scratch3_looks._say("fail 499: banana should be < 🎉", target); } if (!(("" + ("banana".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 500: banana should be = 🎉",}, b0, false, false, "E+", null); +runtime.ext_scratch3_looks._say("fail 500: banana should be = 🎉", target); } if (!(("" + ("banana".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 501: banana should be > 🎉",}, b0, false, false, "E-", null); +runtime.ext_scratch3_looks._say("fail 501: banana should be > 🎉", target); } if (!(("" + ("banana".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 502: banana should be < ",}, b0, false, false, "E/", null); +runtime.ext_scratch3_looks._say("fail 502: banana should be < ", target); } if (!(("" + ("banana".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 503: banana should be = ",}, b0, false, false, "E;", null); +runtime.ext_scratch3_looks._say("fail 503: banana should be = ", target); } if (!(("" + ("banana".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 504: banana should be > ",}, b0, false, false, "E?", null); +runtime.ext_scratch3_looks._say("fail 504: banana should be > ", target); } if (!(("" + ("🎉".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 505: 🎉 should be < 0",}, b0, false, false, "E[", null); +runtime.ext_scratch3_looks._say("fail 505: 🎉 should be < 0", target); } if (!(("" + ("🎉".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 506: 🎉 should be = 0",}, b0, false, false, "E^", null); +runtime.ext_scratch3_looks._say("fail 506: 🎉 should be = 0", target); } if (!(("" + ("🎉".toLowerCase() > "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 507: 🎉 should be > 0",}, b0, false, false, "E`", null); +runtime.ext_scratch3_looks._say("fail 507: 🎉 should be > 0", target); } if (!(("" + ("🎉".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 508: 🎉 should be < 0.0",}, b0, false, false, "E|", null); +runtime.ext_scratch3_looks._say("fail 508: 🎉 should be < 0.0", target); } if (!(("" + ("🎉".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 509: 🎉 should be = 0.0",}, b0, false, false, "E~", null); +runtime.ext_scratch3_looks._say("fail 509: 🎉 should be = 0.0", target); } if (!(("" + ("🎉".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 510: 🎉 should be > 0.0",}, b0, false, false, "Fb", null); +runtime.ext_scratch3_looks._say("fail 510: 🎉 should be > 0.0", target); } if (!(("" + ("🎉".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 511: 🎉 should be < 1.23",}, b0, false, false, "Fd", null); +runtime.ext_scratch3_looks._say("fail 511: 🎉 should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 512: 🎉 should be = 1.23",}, b0, false, false, "Ff", null); +runtime.ext_scratch3_looks._say("fail 512: 🎉 should be = 1.23", target); } if (!(("" + ("🎉".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 513: 🎉 should be > 1.23",}, b0, false, false, "Fh", null); +runtime.ext_scratch3_looks._say("fail 513: 🎉 should be > 1.23", target); } if (!(("" + ("🎉".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 514: 🎉 should be < .23",}, b0, false, false, "Fj", null); +runtime.ext_scratch3_looks._say("fail 514: 🎉 should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 515: 🎉 should be = .23",}, b0, false, false, "Fl", null); +runtime.ext_scratch3_looks._say("fail 515: 🎉 should be = .23", target); } if (!(("" + ("🎉".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 516: 🎉 should be > .23",}, b0, false, false, "Fn", null); +runtime.ext_scratch3_looks._say("fail 516: 🎉 should be > .23", target); } if (!(("" + ("🎉".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 517: 🎉 should be < 0.123",}, b0, false, false, "Fp", null); +runtime.ext_scratch3_looks._say("fail 517: 🎉 should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 518: 🎉 should be = 0.123",}, b0, false, false, "Fr", null); +runtime.ext_scratch3_looks._say("fail 518: 🎉 should be = 0.123", target); } if (!(("" + ("🎉".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 519: 🎉 should be > 0.123",}, b0, false, false, "Ft", null); +runtime.ext_scratch3_looks._say("fail 519: 🎉 should be > 0.123", target); } if (!(("" + ("🎉".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 520: 🎉 should be < -0",}, b0, false, false, "Fv", null); +runtime.ext_scratch3_looks._say("fail 520: 🎉 should be < -0", target); } if (!(("" + ("🎉".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 521: 🎉 should be = -0",}, b0, false, false, "Fx", null); +runtime.ext_scratch3_looks._say("fail 521: 🎉 should be = -0", target); } if (!(("" + ("🎉".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 522: 🎉 should be > -0",}, b0, false, false, "Fz", null); +runtime.ext_scratch3_looks._say("fail 522: 🎉 should be > -0", target); } if (!(("" + ("🎉".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 523: 🎉 should be < -1",}, b0, false, false, "FB", null); +runtime.ext_scratch3_looks._say("fail 523: 🎉 should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 524: 🎉 should be = -1",}, b0, false, false, "FD", null); +runtime.ext_scratch3_looks._say("fail 524: 🎉 should be = -1", target); } if (!(("" + ("🎉".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 525: 🎉 should be > -1",}, b0, false, false, "FF", null); +runtime.ext_scratch3_looks._say("fail 525: 🎉 should be > -1", target); } if (!(("" + ("🎉".toLowerCase() < "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 526: 🎉 should be < true",}, b0, false, false, "FH", null); +runtime.ext_scratch3_looks._say("fail 526: 🎉 should be < true", target); } if (!(("" + ("🎉".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 527: 🎉 should be = true",}, b0, false, false, "FJ", null); +runtime.ext_scratch3_looks._say("fail 527: 🎉 should be = true", target); } if (!(("" + ("🎉".toLowerCase() > "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 528: 🎉 should be > true",}, b0, false, false, "FL", null); +runtime.ext_scratch3_looks._say("fail 528: 🎉 should be > true", target); } if (!(("" + ("🎉".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 529: 🎉 should be < false",}, b0, false, false, "FN", null); +runtime.ext_scratch3_looks._say("fail 529: 🎉 should be < false", target); } if (!(("" + ("🎉".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 530: 🎉 should be = false",}, b0, false, false, "FP", null); +runtime.ext_scratch3_looks._say("fail 530: 🎉 should be = false", target); } if (!(("" + ("🎉".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 531: 🎉 should be > false",}, b0, false, false, "FR", null); +runtime.ext_scratch3_looks._say("fail 531: 🎉 should be > false", target); } if (!(("" + ("🎉".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 532: 🎉 should be < NaN",}, b0, false, false, "FT", null); +runtime.ext_scratch3_looks._say("fail 532: 🎉 should be < NaN", target); } if (!(("" + ("🎉".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 533: 🎉 should be = NaN",}, b0, false, false, "FV", null); +runtime.ext_scratch3_looks._say("fail 533: 🎉 should be = NaN", target); } if (!(("" + ("🎉".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 534: 🎉 should be > NaN",}, b0, false, false, "FX", null); +runtime.ext_scratch3_looks._say("fail 534: 🎉 should be > NaN", target); } if (!(("" + ("🎉".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 535: 🎉 should be < Infinity",}, b0, false, false, "FZ", null); +runtime.ext_scratch3_looks._say("fail 535: 🎉 should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 536: 🎉 should be = Infinity",}, b0, false, false, "F1", null); +runtime.ext_scratch3_looks._say("fail 536: 🎉 should be = Infinity", target); } if (!(("" + ("🎉".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 537: 🎉 should be > Infinity",}, b0, false, false, "F3", null); +runtime.ext_scratch3_looks._say("fail 537: 🎉 should be > Infinity", target); } if (!(("" + ("🎉".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 538: 🎉 should be < banana",}, b0, false, false, "F5", null); +runtime.ext_scratch3_looks._say("fail 538: 🎉 should be < banana", target); } if (!(("" + ("🎉".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 539: 🎉 should be = banana",}, b0, false, false, "F7", null); +runtime.ext_scratch3_looks._say("fail 539: 🎉 should be = banana", target); } if (!(("" + ("🎉".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 540: 🎉 should be > banana",}, b0, false, false, "F9", null); +runtime.ext_scratch3_looks._say("fail 540: 🎉 should be > banana", target); } if (!(("" + ("🎉".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 541: 🎉 should be < 🎉",}, b0, false, false, "F#", null); +runtime.ext_scratch3_looks._say("fail 541: 🎉 should be < 🎉", target); } if (!(("" + ("🎉".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 542: 🎉 should be = 🎉",}, b0, false, false, "F(", null); +runtime.ext_scratch3_looks._say("fail 542: 🎉 should be = 🎉", target); } if (!(("" + ("🎉".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 543: 🎉 should be > 🎉",}, b0, false, false, "F*", null); +runtime.ext_scratch3_looks._say("fail 543: 🎉 should be > 🎉", target); } if (!(("" + ("🎉".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 544: 🎉 should be < ",}, b0, false, false, "F,", null); +runtime.ext_scratch3_looks._say("fail 544: 🎉 should be < ", target); } if (!(("" + ("🎉".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 545: 🎉 should be = ",}, b0, false, false, "F.", null); +runtime.ext_scratch3_looks._say("fail 545: 🎉 should be = ", target); } if (!(("" + ("🎉".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 546: 🎉 should be > ",}, b0, false, false, "F:", null); +runtime.ext_scratch3_looks._say("fail 546: 🎉 should be > ", target); } if (!(("" + ("".toLowerCase() < "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 547: should be < 0",}, b0, false, false, "F=", null); +runtime.ext_scratch3_looks._say("fail 547: should be < 0", target); } if (!(("" + ("".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 548: should be = 0",}, b0, false, false, "F@", null); +runtime.ext_scratch3_looks._say("fail 548: should be = 0", target); } if (!(("" + ("".toLowerCase() > "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 549: should be > 0",}, b0, false, false, "F]", null); +runtime.ext_scratch3_looks._say("fail 549: should be > 0", target); } if (!(("" + ("".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 550: should be < 0.0",}, b0, false, false, "F_", null); +runtime.ext_scratch3_looks._say("fail 550: should be < 0.0", target); } if (!(("" + ("".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 551: should be = 0.0",}, b0, false, false, "F{", null); +runtime.ext_scratch3_looks._say("fail 551: should be = 0.0", target); } if (!(("" + ("".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 552: should be > 0.0",}, b0, false, false, "F}", null); +runtime.ext_scratch3_looks._say("fail 552: should be > 0.0", target); } if (!(("" + ("".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 553: should be < 1.23",}, b0, false, false, "Ga", null); +runtime.ext_scratch3_looks._say("fail 553: should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 554: should be = 1.23",}, b0, false, false, "Gc", null); +runtime.ext_scratch3_looks._say("fail 554: should be = 1.23", target); } if (!(("" + ("".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 555: should be > 1.23",}, b0, false, false, "Ge", null); +runtime.ext_scratch3_looks._say("fail 555: should be > 1.23", target); } if (!(("" + ("".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 556: should be < .23",}, b0, false, false, "Gg", null); +runtime.ext_scratch3_looks._say("fail 556: should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 557: should be = .23",}, b0, false, false, "Gi", null); +runtime.ext_scratch3_looks._say("fail 557: should be = .23", target); } if (!(("" + ("".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 558: should be > .23",}, b0, false, false, "Gk", null); +runtime.ext_scratch3_looks._say("fail 558: should be > .23", target); } if (!(("" + ("".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 559: should be < 0.123",}, b0, false, false, "Gm", null); +runtime.ext_scratch3_looks._say("fail 559: should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 560: should be = 0.123",}, b0, false, false, "Go", null); +runtime.ext_scratch3_looks._say("fail 560: should be = 0.123", target); } if (!(("" + ("".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 561: should be > 0.123",}, b0, false, false, "Gq", null); +runtime.ext_scratch3_looks._say("fail 561: should be > 0.123", target); } if (!(("" + ("".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 562: should be < -0",}, b0, false, false, "Gs", null); +runtime.ext_scratch3_looks._say("fail 562: should be < -0", target); } if (!(("" + ("".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 563: should be = -0",}, b0, false, false, "Gu", null); +runtime.ext_scratch3_looks._say("fail 563: should be = -0", target); } if (!(("" + ("".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 564: should be > -0",}, b0, false, false, "Gw", null); +runtime.ext_scratch3_looks._say("fail 564: should be > -0", target); } if (!(("" + ("".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 565: should be < -1",}, b0, false, false, "Gy", null); +runtime.ext_scratch3_looks._say("fail 565: should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 566: should be = -1",}, b0, false, false, "GA", null); +runtime.ext_scratch3_looks._say("fail 566: should be = -1", target); } if (!(("" + ("".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 567: should be > -1",}, b0, false, false, "GC", null); +runtime.ext_scratch3_looks._say("fail 567: should be > -1", target); } if (!(("" + ("".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 568: should be < true",}, b0, false, false, "GE", null); +runtime.ext_scratch3_looks._say("fail 568: should be < true", target); } if (!(("" + ("".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 569: should be = true",}, b0, false, false, "GG", null); +runtime.ext_scratch3_looks._say("fail 569: should be = true", target); } if (!(("" + ("".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 570: should be > true",}, b0, false, false, "GI", null); +runtime.ext_scratch3_looks._say("fail 570: should be > true", target); } if (!(("" + ("".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 571: should be < false",}, b0, false, false, "GK", null); +runtime.ext_scratch3_looks._say("fail 571: should be < false", target); } if (!(("" + ("".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 572: should be = false",}, b0, false, false, "GM", null); +runtime.ext_scratch3_looks._say("fail 572: should be = false", target); } if (!(("" + ("".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 573: should be > false",}, b0, false, false, "GO", null); +runtime.ext_scratch3_looks._say("fail 573: should be > false", target); } if (!(("" + ("".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 574: should be < NaN",}, b0, false, false, "GQ", null); +runtime.ext_scratch3_looks._say("fail 574: should be < NaN", target); } if (!(("" + ("".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 575: should be = NaN",}, b0, false, false, "GS", null); +runtime.ext_scratch3_looks._say("fail 575: should be = NaN", target); } if (!(("" + ("".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 576: should be > NaN",}, b0, false, false, "GU", null); +runtime.ext_scratch3_looks._say("fail 576: should be > NaN", target); } if (!(("" + ("".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 577: should be < Infinity",}, b0, false, false, "GW", null); +runtime.ext_scratch3_looks._say("fail 577: should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 578: should be = Infinity",}, b0, false, false, "GY", null); +runtime.ext_scratch3_looks._say("fail 578: should be = Infinity", target); } if (!(("" + ("".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 579: should be > Infinity",}, b0, false, false, "G0", null); +runtime.ext_scratch3_looks._say("fail 579: should be > Infinity", target); } if (!(("" + ("".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 580: should be < banana",}, b0, false, false, "G2", null); +runtime.ext_scratch3_looks._say("fail 580: should be < banana", target); } if (!(("" + ("".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 581: should be = banana",}, b0, false, false, "G4", null); +runtime.ext_scratch3_looks._say("fail 581: should be = banana", target); } if (!(("" + ("".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 582: should be > banana",}, b0, false, false, "G6", null); +runtime.ext_scratch3_looks._say("fail 582: should be > banana", target); } if (!(("" + ("".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 583: should be < 🎉",}, b0, false, false, "G8", null); +runtime.ext_scratch3_looks._say("fail 583: should be < 🎉", target); } if (!(("" + ("".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 584: should be = 🎉",}, b0, false, false, "G!", null); +runtime.ext_scratch3_looks._say("fail 584: should be = 🎉", target); } if (!(("" + ("".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 585: should be > 🎉",}, b0, false, false, "G%", null); +runtime.ext_scratch3_looks._say("fail 585: should be > 🎉", target); } if (!(("" + ("".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 586: should be < ",}, b0, false, false, "G)", null); +runtime.ext_scratch3_looks._say("fail 586: should be < ", target); } if (!(("" + ("".toLowerCase() === "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 587: should be = ",}, b0, false, false, "G+", null); +runtime.ext_scratch3_looks._say("fail 587: should be = ", target); } if (!(("" + ("".toLowerCase() > "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 588: should be > ",}, b0, false, false, "G.", null); +runtime.ext_scratch3_looks._say("fail 588: should be > ", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "G-", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot index 946a0afb6f6..5576caee39a 100644 --- a/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-comparison-matrix-runtime.sb3.tw-snapshot @@ -3,11 +3,10 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "ae", null); -yield* thread.procedures["Wrun test"](); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "aZ", null); +runtime.ext_scratch3_looks._say("plan 0", target); +thread.procedures["Wrun test"](); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -18,28 +17,26 @@ const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; const b2 = stage.variables["n^wm8jw#b24sggt.S^tD"]; const b3 = stage.variables["_]6^lq+-%H0{ov`tKt7$"]; const b4 = stage.variables["3lyKRepBc$tx)EWlpr!y"]; -const b5 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_run_test () { +return function funXYZ_run_test () { thread.procedures["Wsetup values"](); b0.value = 0; b1.value = 0; for (var a0 = b2.value.length; a0 > 0; a0--) { -b1.value = (toNotNaN(+b1.value) + 1); +b1.value = (b1.value + 1); b3.value = 0; for (var a1 = b2.value.length; a1 > 0; a1--) { -b3.value = (toNotNaN(+b3.value) + 1); -b0.value = (toNotNaN(+b0.value) + 1); -if (!compareEqual(compareGreaterThan(listGet(b2.value, b1.value), (b2.value[(b3.value | 0) - 1] ?? "")), (b4.value[(b0.value | 0) - 1] ?? ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be > " + ("" + (b2.value[(b3.value | 0) - 1] ?? ""))))),}, b5, true, false, "]", null); +b3.value = (b3.value + 1); +b0.value = (b0.value + 1); +if (!compareEqual(compareGreaterThan((b2.value[b1.value - 1] ?? ""), (b2.value[b3.value - 1] ?? "")), (b4.value[b0.value - 1] ?? ""))) { +runtime.ext_scratch3_looks._say(("fail " + (("" + (b2.value[b1.value - 1] ?? "")) + (" should be > " + ("" + (b2.value[b3.value - 1] ?? ""))))), target); } -b0.value = (toNotNaN(+b0.value) + 1); -if (!compareEqual(compareEqual(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be = " + ("" + listGet(b2.value, b3.value))))),}, b5, true, false, "|", null); +b0.value = (b0.value + 1); +if (!compareEqual(compareEqual((b2.value[b1.value - 1] ?? ""), (b2.value[b3.value - 1] ?? "")), (b4.value[b0.value - 1] ?? ""))) { +runtime.ext_scratch3_looks._say(("fail " + (("" + (b2.value[b1.value - 1] ?? "")) + (" should be = " + ("" + (b2.value[b3.value - 1] ?? ""))))), target); } -b0.value = (toNotNaN(+b0.value) + 1); -if (!compareEqual(compareLessThan(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be < " + ("" + listGet(b2.value, b3.value))))),}, b5, true, true, "ab", null); -if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} +b0.value = (b0.value + 1); +if (!compareEqual(compareLessThan((b2.value[b1.value - 1] ?? ""), (b2.value[b3.value - 1] ?? "")), (b4.value[b0.value - 1] ?? ""))) { +runtime.ext_scratch3_looks._say(("fail " + (("" + (b2.value[b1.value - 1] ?? "")) + (" should be < " + ("" + (b2.value[b3.value - 1] ?? ""))))), target); } } } diff --git a/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot index 3cc61e9b75d..66011d00da6 100644 --- a/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-compatibility-layer-type-barrier.sb3.tw-snapshot @@ -3,17 +3,16 @@ // 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 = runtime.getOpcodeFunction("looks_sayforsecs"); +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = runtime.getOpcodeFunction("looks_sayforsecs"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); -b1.value = (0 + 0); -yield* executeInCompatibilityLayer({"MESSAGE":"Hello!","SECS":0.1,}, b2, false, false, "d", null); -if (((toNotNaN(+b1.value) + 2) === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "i", null); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = (0 + 0); +yield* executeInCompatibilityLayer({"MESSAGE":"Hello!","SECS":0.1,}, b1, false, false, "d", null); +if (((toNotNaN(+b0.value) + 2) === 2)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "m", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-coordinate-precision.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-coordinate-precision.sb3.tw-snapshot index ecaec5b0809..446c232e2d2 100644 --- a/test/snapshot/__snapshots__/tw-coordinate-precision.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-coordinate-precision.sb3.tw-snapshot @@ -3,34 +3,33 @@ // 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 = runtime.getSpriteTargetByName("Sprite1"); +const b0 = runtime.getSpriteTargetByName("Sprite1"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 6",}, b0, false, false, "`f)8`e7_V%]cmRy7eZ?*", null); +runtime.ext_scratch3_looks._say("plan 6", target); target.setXY(1e-9, target.y); if ((limitPrecision(target.x) === 1e-9)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass much above x does not round",}, b0, false, false, "wnAyae772?^VZ]bq?#*p", null); +runtime.ext_scratch3_looks._say("pass much above x does not round", target); } -if (((b1 ? b1.x : 0) === 1e-9)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass initial 'of' test",}, b0, false, false, "${qf}t3_Wf_/sqC#i0WN", null); +if (((b0 ? b0.x : 0) === 1e-9)) { +runtime.ext_scratch3_looks._say("pass initial 'of' test", target); } target.setXY(target.x + 0, target.y); runtime.ext_scratch3_motion._moveSteps(0, target); target.setXY(target.x + -9e-10, target.y); -if (((b1 ? b1.x : 0) === 1.0000000000000007e-10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 'of' never rounds - positive x",}, b0, false, false, "zt/Fd,i768/rohNq-OU/", null); +if (((b0 ? b0.x : 0) === 1.0000000000000007e-10)) { +runtime.ext_scratch3_looks._say("pass 'of' never rounds - positive x", target); } if ((limitPrecision(target.x) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass x slightly above 0 rounds",}, b0, false, false, "p5a6(?e#B|B(d.fe;b6F", null); +runtime.ext_scratch3_looks._say("pass x slightly above 0 rounds", target); } target.setXY(target.x + -9e-10, target.y); target.setXY(target.x, target.y + 0); -if (((b1 ? b1.x : 0) === -7.999999999999999e-10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 'of' never rounds and change x - negative x",}, b0, false, false, "![=|9E8]xp_9QR]fu}4M", null); +if (((b0 ? b0.x : 0) === -7.999999999999999e-10)) { +runtime.ext_scratch3_looks._say("pass 'of' never rounds and change x - negative x", target); } if ((limitPrecision(target.x) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass x slightly below 0 rounds",}, b0, false, false, "4o-vB]D}HJ1/*qW~k3Cd", null); +runtime.ext_scratch3_looks._say("pass x slightly below 0 rounds", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "8We]d__[]7X;@+e*x~^@", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-counter.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-counter.sb3.tw-snapshot index abbfa97a51e..838b27fe8f0 100644 --- a/test/snapshot/__snapshots__/tw-counter.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-counter.sb3.tw-snapshot @@ -3,34 +3,32 @@ // 2 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { if ((runtime.ext_scratch3_control._counter === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass global",}, b0, false, false, "C", null); +runtime.ext_scratch3_looks._say("pass global", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "B", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // 1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 5",}, b0, false, false, "g", null); +runtime.ext_scratch3_looks._say("plan 5", target); if ((runtime.ext_scratch3_control._counter === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass initial value = 0",}, b0, false, false, "q", null); +runtime.ext_scratch3_looks._say("pass initial value = 0", target); } runtime.ext_scratch3_control._counter++; if ((runtime.ext_scratch3_control._counter === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass incr 1",}, b0, false, false, "s", null); +runtime.ext_scratch3_looks._say("pass incr 1", target); } runtime.ext_scratch3_control._counter++; if ((runtime.ext_scratch3_control._counter === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass incr 2",}, b0, false, false, "u", null); +runtime.ext_scratch3_looks._say("pass incr 2", target); } runtime.ext_scratch3_control._counter = 0; if ((runtime.ext_scratch3_control._counter === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass clear = 0",}, b0, false, false, "w", null); +runtime.ext_scratch3_looks._say("pass clear = 0", target); } for (var a0 = 10; a0 > 0; a0--) { runtime.ext_scratch3_control._counter++; diff --git a/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot index 3429d7b3b4d..d6422034fe0 100644 --- a/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot @@ -3,19 +3,18 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); -b1.value = 0; +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = 0; for (var a0 = toNotNaN(+thread.procedures["Zblock name"]()); a0 >= 0.5; a0--) { -b1.value = (toNotNaN(+b1.value) + 1); +b0.value = (toNotNaN(+b0.value) + 1); yield; } -if ((toNotNaN(+b1.value) === 40)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "n", null); +if ((toNotNaN(+b0.value) === 40)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot index 7676e37b15c..14cf2f1aa3b 100644 --- a/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot @@ -3,17 +3,16 @@ // 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["FpLI$ida6)qR,q~y`1|*"]; +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = stage.variables["FpLI$ida6)qR,q~y`1|*"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); -b1.value = (1 + 2); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = (1 + 2); yield* thread.procedures["Zsomething that yields"](); -if ((("" + listGet(b2.value, b1.value)).toLowerCase() === "the only thing".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "o", null); +if ((("" + listGet(b1.value, b0.value)).toLowerCase() === "the only thing".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot index 5f84b8b41da..754e542daa6 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot @@ -3,21 +3,20 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 4",}, b0, false, false, "i", null); +runtime.ext_scratch3_looks._say("plan 4", target); if (compareGreaterThan(("something".toLowerCase() === "something".toLowerCase()), ("0" + ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "k", null); +runtime.ext_scratch3_looks._say("pass", target); } if (compareLessThan(("something".toLowerCase() === "else".toLowerCase()), ("1" + ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "m", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((+("something".toLowerCase() === "something".toLowerCase())) > (0 + 0))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "n", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((+("something".toLowerCase() === "else".toLowerCase())) < (1 + 0))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "o", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot index 87f027a3c1c..f6f6db0a82b 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot @@ -3,26 +3,25 @@ // 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 = runtime.getOpcodeFunction("motion_pointtowards"); +const b0 = runtime.getOpcodeFunction("motion_pointtowards"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 4",}, b0, false, false, "h", null); +runtime.ext_scratch3_looks._say("plan 4", target); target.setDirection(95); if ((target.direction === 95)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 1",}, b0, false, false, "o", null); +runtime.ext_scratch3_looks._say("pass 1", target); } target.setDirection((1 / 0)); if ((target.direction === 95)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 2",}, b0, false, false, "r", null); +runtime.ext_scratch3_looks._say("pass 2", target); } target.setDirection(toNotNaN((0 / 0))); if ((target.direction === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 3",}, b0, false, false, "u", null); +runtime.ext_scratch3_looks._say("pass 3", target); } -yield* executeInCompatibilityLayer({"TOWARDS":"Sprite2",}, b1, false, false, "g", null); +yield* executeInCompatibilityLayer({"TOWARDS":"Sprite2",}, b0, false, false, "g", null); if ((target.direction === 90)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 4",}, b0, false, false, "y", null); +runtime.ext_scratch3_looks._say("pass 4", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "w", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-random-with-invalid-number-with-period.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-random-with-invalid-number-with-period.sb3.tw-snapshot index 92e17fec5ba..4fcfeee75e0 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-random-with-invalid-number-with-period.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-random-with-invalid-number-with-period.sb3.tw-snapshot @@ -3,30 +3,29 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 6",}, b0, false, false, "j", null); -b1.value = runtime.ext_scratch3_operators._random(("an invalid number" + "."), 1); -if (!(b1.value <= 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "m", null); +runtime.ext_scratch3_looks._say("plan 6", target); +b0.value = runtime.ext_scratch3_operators._random(("an invalid number" + "."), 1); +if (!(b0.value <= 0)) { +runtime.ext_scratch3_looks._say("pass", target); } -if (compareLessThan(b1.value, 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "r", null); +if ((b0.value < 1)) { +runtime.ext_scratch3_looks._say("pass", target); } -if ((("" + b1.value).toLowerCase().indexOf(".".toLowerCase()) !== -1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "s", null); +if ((("" + b0.value).toLowerCase().indexOf(".".toLowerCase()) !== -1)) { +runtime.ext_scratch3_looks._say("pass", target); } -b1.value = runtime.ext_scratch3_operators._random(1, ("an invalid number" + ".")); -if (!(b1.value <= 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "v", null); +b0.value = runtime.ext_scratch3_operators._random(1, ("an invalid number" + ".")); +if (!(b0.value <= 0)) { +runtime.ext_scratch3_looks._say("pass", target); } -if (compareLessThan(b1.value, 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "x", null); +if ((b0.value < 1)) { +runtime.ext_scratch3_looks._say("pass", target); } -if ((("" + b1.value).toLowerCase().indexOf(".".toLowerCase()) !== -1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "A", null); +if ((("" + b0.value).toLowerCase().indexOf(".".toLowerCase()) !== -1)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "y", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot index 4168b881940..5b92a63c221 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot @@ -3,21 +3,20 @@ // 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 = target.variables["gTtSj;o_E;Snkn620KF."]; -const b2 = target.variables["zShM`!CD?d_|Z,]5X}N6"]; +const b0 = target.variables["gTtSj;o_E;Snkn620KF."]; +const b1 = target.variables["zShM`!CD?d_|Z,]5X}N6"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "d", null); -b1.value = 2; -if ((b1.value === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass variable",}, b0, false, false, "k", null); +runtime.ext_scratch3_looks._say("plan 2", target); +b0.value = 2; +if ((b0.value === 2)) { +runtime.ext_scratch3_looks._say("pass variable", target); } -b2.value = []; -b2.value.push(3); -b2._monitorUpToDate = false; -if ((toNotNaN(+(b2.value[1 - 1] ?? "")) === 3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass list",}, b0, false, false, "m", null); +b1.value = []; +b1.value.push(3); +b1._monitorUpToDate = false; +if ((toNotNaN(+(b1.value[1 - 1] ?? "")) === 3)) { +runtime.ext_scratch3_looks._say("pass list", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot index 04776d0d68a..c2537995306 100644 --- a/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot @@ -5,17 +5,16 @@ (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("sound_setvolumeto"); const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { yield* executeInCompatibilityLayer({"VOLUME":0,}, b0, false, false, "d", null); b1.value = 0; -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b2, false, false, "g", null); +runtime.ext_scratch3_looks._say("plan 1", target); yield* thread.procedures["Wno refresh"](); yield* thread.procedures["Wruns below with no refresh"](); if (compareEqual(b1.value, 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b2, false, false, "v", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b2, false, false, "f", null); +runtime.ext_scratch3_looks._say("end", target); runtime.stopAll(); retire(); return; retire(); return; diff --git a/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot index 07442f3cde8..9bb8aee3462 100644 --- a/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot @@ -3,11 +3,10 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "d", null); +runtime.ext_scratch3_looks._say("plan 0", target); thread.procedures["Zfoo %s"](""); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) 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 df951a5196f..f300be90657 100644 --- a/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "Z", null); +runtime.ext_scratch3_looks._say("plan 1", target); thread.procedures["Wrun"](); -yield* thread.procedures["Wvalidate"](); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "aw", null); +thread.procedures["Wvalidate"](); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -32,19 +31,18 @@ const b0 = stage.variables["7AH{dO^X;}C[{[l~g-7m"]; const b1 = stage.variables["gPJ}c-PZz?Y+_L][iMU_"]; const b2 = stage.variables["EF^k=u-t@S)w60;RP?dZ-list-list"]; const b3 = stage.variables["FsKqV/2kid0gw0J+Jj(c"]; -const b4 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_validate () { +return function funXYZ_validate () { b0.value = 1; b1.value = 1; for (var a0 = b2.value.length; a0 > 0; a0--) { -if (!compareEqual((b2.value[(b1.value | 0) - 1] ?? ""), (b3.value[(b1.value | 0) - 1] ?? ""))) { +if (!compareEqual((b2.value[b1.value - 1] ?? ""), (b3.value[b1.value - 1] ?? ""))) { b0.value = 0; -yield* executeInCompatibilityLayer({"MESSAGE":("fail mismatch at index " + ("" + b1.value)),}, b4, true, false, ",", null); +runtime.ext_scratch3_looks._say(("fail mismatch at index " + ("" + b1.value)), target); } -b1.value = (toNotNaN(+b1.value) + 1); +b1.value = (b1.value + 1); } -if ((toNotNaN(+b0.value) === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass sorted",}, b4, true, false, "aE", null); +if ((b0.value === 1)) { +runtime.ext_scratch3_looks._say("pass sorted", target); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/tw-list-any.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-list-any.sb3.tw-snapshot index d6988304d85..e099222961b 100644 --- a/test/snapshot/__snapshots__/tw-list-any.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-list-any.sb3.tw-snapshot @@ -3,36 +3,35 @@ // Sprite2 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["eFlmP1{XC+I1:h0Yln.K"]; +const b0 = stage.variables["eFlmP1{XC+I1:h0Yln.K"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 7",}, b0, false, false, "h", null); -b1.value = []; -listInsert(b1, "any", "a"); -listInsert(b1, "any", "b"); -listInsert(b1, "any", "c"); -if ((b1.value.length === 3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "s", null); +runtime.ext_scratch3_looks._say("plan 7", target); +b0.value = []; +listInsert(b0, "any", "a"); +listInsert(b0, "any", "b"); +listInsert(b0, "any", "c"); +if ((b0.value.length === 3)) { +runtime.ext_scratch3_looks._say("pass", target); } -if (listContains(b1, "a")) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "v", null); +if (listContains(b0, "a")) { +runtime.ext_scratch3_looks._say("pass", target); } -if (listContains(b1, "b")) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "x", null); +if (listContains(b0, "b")) { +runtime.ext_scratch3_looks._say("pass", target); } -if (listContains(b1, "c")) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "z", null); +if (listContains(b0, "c")) { +runtime.ext_scratch3_looks._say("pass", target); } -if (listContains(b1, listGet(b1.value, "any"))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "A", null); +if (listContains(b0, listGet(b0.value, "any"))) { +runtime.ext_scratch3_looks._say("pass", target); } -listDelete(b1, "any"); -if ((b1.value.length === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "C", null); +listDelete(b0, "any"); +if ((b0.value.length === 2)) { +runtime.ext_scratch3_looks._say("pass", target); } -if ((("" + listGet(b1.value, "*")).toLowerCase() === "".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "F", null); +if ((("" + listGet(b0.value, "*")).toLowerCase() === "".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "E", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) 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 index 424a7c8e5f0..5cc654ba081 100644 --- 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 @@ -3,15 +3,14 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "g", null); +runtime.ext_scratch3_looks._say("plan 1", target); thread.procedures["Wtest %s"]("random"); -if ((("" + b1.value).toLowerCase() === "random".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "p", null); +if ((("" + b0.value).toLowerCase() === "random".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null); +runtime.ext_scratch3_looks._say("end", target); retire(); 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 index 1a3fb7c91b1..6dda54881f6 100644 --- 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 @@ -3,27 +3,26 @@ // 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"]; +const b0 = stage.variables["%ehs:~!Y0l-5=!mnd-B?"]; +const b1 = stage.variables["=3aHfv[mKa)v,Wfpy:y?"]; +const b2 = 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 = (toNotNaN(+b2.value) + 1); -b3.value = (b1.value[(b2.value | 0) - 1] ?? ""); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = []; +b0.value.push((1 + 2)); +b0._monitorUpToDate = false; +b0.value.push("eof"); +b0._monitorUpToDate = false; +b1.value = 0; +b2.value = "bwah"; +while (!(("" + b2.value).toLowerCase() === "eof".toLowerCase())) { +b1.value = (toNotNaN(+b1.value) + 1); +b2.value = (b0.value[(b1.value | 0) - 1] ?? ""); yield; } -if ((toNotNaN(+b2.value) === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "q", null); +if ((toNotNaN(+b1.value) === 2)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-obsolete-blocks.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-obsolete-blocks.sb3.tw-snapshot index ac61a75d00a..71a44853beb 100644 --- a/test/snapshot/__snapshots__/tw-obsolete-blocks.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-obsolete-blocks.sb3.tw-snapshot @@ -3,31 +3,30 @@ // 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 = runtime.getOpcodeFunction("sensing_userid"); -const b3 = runtime.getOpcodeFunction("motion_xscroll"); -const b4 = runtime.getOpcodeFunction("motion_yscroll"); -const b5 = runtime.getOpcodeFunction("motion_scroll_right"); -const b6 = runtime.getOpcodeFunction("motion_scroll_up"); -const b7 = runtime.getOpcodeFunction("motion_align_scene"); -const b8 = runtime.getOpcodeFunction("looks_setstretchto"); -const b9 = runtime.getOpcodeFunction("looks_changestretchby"); -const b10 = runtime.getOpcodeFunction("looks_hideallsprites"); +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = runtime.getOpcodeFunction("sensing_userid"); +const b2 = runtime.getOpcodeFunction("motion_xscroll"); +const b3 = runtime.getOpcodeFunction("motion_yscroll"); +const b4 = runtime.getOpcodeFunction("motion_scroll_right"); +const b5 = runtime.getOpcodeFunction("motion_scroll_up"); +const b6 = runtime.getOpcodeFunction("motion_align_scene"); +const b7 = runtime.getOpcodeFunction("looks_setstretchto"); +const b8 = runtime.getOpcodeFunction("looks_changestretchby"); +const b9 = runtime.getOpcodeFunction("looks_hideallsprites"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "pW2KnJW$%KXFoppMJBAi", null); -b1.value = (yield* executeInCompatibilityLayer({}, b2, false, false, "X[|X;C.(v[|^i|@0Eqy4", null)); -b1.value = (yield* executeInCompatibilityLayer({}, b3, false, false, "z;H$hVK7X;MZSyO9U/#1", null)); -b1.value = (yield* executeInCompatibilityLayer({}, b4, false, false, ";Q94_J}Jv36TqTll;ji*", null)); -yield* executeInCompatibilityLayer({"DISTANCE":10,}, b5, false, false, "_TLJeW5hG9gAtYO2c*D9", null); -yield* executeInCompatibilityLayer({"DISTANCE":10,}, b6, false, false, "o=l#1WJR!L37RN`q:`8E", null); -yield* executeInCompatibilityLayer({"ALIGNMENT":"bottom-left",}, b7, false, false, "idkZ9I+=Q:@xXm;N-2Oy", null); -yield* executeInCompatibilityLayer({"STRETCH":100,}, b8, false, false, "AMs-%pRGK*v6a[.XifN1", null); -yield* executeInCompatibilityLayer({"STRETCH":100,}, b8, false, false, "g+bBVCHp+A[-X2E7-7#|", null); -yield* executeInCompatibilityLayer({"CHANGE":10,}, b9, false, false, "ZN24~,cX56Dc2k4vt}HB", null); -yield* executeInCompatibilityLayer({"CHANGE":10,}, b9, false, false, "Zjds+5Is*:nb7wnX{rYN", null); -yield* executeInCompatibilityLayer({}, b10, false, false, "8X_d`@6,B7%wzr7.xE}t", null); -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "C/%^M/1/S`iX8*M~Q;!3", null); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "(C;YJ2L~?zR[Y)Wti?3m", null); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = (yield* executeInCompatibilityLayer({}, b1, false, false, "X[|X;C.(v[|^i|@0Eqy4", null)); +b0.value = (yield* executeInCompatibilityLayer({}, b2, false, false, "z;H$hVK7X;MZSyO9U/#1", null)); +b0.value = (yield* executeInCompatibilityLayer({}, b3, false, false, ";Q94_J}Jv36TqTll;ji*", null)); +yield* executeInCompatibilityLayer({"DISTANCE":10,}, b4, false, false, "_TLJeW5hG9gAtYO2c*D9", null); +yield* executeInCompatibilityLayer({"DISTANCE":10,}, b5, false, false, "o=l#1WJR!L37RN`q:`8E", null); +yield* executeInCompatibilityLayer({"ALIGNMENT":"bottom-left",}, b6, false, false, "idkZ9I+=Q:@xXm;N-2Oy", null); +yield* executeInCompatibilityLayer({"STRETCH":100,}, b7, false, false, "AMs-%pRGK*v6a[.XifN1", null); +yield* executeInCompatibilityLayer({"STRETCH":100,}, b7, false, false, "g+bBVCHp+A[-X2E7-7#|", null); +yield* executeInCompatibilityLayer({"CHANGE":10,}, b8, false, false, "ZN24~,cX56Dc2k4vt}HB", null); +yield* executeInCompatibilityLayer({"CHANGE":10,}, b8, false, false, "Zjds+5Is*:nb7wnX{rYN", null); +yield* executeInCompatibilityLayer({}, b9, false, false, "8X_d`@6,B7%wzr7.xE}t", null); +runtime.ext_scratch3_looks._say("pass", target); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-one-divide-negative-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-one-divide-negative-zero.sb3.tw-snapshot index d87b4b227fe..3e2eeffa931 100644 --- a/test/snapshot/__snapshots__/tw-one-divide-negative-zero.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-one-divide-negative-zero.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "@|B*yJ0zKh!acN`7L-N5", null); +runtime.ext_scratch3_looks._say("plan 1", target); if (((1 / -0) === -Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "=enYDFG11Nj/0BL:y56w", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",Cpv8W0RH0RgNky[1xb:", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot index 0f6a49f62b7..3b2521664aa 100644 --- a/test/snapshot/__snapshots__/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot @@ -4,13 +4,12 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["PsY$$vp$IVH;dDAr[q2h"]; -const b1 = runtime.getOpcodeFunction("looks_say"); -const b2 = stage.variables["l^q!%fq]Bv;72dlGf}^Z"]; +const b1 = stage.variables["l^q!%fq]Bv;72dlGf}^Z"]; return function* genXYZ () { b0.value = 0; -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b1, false, false, "}fY]VN(X|v/[G`P0?@s2", null); +runtime.ext_scratch3_looks._say("plan 0", target); for (var a0 = 30; a0 > 0; a0--) { -b2.value = runtime.ioDevices.clock.projectTimer(); +b1.value = runtime.ioDevices.clock.projectTimer(); thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -22,7 +21,7 @@ thread.timer = null; yield; } b0.value = 1; -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b1, false, false, "mDG0BTTG/wwr;/Uz~u^c", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -31,7 +30,6 @@ retire(); return; const b0 = stage.variables["l^q!%fq]Bv;72dlGf}^Z"]; const b1 = runtime.getOpcodeFunction("event_whengreaterthan"); const b2 = stage.variables["PsY$$vp$IVH;dDAr[q2h"]; -const b3 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { { const resolvedValue = toBoolean((yield* executeInCompatibilityLayer({"VALUE":b0.value,"WHENGREATERTHANMENU":"TIMER",}, b1, false, false, "iNmua~6veGey6O-_UB9.", null))); @@ -45,7 +43,7 @@ retire(); return; yield; } if (compareEqual(b2.value, 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b3, false, false, "JE9*Ms@I!EKJ-|Bcga#W", null); +runtime.ext_scratch3_looks._say("fail", target); } retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot index 58b908a70ce..adf5671a8c7 100644 --- a/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot @@ -3,18 +3,16 @@ // Player script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "#0F2+kcgu;or|hdwuT9{", null); -yield* thread.procedures["ZSet Costume"](); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Q^(MKge)QH2e:WH6b6g@", null); +runtime.ext_scratch3_looks._say("plan 1", target); +thread.procedures["ZSet Costume"](); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Player ZSet Costume (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_Set_Costume () { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "Z$W^@c(f)rHu:DL/SGuQ", null); +return function funXYZ_Set_Costume () { +runtime.ext_scratch3_looks._say("pass", target); return ""; }; }) diff --git a/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot index f2456f2e254..5766bd76809 100644 --- a/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-arguments-with-same-name.sb3.tw-snapshot @@ -3,31 +3,28 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "J#qm1yA(@Z6mj%Mgh;0X", null); -yield* thread.procedures["Znumber or text %s %s"]("bad","ok"); -yield* thread.procedures["Zboolean %b %b"]("false",!false); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb(Mu?gdTIH^;kC_", null); +runtime.ext_scratch3_looks._say("plan 2", target); +thread.procedures["Znumber or text %s %s"]("bad","ok"); +thread.procedures["Zboolean %b %b"]("false",!false); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 Znumber or text %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_number_or_text__ (p0,p1) { +return function funXYZ_number_or_text__ (p0,p1) { if ((("" + p1).toLowerCase() === "ok".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "HH`yRe9(x5%D:eV@EmkE", null); +runtime.ext_scratch3_looks._say("pass", target); } return ""; }; }) // Sprite1 Zboolean %b %b (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_boolean__ (p0,p1) { +return function funXYZ_boolean__ (p0,p1) { if (toBoolean(p1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "M^!cgco]B(V)je$a6lF7", null); +runtime.ext_scratch3_looks._say("pass", target); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot index f80c51477bd..98305cc14c7 100644 --- a/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot @@ -3,16 +3,15 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "qf{MD}-f+l?U+)KA#Vnm", null); -b1.value = ""; +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = ""; thread.procedures["Zdo something"](); -if (!(b1.value.toLowerCase() === "".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "Sgf_#7|GOpx!R]?Q3]$s", null); +if (!(b0.value.toLowerCase() === "".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",vD-ZG7f{]FoJ`,))JWh", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot index c86b1325e8f..e0e3857ecd3 100644 --- a/test/snapshot/__snapshots__/tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot @@ -3,9 +3,8 @@ // Apple script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a", null); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "f", null); +runtime.ext_scratch3_looks._say("plan 0", target); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot index d3a12562b1a..2cf755d294c 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-non-existant.sb3.tw-snapshot @@ -23,19 +23,18 @@ retire(); return; // 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["Go=PJS7BFXYo_qi2S:kQ"]; +const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "o", null); -b1.value = 0; +runtime.ext_scratch3_looks._say("plan 2", target); +b0.value = 0; if (compareEqual(thread.procedures["Zinvalid params - reporter"](), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass invalid params reporter",}, b0, false, false, "L", null); +runtime.ext_scratch3_looks._say("pass invalid params reporter", target); } if (compareEqual(thread.procedures["Zinvalid params - boolean"](), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass invalid params boolean",}, b0, false, false, "N", null); +runtime.ext_scratch3_looks._say("pass invalid params boolean", target); } runtime.stopForTarget(target, thread); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "P", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-procedure-return-non-existent.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-non-existent.sb3.tw-snapshot index cea7ecccc17..7c867947149 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-non-existent.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-non-existent.sb3.tw-snapshot @@ -3,15 +3,14 @@ // Sprite2 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 b0 = 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 = "discard me"; -b1.value = ""; -if ((("" + b1.value).toLowerCase() === "".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent procedure returned empty string",}, b0, false, false, "h", null); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = "discard me"; +b0.value = ""; +if ((("" + b0.value).toLowerCase() === "".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass non existent procedure returned empty string", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null); +runtime.ext_scratch3_looks._say("end", target); 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 2952a58ecbc..d0e29b100c2 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-recursion.sb3.tw-snapshot @@ -3,30 +3,29 @@ // 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["Go=PJS7BFXYo_qi2S:kQ"]; -const b2 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 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 ((toNotNaN(+b1.value) === 4)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp recursion yields",}, b0, false, false, "ao", null); +runtime.ext_scratch3_looks._say("plan 18", target); +b0.value = 0; +b1.value = (yield* thread.procedures["Znon warp recursion should yield %s"](8)); +if ((toNotNaN(+b0.value) === 4)) { +runtime.ext_scratch3_looks._say("pass non warp recursion yields", target); } -b1.value = 0; -b2.value = thread.procedures["Wwarp recursion should not yield %s"](8); -if ((b1.value === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass warp recursion does not yield",}, b0, false, false, "ar", null); +b0.value = 0; +b1.value = thread.procedures["Wwarp recursion should not yield %s"](8); +if ((b0.value === 0)) { +runtime.ext_scratch3_looks._say("pass warp recursion does not yield", target); } -b1.value = 0; -b2.value = (yield* thread.procedures["Zfib %s"](7)); -if ((toNotNaN(+b1.value) === 20)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp fib yielded",}, b0, false, false, "au", null); +b0.value = 0; +b1.value = (yield* thread.procedures["Zfib %s"](7)); +if ((toNotNaN(+b0.value) === 20)) { +runtime.ext_scratch3_looks._say("pass non warp fib yielded", target); } yield* thread.procedures["Zrecursing yields between each %s"]("initial"); yield* thread.procedures["Zrecursing arguments eval order %s %s %s %s"]("initial","","",""); runtime.stopForTarget(target, thread); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "av", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -63,21 +62,20 @@ return ""; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_recursing_yields_bet (p0) { if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = 0; b1.value = (toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3))) + toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)))))))))))); if ((toNotNaN(+b0.value) === 3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recursing between calls yields final",}, b2, false, false, "aK", null); +runtime.ext_scratch3_looks._say("pass recursing between calls yields final", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":"fail recursing between calls yields final",}, b2, false, false, "aL", null); +runtime.ext_scratch3_looks._say("fail recursing between calls yields final", target); } } else { if (compareEqual(b0.value, p0)) { -yield* executeInCompatibilityLayer({"MESSAGE":("pass recursing between calls yields " + ("" + p0)),}, b2, false, false, "#", null); +runtime.ext_scratch3_looks._say(("pass recursing between calls yields " + ("" + p0)), target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":("fail recursing between calls yields " + ("" + p0)),}, b2, false, false, "%", null); +runtime.ext_scratch3_looks._say(("fail recursing between calls yields " + ("" + p0)), target); } } return ""; @@ -88,35 +86,34 @@ return ""; const b0 = stage.variables["4HH82mPlVMOONdl(Ot*7"]; const b1 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b2 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; -const b3 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_recursing_arguments_ (p0,p1,p2,p3) { if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = []; b1.value = 0; b2.value = (yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 1",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 2",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 3",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 4","","","")),(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 5","","","")),(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 6","","","")))),"","")),"",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 7","","","")))); if ((("" + (b0.value[1 - 1] ?? "")).toLowerCase() === "1/child 4".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 1",}, b3, false, false, "aZ", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 1", target); } if ((("" + (b0.value[2 - 1] ?? "")).toLowerCase() === "1/child 5".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 2",}, b3, false, false, "a#", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 2", target); } if ((("" + (b0.value[3 - 1] ?? "")).toLowerCase() === "2/child 6".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 3",}, b3, false, false, "a(", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 3", target); } if ((("" + (b0.value[4 - 1] ?? "")).toLowerCase() === "2/child 3".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 4",}, b3, false, false, "a*", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 4", target); } if ((("" + (b0.value[5 - 1] ?? "")).toLowerCase() === "3/child 2".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 5",}, b3, false, false, "a,", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 5", target); } if ((("" + (b0.value[6 - 1] ?? "")).toLowerCase() === "3/child 7".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 6",}, b3, false, false, "a.", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 6", target); } if ((("" + (b0.value[7 - 1] ?? "")).toLowerCase() === "4/child 1".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 7",}, b3, false, false, "a:", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 7", target); } if ((b0.value.length === 7)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - length is correct",}, b3, false, false, "a=", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - length is correct", target); } } else { b0.value.push((("" + b1.value) + ("/" + ("" + p0)))); diff --git a/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot index e356c359bf8..c14aa78f900 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-simple.sb3.tw-snapshot @@ -3,27 +3,26 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 8",}, b0, false, false, "x", null); +runtime.ext_scratch3_looks._say("plan 8", target); if ((("" + thread.procedures["Zsimplest"]()).toLowerCase() === "It works!".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass simplest",}, b0, false, false, ":", null); +runtime.ext_scratch3_looks._say("pass simplest", target); } if ((("" + thread.procedures["Znesting 1"]()).toLowerCase() === "42-54".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass nesting1",}, b0, false, false, "=", null); +runtime.ext_scratch3_looks._say("pass nesting1", target); } if ((toNotNaN(+thread.procedures["Wwarp fib %s"](12)) === 144)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass fib 12",}, b0, false, false, "@", null); +runtime.ext_scratch3_looks._say("pass fib 12", target); } if ((toNotNaN(+thread.procedures["Wfactorial %s"](12)) === 479001600)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass factorial 12",}, b0, false, false, "]", null); +runtime.ext_scratch3_looks._say("pass factorial 12", target); } -b1.value = (yield* thread.procedures["Zno shadowing 1 %s %s"]("f","g")); -if ((("" + b1.value).toLowerCase() === "".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass default return value",}, b0, false, false, "|", null); +b0.value = thread.procedures["Zno shadowing 1 %s %s"]("f","g"); +if ((("" + b0.value).toLowerCase() === "".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass default return value", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "`", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -61,19 +60,18 @@ return ""; // Sprite1 Zno shadowing 1 %s %s (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_no_shadowing_1__ (p0,p1) { +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function funXYZ_no_shadowing_1__ (p0,p1) { if (((("" + p0).toLowerCase() === "f".toLowerCase()) && (("" + p1).toLowerCase() === "g".toLowerCase()))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass shadow check 1",}, b0, false, false, "aq", null); +runtime.ext_scratch3_looks._say("pass shadow check 1", target); } -b1.value = thread.procedures["Zno shadowing 2 %s %s"](1,2); +b0.value = thread.procedures["Zno shadowing 2 %s %s"](1,2); if (((("" + p0).toLowerCase() === "f".toLowerCase()) && (("" + p1).toLowerCase() === "g".toLowerCase()))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass shadow check 2",}, b0, false, false, "au", null); +runtime.ext_scratch3_looks._say("pass shadow check 2", target); } -b1.value = thread.procedures["Zno shadowing 2 %s %s"](3,4); +b0.value = thread.procedures["Zno shadowing 2 %s %s"](3,4); if (((("" + p0).toLowerCase() === "f".toLowerCase()) && (("" + p1).toLowerCase() === "g".toLowerCase()))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass shadow check 3",}, b0, false, false, "ax", null); +runtime.ext_scratch3_looks._say("pass shadow check 3", target); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot index 89a6e4963fb..bf4562d1098 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-stops-scripts.sb3.tw-snapshot @@ -3,27 +3,25 @@ // 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["PsAI*C{QHI3*4?O8p#TM"]; +const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "f", null); -yield* thread.procedures["Wreturn stops the script immediately"](); -if ((toNotNaN(+b1.value) === 25)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass return stopped the script immediately",}, b0, false, false, "u", null); +runtime.ext_scratch3_looks._say("plan 2", target); +thread.procedures["Wreturn stops the script immediately"](); +if ((b0.value === 25)) { +runtime.ext_scratch3_looks._say("pass return stopped the script immediately", target); } yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "Test return outside of custom block" })); -if ((toNotNaN(+b1.value) === 18)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass return worked to stop outside of custom block",}, b0, false, false, "x", null); +if ((toNotNaN(+b0.value) === 18)) { +runtime.ext_scratch3_looks._say("pass return worked to stop outside of custom block", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "v", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 Wreturn stops the script immediately (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; -const b1 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_return_stops_the_scr () { +return function funXYZ_return_stops_the_scr () { b0.value = 0; for (var a0 = 100; a0 > 0; a0--) { b0.value = (b0.value + 1); @@ -31,7 +29,7 @@ if ((b0.value === 25)) { return "stopped!"; } } -yield* executeInCompatibilityLayer({"MESSAGE":"fail return did not stop the script immediately",}, b1, true, false, "z", null); +runtime.ext_scratch3_looks._say("fail return did not stop the script immediately", target); return ""; }; }) diff --git a/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot index faa31335951..b871beebb51 100644 --- a/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-procedure-return-warp.sb3.tw-snapshot @@ -23,19 +23,17 @@ retire(); return; // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 3",}, b0, false, false, "k", null); +runtime.ext_scratch3_looks._say("plan 3", target); yield* thread.procedures["Znon warp"](); runtime.stopForTarget(target, thread); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "N", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 Znon warp (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_non_warp () { b0.value = 0; for (var a0 = 5; a0 > 0; a0--) { @@ -50,10 +48,10 @@ thread.timer = null; yield; } if ((toNotNaN(+b0.value) === 5)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 1",}, b1, false, false, "R", null); +runtime.ext_scratch3_looks._say("pass non warp 1", target); } if ((("" + (yield* thread.procedures["Wverify runs warp %s"]((yield* thread.procedures["Zverify runs non warp %s"]((yield* thread.procedures["Wverify runs warp %s"]("abc"))))))).toLowerCase() === "warp: non warp: warp: abc".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp and warp mix",}, b1, false, false, "S", null); +runtime.ext_scratch3_looks._say("pass non warp and warp mix", target); } b0.value = 0; for (var a2 = 5; a2 > 0; a2--) { @@ -68,7 +66,7 @@ thread.timer = null; yield; } if ((toNotNaN(+b0.value) === 5)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 2",}, b1, false, false, "W", null); +runtime.ext_scratch3_looks._say("pass non warp 2", target); } return ""; }; }) @@ -76,7 +74,6 @@ return ""; // Sprite1 Wverify runs warp %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_verify_runs_warp_ (p0) { b0.value = 0; for (var a0 = 5; a0 > 0; a0--) { @@ -89,7 +86,7 @@ if (isStuck()) yield; thread.timer = null; } if (!compareEqual(b0.value, 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail did not run warp",}, b1, true, false, "Z", null); +runtime.ext_scratch3_looks._say("fail did not run warp", target); } return ("warp: " + ("" + p0)); return ""; @@ -98,7 +95,6 @@ return ""; // Sprite1 Zverify runs non warp %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_verify_runs_non_warp (p0) { b0.value = 0; for (var a0 = 5; a0 > 0; a0--) { @@ -113,7 +109,7 @@ thread.timer = null; yield; } if (compareEqual(b0.value, 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail ran warp",}, b1, false, false, "L", null); +runtime.ext_scratch3_looks._say("fail ran warp", target); } return ("non warp: " + ("" + p0)); return ""; diff --git a/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot index 4c166406d91..608f12c0515 100644 --- a/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot @@ -5,15 +5,14 @@ (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["JbF5exWEi*m?-UEmkASS"]; const b1 = stage.variables["[G/@.KGc-4y[(GZ(bt7o"]; -const b2 = runtime.getOpcodeFunction("looks_say"); -const b3 = runtime.getOpcodeFunction("sound_seteffectto"); +const b2 = runtime.getOpcodeFunction("sound_seteffectto"); return function* genXYZ () { while (true) { if (compareEqual(b0.value, b1.value)) { } else { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b2, false, false, "89/dl$1dp$~nj81:jj@H", null); +runtime.ext_scratch3_looks._say("pass", target); b1.value = b0.value; -yield* executeInCompatibilityLayer({"VALUE":b0.value,"EFFECT":"pitch",}, b3, false, true, "*=8r,g4Pzvxo?aSMcpfX", null); +yield* executeInCompatibilityLayer({"VALUE":b0.value,"EFFECT":"pitch",}, b2, false, true, "*=8r,g4Pzvxo?aSMcpfX", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } yield; @@ -24,16 +23,15 @@ retire(); return; // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["[G/@.KGc-4y[(GZ(bt7o"]; -const b1 = runtime.getOpcodeFunction("looks_say"); -const b2 = stage.variables["JbF5exWEi*m?-UEmkASS"]; +const b1 = stage.variables["JbF5exWEi*m?-UEmkASS"]; return function* genXYZ () { b0.value = 0; -yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b1, false, false, "0/2-)Gp^^=haQ1OMD.xb", null); +runtime.ext_scratch3_looks._say("plan 15", target); for (var a0 = 15; a0 > 0; a0--) { -if ((toNotNaN(+b2.value) === 200)) { -b2.value = 50; +if ((toNotNaN(+b1.value) === 200)) { +b1.value = 50; } else { -b2.value = 200; +b1.value = 200; } thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); @@ -45,7 +43,7 @@ yield; thread.timer = null; yield; } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b1, false, false, "--nBRXyJfqS0MM9`#S3}", null); +runtime.ext_scratch3_looks._say("end", target); runtime.stopAll(); retire(); return; retire(); return; diff --git a/test/snapshot/__snapshots__/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot index 020097c50f2..188696ef9c7 100644 --- a/test/snapshot/__snapshots__/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot @@ -3,15 +3,14 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); +runtime.ext_scratch3_looks._say("plan 1", target); thread.procedures["Wa"](); -if ((("" + b1.value).toLowerCase() === "bwah".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "l", null); +if ((("" + b0.value).toLowerCase() === "bwah".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "k", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot index e2ba9156759..ca239793693 100644 --- a/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot @@ -3,11 +3,10 @@ // Text script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a~", null); +runtime.ext_scratch3_looks._say("plan 0", target); thread.procedures["Wtest 1"](); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "dh", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-restart-broadcast-threads.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-restart-broadcast-threads.sb3.tw-snapshot index 2356e02f907..8da7bc06f09 100644 --- a/test/snapshot/__snapshots__/tw-restart-broadcast-threads.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-restart-broadcast-threads.sb3.tw-snapshot @@ -3,11 +3,10 @@ // Sprite2 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "aQ(Y!Bs3;[rV^Q%AQ,NX", null); -b1.value = 0; +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = 0; startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); thread.timer = timer(); @@ -18,10 +17,10 @@ while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -if ((toNotNaN(+b1.value) === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "`SX*FG*Lwo*0_T=box-@", null); +if ((toNotNaN(+b0.value) === 1)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "|#`zzPA_x%{`FyIAQhb4", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot index d92f0cf7405..27fd3590b47 100644 --- a/test/snapshot/__snapshots__/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot @@ -3,15 +3,14 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); +runtime.ext_scratch3_looks._say("plan 1", target); target.setDirection(90); target.setDirection((target.direction + 0.25)); target.setDirection((target.direction + 0.25)); if ((target.direction === 90.5)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "i", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "h", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot index aff4757d938..98631100e00 100644 --- a/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-safe-procedure-argument-casting.sb3.tw-snapshot @@ -3,18 +3,17 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "J#qm1yA(@Z6mj%Mgh;0X", null); +runtime.ext_scratch3_looks._say("plan 2", target); thread.procedures["Zswitch %s"]("1"); if ((((target.currentCostume + 1) === 2) && (toNotNaN(+target.getCostumes()[target.currentCostume].name) === 1))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ";DM$.QW6o-O+T/oBdqt!", null); +runtime.ext_scratch3_looks._say("pass", target); } thread.procedures["Zswitch %s"]("2"); if ((((target.currentCostume + 1) === 1) && (toNotNaN(+target.getCostumes()[target.currentCostume].name) === 2))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "71a9Slk0w=^~x;5T@nw,", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb(Mu?gdTIH^;kC_", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot index ff8ab6ec888..accaed1f172 100644 --- a/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot @@ -3,13 +3,12 @@ // 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["G{NQ*NXG*qzywe1Q3?FM"]; -const b2 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b0 = stage.variables["G{NQ*NXG*qzywe1Q3?FM"]; +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = 0; b1.value = 0; -b2.value = 0; startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); retire(); return; }; }) @@ -18,7 +17,6 @@ retire(); return; (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["G{NQ*NXG*qzywe1Q3?FM"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { if (compareEqual(b0.value, 0)) { b0.value = 1; @@ -30,9 +28,9 @@ yield; b1.value = 2; } else { if ((toNotNaN(+b1.value) === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b2, false, false, "p", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b2, false, false, "n", null); +runtime.ext_scratch3_looks._say("end", target); } retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot index b15bc894fa8..fa2c818d9ba 100644 --- a/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot @@ -3,112 +3,111 @@ // Sprite2 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 && stage.lookupVariableByNameAndType("Stage variable", "", true); -const b2 = runtime.getSpriteTargetByName("Test sprite"); -const b3 = b2 && b2.lookupVariableByNameAndType("Private variable", "", true); -const b4 = stage && stage.lookupVariableByNameAndType("This variable used to exist", "", true); -const b5 = stage.variables["GTmK+*w8mNQP,z`4WG8#"]; -const b6 = runtime.getSpriteTargetByName("Sprite that doesn't exist"); +const b0 = stage && stage.lookupVariableByNameAndType("Stage variable", "", true); +const b1 = runtime.getSpriteTargetByName("Test sprite"); +const b2 = b1 && b1.lookupVariableByNameAndType("Private variable", "", true); +const b3 = stage && stage.lookupVariableByNameAndType("This variable used to exist", "", true); +const b4 = stage.variables["GTmK+*w8mNQP,z`4WG8#"]; +const b5 = runtime.getSpriteTargetByName("Sprite that doesn't exist"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 32",}, b0, false, false, "oX(r}qUQo7fd[u~D_4@T", null); +runtime.ext_scratch3_looks._say("plan 32", target); if (((stage.currentCostume + 1) === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass backdrop #",}, b0, false, false, "T9..K[5LEO1f~{%eoPU;", null); +runtime.ext_scratch3_looks._say("pass backdrop #", target); } if ((stage.getCostumes()[stage.currentCostume].name.toLowerCase() === "Backdrop name test".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass backdrop name",}, b0, false, false, "q63|^NKAu?OMK%W-s}+~", null); +runtime.ext_scratch3_looks._say("pass backdrop name", target); } if (((stage ? stage.volume : 0) === 45)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass stage volume",}, b0, false, false, "9Coi(uM:DG!WPZ($,SnY", null); +runtime.ext_scratch3_looks._say("pass stage volume", target); } -if ((("" + (b1 ? b1.value : 0)).toLowerCase() === "Variable in stage".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass stage variable",}, b0, false, false, "D_EA]xN%|[NsTKqc4up9", null); +if ((("" + (b0 ? b0.value : 0)).toLowerCase() === "Variable in stage".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass stage variable", target); } -if (((b2 ? b2.x : 0) === 19)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass x",}, b0, false, false, "ek^n,6zjHyX;YOW;H@]?", null); +if (((b1 ? b1.x : 0) === 19)) { +runtime.ext_scratch3_looks._say("pass x", target); } -if (((b2 ? b2.y : 0) === 20)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass y",}, b0, false, false, "-DZ%ny~~x.m12l9I64~W", null); +if (((b1 ? b1.y : 0) === 20)) { +runtime.ext_scratch3_looks._say("pass y", target); } -if (((b2 ? b2.direction : 0) === 89)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass direction",}, b0, false, false, "$Y=E2o@3oa-^OHt5v:-b", null); +if (((b1 ? b1.direction : 0) === 89)) { +runtime.ext_scratch3_looks._say("pass direction", target); } -if (((b2 ? b2.currentCostume + 1 : 0) === 3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass costume #",}, b0, false, false, "+zO[+f?c7F`ZGTbD.oqI", null); +if (((b1 ? b1.currentCostume + 1 : 0) === 3)) { +runtime.ext_scratch3_looks._say("pass costume #", target); } -if (((b2 ? b2.getCostumes()[b2.currentCostume].name : 0).toLowerCase() === "Costume name test".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass costume name",}, b0, false, false, "Y6L|T0Pvwsct2gq+HGvv", null); +if (((b1 ? b1.getCostumes()[b1.currentCostume].name : 0).toLowerCase() === "Costume name test".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass costume name", target); } -if (((b2 ? b2.size : 0) === 76.01)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass size",}, b0, false, false, "IBZv@o)qX~r6)!;hqaWa", null); +if (((b1 ? b1.size : 0) === 76.01)) { +runtime.ext_scratch3_looks._say("pass size", target); } -if (((b2 ? b2.volume : 0) === 14.3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass volume",}, b0, false, false, "JBHJ,)N)@]~;;yFTY`RG", null); +if (((b1 ? b1.volume : 0) === 14.3)) { +runtime.ext_scratch3_looks._say("pass volume", target); } -if ((("" + (b3 ? b3.value : 0)).toLowerCase() === "Private variable value".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass private variable",}, b0, false, false, "#jYbx])r8^`95~ZgPtZD", null); +if ((("" + (b2 ? b2.value : 0)).toLowerCase() === "Private variable value".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass private variable", target); } -if (compareEqual((b4 ? b4.value : 0), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent variable",}, b0, false, false, ")nnN?*l+E)dC(fT5(_@q", null); +if (compareEqual((b3 ? b3.value : 0), 0)) { +runtime.ext_scratch3_looks._say("pass non existent variable", target); } -b5.value = (("" + randomInt(1, 9)) + ("" + randomInt(1, 9))); -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b5.value, PROPERTY: "backdrop #" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop #",}, b0, false, false, "UFr{fbR3@a.u_paq:r]F", null); +b4.value = (("" + randomInt(1, 9)) + ("" + randomInt(1, 9))); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "backdrop #" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE backdrop #", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "backdrop name" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop name",}, b0, false, false, "wzVsIitt0^t(wDS-V3?Z", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "backdrop name" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE backdrop name", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "volume" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE volume",}, b0, false, false, ":SZx%]xR5t`;;@M~:jT:", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "volume" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE volume", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "Stage variable" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE stage variable",}, b0, false, false, "!eEjdEJj!yYb{buag^M[", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "Stage variable" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE stage variable", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "x position" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE x",}, b0, false, false, "!6!o,FiLV=w2bS~{R|AK", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "x position" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE x", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "y position" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE y",}, b0, false, false, "5K7_7*adzRDbfFjxanQF", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "y position" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE y", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "direction" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE direction",}, b0, false, false, "D{z)e;(*H|.gAykbuSkE", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "direction" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE direction", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "costume #" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE costume #",}, b0, false, false, "WgCH3j9ObHA,;P3T=now", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "costume #" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE costume #", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "costume name" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE costume name",}, b0, false, false, "qhxQy$^wiOTOEu.=2^i)", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "costume name" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE costume name", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "size" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE size",}, b0, false, false, "+6V.t=]xZ=Gl?%-OWbFy", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "size" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE size", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "volume" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE volume",}, b0, false, false, "*E:B}?C@H2ce2uRr9.9=", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "volume" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE volume", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "Private variable" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE private variable",}, b0, false, false, "B6r;3{7R7g4Z.pzeGiCM", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "Private variable" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE private variable", target); } -if (((b6 ? b6.x : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop #",}, b0, false, false, "q[X%xv.u6==Riu20?y{I", null); +if (((b5 ? b5.x : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE backdrop #", target); } -if (((b6 ? b6.y : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop name",}, b0, false, false, "?M4CH@e3~]30+$4[brH[", null); +if (((b5 ? b5.y : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE backdrop name", target); } -if (((b6 ? b6.direction : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE volume",}, b0, false, false, "H:D~v_)nZ?oJ8X|qHag#", null); +if (((b5 ? b5.direction : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE volume", target); } -if (((b6 ? b6.currentCostume + 1 : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE stage variable",}, b0, false, false, "lqwZ[26e,$PwYz,OlO0X", null); +if (((b5 ? b5.currentCostume + 1 : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE stage variable", target); } -if (compareEqual((b6 ? b6.getCostumes()[b6.currentCostume].name : 0), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE x",}, b0, false, false, "I@zdHi0kl|{:ze_J.}S_", null); +if (compareEqual((b5 ? b5.getCostumes()[b5.currentCostume].name : 0), 0)) { +runtime.ext_scratch3_looks._say("pass NE x", target); } -if (((b6 ? b6.size : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE y",}, b0, false, false, "qD{Ni|{SL:`04:Gj/A7B", null); +if (((b5 ? b5.size : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE y", target); } -if (((b6 ? b6.volume : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE direction",}, b0, false, false, "vvB(iq@jjvj{=_{:6DXZ", null); +if (((b5 ? b5.volume : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE direction", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "dJRK.)mKX6,r26Jy]5qr", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot index 7899f9ed374..d258651feb7 100644 --- a/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-simple-string-operations.sb3.tw-snapshot @@ -3,15 +3,14 @@ // 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["PJl9-2GypE.OstQk*B_*"]; +const b0 = stage.variables["PJl9-2GypE.OstQk*B_*"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); +runtime.ext_scratch3_looks._say("plan 1", target); thread.procedures["Wa"](); -if ((b1.value.toLowerCase() === "babab".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "s", null); +if ((b0.value.toLowerCase() === "babab".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "q", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) 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 index 3e809112dd6..69eaca7f0d6 100644 --- 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 @@ -3,19 +3,18 @@ // 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 b0 = 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._say("plan 2", target); +b0.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._say("pass initial costume", target); } -runtime.ext_scratch3_looks._setCostume(target, b1.value); +runtime.ext_scratch3_looks._setCostume(target, b0.value); if (((target.currentCostume + 1) === 3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass costume \"5\"",}, b0, false, false, "m", null); +runtime.ext_scratch3_looks._say("pass costume \"5\"", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-stage-cannot-move-layers.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-stage-cannot-move-layers.sb3.tw-snapshot index a19e0ba91c0..685797599df 100644 --- a/test/snapshot/__snapshots__/tw-stage-cannot-move-layers.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-stage-cannot-move-layers.sb3.tw-snapshot @@ -3,11 +3,10 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "5,snC%48IW(1ZVM(k0l2", null); -b1.value = "Initial"; +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = "Initial"; thread.timer = timer(); var a0 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -17,17 +16,16 @@ yield; } thread.timer = null; yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "Test 1" })); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "5.$W?rkoLYkKo1qX@%@?", null); +runtime.ext_scratch3_looks._say("end", target); 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).toLowerCase() === "Initial".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b1, false, false, "eR%8T)3MQjkbQkAh~L0%", null); +runtime.ext_scratch3_looks._say("pass", target); } 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 index 7530899818e..0078fee3bd0 100644 --- 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 @@ -3,16 +3,15 @@ // 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"]; +const b0 = stage.variables["KMKx1gRubgLz,!L]^TBS"]; +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); +runtime.ext_scratch3_looks._say("plan 1", target); thread.procedures["Wtest"](); -if ((("" + listGet(b1.value, b2.value)).toLowerCase() === "thing".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "m", null); +if ((("" + listGet(b0.value, b1.value)).toLowerCase() === "thing".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-subtract-can-return-nan.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-subtract-can-return-nan.sb3.tw-snapshot index e784ce8a4bd..d48db9ac3fa 100644 --- a/test/snapshot/__snapshots__/tw-subtract-can-return-nan.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-subtract-can-return-nan.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "6_?4sPB-|g:DtjdOm5Q-", null); +runtime.ext_scratch3_looks._say("plan 1", target); if (!((Infinity - Infinity) <= 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ")-u2YbbMb;gXMPOidjPj", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "zqE}hdaes.b)@mO1{R;X", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-tab-equals-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-tab-equals-zero.sb3.tw-snapshot index 119556a43f1..a55f7db71ab 100644 --- a/test/snapshot/__snapshots__/tw-tab-equals-zero.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-tab-equals-zero.sb3.tw-snapshot @@ -3,11 +3,10 @@ // 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["Kl,Own0m6{^v3$E{Wsc="]; +const b0 = stage.variables["Kl,Own0m6{^v3$E{Wsc="]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 6",}, b0, false, false, "i", null); -b1.value = "\t"; +runtime.ext_scratch3_looks._say("plan 6", target); +b0.value = "\t"; startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); retire(); return; }; }) @@ -15,26 +14,25 @@ retire(); return; // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Kl,Own0m6{^v3$E{Wsc="]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { if (compareEqual(b0.value, ("0" + ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t in a variable = string 0",}, b1, false, false, "q", null); +runtime.ext_scratch3_looks._say("pass \\t in a variable = string 0", target); } if (compareEqual("\t", ("0" + ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass literal \\t = string 0",}, b1, false, false, "u", null); +runtime.ext_scratch3_looks._say("pass literal \\t = string 0", target); } if (compareEqual((" " + ("" + b0.value)), ("0" + ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t and other spaces = string 0",}, b1, false, false, "w", null); +runtime.ext_scratch3_looks._say("pass \\t and other spaces = string 0", target); } if (compareEqual(b0.value, (0 + 0))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t in a variable = number 0",}, b1, false, false, "z", null); +runtime.ext_scratch3_looks._say("pass \\t in a variable = number 0", target); } if ((0 === (0 + 0))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass literal \\t = number 0",}, b1, false, false, "B", null); +runtime.ext_scratch3_looks._say("pass literal \\t = number 0", target); } if (compareEqual((" " + ("" + b0.value)), (0 + 0))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t and other spaces = number 0",}, b1, false, false, "E", null); +runtime.ext_scratch3_looks._say("pass \\t and other spaces = number 0", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b1, false, false, "D", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot index 41796eb6fd9..0fae46c5922 100644 --- a/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-tangent.sb3.tw-snapshot @@ -3,54 +3,53 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b0, false, false, "p", null); +runtime.ext_scratch3_looks._say("plan 15", target); if (compareEqual(tan(0), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 0",}, b0, false, false, "O", null); +runtime.ext_scratch3_looks._say("pass 0", target); } if ((toNotNaN(tan(90)) === Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 90",}, b0, false, false, "G", null); +runtime.ext_scratch3_looks._say("pass 90", target); } if (compareEqual(tan(180), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 180",}, b0, false, false, "I", null); +runtime.ext_scratch3_looks._say("pass 180", target); } if ((toNotNaN(tan(270)) === -Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 270",}, b0, false, false, "K", null); +runtime.ext_scratch3_looks._say("pass 270", target); } if (compareEqual(tan(360), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 360",}, b0, false, false, "M", null); +runtime.ext_scratch3_looks._say("pass 360", target); } if ((toNotNaN(tan(450)) === Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 450",}, b0, false, false, "Q", null); +runtime.ext_scratch3_looks._say("pass 450", target); } if (compareEqual(tan(540), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 540",}, b0, false, false, "S", null); +runtime.ext_scratch3_looks._say("pass 540", target); } if ((toNotNaN(tan(630)) === -Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 630",}, b0, false, false, "U", null); +runtime.ext_scratch3_looks._say("pass 630", target); } if (compareEqual(tan(720), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 720",}, b0, false, false, "W", null); +runtime.ext_scratch3_looks._say("pass 720", target); } if ((toNotNaN(tan(810)) === Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 810",}, b0, false, false, "Y", null); +runtime.ext_scratch3_looks._say("pass 810", target); } if ((toNotNaN(tan(-90)) === -Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass -90",}, b0, false, false, "0", null); +runtime.ext_scratch3_looks._say("pass -90", target); } if (compareEqual(tan(-180), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass -180",}, b0, false, false, "2", null); +runtime.ext_scratch3_looks._say("pass -180", target); } if ((toNotNaN(tan(-270)) === Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass -270",}, b0, false, false, "4", null); +runtime.ext_scratch3_looks._say("pass -270", target); } if (compareEqual(tan(-360), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass -360",}, b0, false, false, "6", null); +runtime.ext_scratch3_looks._say("pass -360", target); } if ((toNotNaN(tan(-450)) === -Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass -450",}, b0, false, false, "9", null); +runtime.ext_scratch3_looks._say("pass -450", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "8", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot index 014751f5d1e..060a0aa20bf 100644 --- a/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot @@ -3,84 +3,81 @@ // Sprite2 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[",OktMIwz{~bdgWnPEa8u"]; -const b2 = stage.variables["yfy(G`K5K^fJcXAfiN4i"]; +const b0 = stage.variables[",OktMIwz{~bdgWnPEa8u"]; +const b1 = stage.variables["yfy(G`K5K^fJcXAfiN4i"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 14",}, b0, false, false, "S8W[CSRh5A:[y8s/Ridj", null); +runtime.ext_scratch3_looks._say("plan 14", target); if ((10 === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 1",}, b0, false, false, "1ove2a-$DQw7qy5PGdgq", null); +runtime.ext_scratch3_looks._say("pass 1", target); } if ((10 === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 2",}, b0, false, false, "@A5}x{mm-Gk?CVz3o0Yn", null); +runtime.ext_scratch3_looks._say("pass 2", target); } -b1.value = 10; -if ((b1.value === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 3",}, b0, false, false, "Ul:BCck-}Fvdux~x#$${", null); +b0.value = 10; +if ((b0.value === 10)) { +runtime.ext_scratch3_looks._say("pass 3", target); } -if ((toNotNaN(+b1.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 4",}, b0, false, false, "8]2$7P)o#+#Lo]mFSBbx", null); +if ((b0.value === 10)) { +runtime.ext_scratch3_looks._say("pass 4", target); } -if ((toNotNaN(+b1.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 5",}, b0, false, false, "ZU^{OfKTg|+Au$$q0[]u", null); +if ((b0.value === 10)) { +runtime.ext_scratch3_looks._say("pass 5", target); } for (var a0 = 1; a0 > 0; a0--) { -if ((toNotNaN(+b1.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 6",}, b0, false, false, "HB+_IN}6=K[*ksxKXH0`", null); +if ((toNotNaN(+b0.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 6", target); } -if ((toNotNaN(+b1.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 7",}, b0, false, false, ";73ODiwcp8IthYURTX;S", null); +if ((toNotNaN(+b0.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 7", target); } -if ((toNotNaN(+b1.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 8",}, b0, false, true, "${[MFmBL-D*1rbas9Q89", null); -if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} +if ((toNotNaN(+b0.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 8", target); } yield; } -b2.value = "010"; -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 9",}, b0, false, false, "#.`@SBj!g-c0:_q/tMZo", null); +b1.value = "010"; +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 9", target); } -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 10",}, b0, false, false, "B`o?V6/q6g),/2w};a#y", null); +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 10", target); } -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 11",}, b0, false, false, "TJ:#TkYBys*!RYiKLXb)", null); +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 11", target); } for (var a1 = 1; a1 > 0; a1--) { -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 12",}, b0, false, false, ",Z,~10Qo~j;(+VL+I3q:", null); +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 12", target); } -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 13",}, b0, false, false, "|Mqx([(26M%#ggW9)U0s", null); +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 13", target); } -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 14",}, b0, false, true, "YvtiKF231lU8p5Qd97RP", null); -if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 14", target); } yield; } if ((0 === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "yO!,nQodLC}uqIc?212+", null); +runtime.ext_scratch3_looks._say("fail", target); } if ((1 === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "XzQt!.^A,SV?q0`Ui)wG", null); +runtime.ext_scratch3_looks._say("fail", target); } if ((0 === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "rxZqw7cv8g;PDM4B%{`?", null); +runtime.ext_scratch3_looks._say("fail", target); } if ((" ".toLowerCase() === "0".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "3G|)eVw1mQm;O~cRy`}0", null); +runtime.ext_scratch3_looks._say("fail", target); } if (("0".toLowerCase() === " ".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "sd5xXX*tsW/~A_Q!0;^w", null); +runtime.ext_scratch3_looks._say("fail", target); } if (("".toLowerCase() === "0".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "7**baE=].WD9OoY1+IEu", null); +runtime.ext_scratch3_looks._say("fail", target); } if (("0".toLowerCase() === "".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "7!IB!=o/2H.Jqj-8Vwhz", null); +runtime.ext_scratch3_looks._say("fail", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "df{tf!WhfRwXgQ?SN_dj", null); +runtime.ext_scratch3_looks._say("end", target); retire(); 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 index 4312367087b..02b2fc4738c 100644 --- 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 @@ -3,16 +3,15 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "e", null); +runtime.ext_scratch3_looks._say("plan 0", target); startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); -b1.value = "bwah"; -while (!(("" + b1.value).toLowerCase() === "bleh".toLowerCase())) { +b0.value = "bwah"; +while (!(("" + b0.value).toLowerCase() === "bleh".toLowerCase())) { yield; } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "h", null); +runtime.ext_scratch3_looks._say("end", target); 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 index 7a4aaa9cae2..2d5bbe8de16 100644 --- a/test/snapshot/__snapshots__/tw-warp-loop-condition-analysis.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-warp-loop-condition-analysis.sb3.tw-snapshot @@ -3,23 +3,22 @@ // 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"]; +const b0 = stage.variables[";~q(!vt3c.Jrz2M]ZMy]"]; +const b1 = 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; +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = []; +b0.value.push((1 + 2)); +b0._monitorUpToDate = false; +b0.value.push((3 + 4)); +b0._monitorUpToDate = false; +b0.value.push("final"); +b0._monitorUpToDate = false; thread.procedures["Wtest"](); -if ((b2.value === 4)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "u", null); +if ((b1.value === 4)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "t", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot index 8f918a81081..90dd7011df2 100644 --- a/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot @@ -3,18 +3,16 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); +runtime.ext_scratch3_looks._say("plan 1", target); yield* thread.procedures["Wrun without screen refresh"](); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "s", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 Wrun without screen refresh (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["F?*}X,`9XBpN_[piGRrz"]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_run_without_screen_r () { b0.value = ((daysSince2000() * 86400) + 3); runtime.ioDevices.clock.resetProjectTimer(); @@ -22,7 +20,7 @@ while (!((runtime.ioDevices.clock.projectTimer() > 0.1) || compareGreaterThan((d if (isStuck()) yield; } if (compareLessThan((daysSince2000() * 86400), b0.value)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b1, true, false, "u", null); +runtime.ext_scratch3_looks._say("pass", target); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot index 20e97770379..8b5cdd42bd8 100644 --- a/test/snapshot/__snapshots__/tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot @@ -3,17 +3,15 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Ny4npe`j3|CTeaIS.:6O", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "2T.vCF,K}vA=XNZ=kY+v", null); +runtime.ext_scratch3_looks._say("plan 0", target); runtime.ext_scratch3_looks._setBackdrop(stage, stage.currentCostume + 1, true); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot index c8479702223..a6ef03ebdb4 100644 --- a/test/snapshot/__snapshots__/tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot @@ -3,17 +3,15 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Ny4npe`j3|CTeaIS.:6O", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "2T.vCF,K}vA=XNZ=kY+v", null); +runtime.ext_scratch3_looks._say("plan 0", target); runtime.ext_scratch3_looks._setBackdrop(stage, "backdrop2"); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot index 229d2814438..7ed5bde1fc6 100644 --- a/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-zombie-cube-escape-284516654.sb3.tw-snapshot @@ -3,19 +3,18 @@ // Sprite2 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["7qur6!bGgvC9I(Nd5.HP"]; -const b2 = stage.variables["sUOp@-6J4y0PqwiXit4!"]; +const b0 = stage.variables["7qur6!bGgvC9I(Nd5.HP"]; +const b1 = stage.variables["sUOp@-6J4y0PqwiXit4!"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, ",a.euo_AgQTxR+D^x0M0", null); -b1.value = 0; -b2.value = ""; -while (!(("" + b2.value).toLowerCase() > "".toLowerCase())) { +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = 0; +b1.value = ""; +while (!(("" + b1.value).toLowerCase() > "".toLowerCase())) { startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "step" }); yield; } -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "miAC8JZ$@akv[+}KR*@B", null); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "gXJU#lhy3A3XA_s[-Xs$", null); +runtime.ext_scratch3_looks._say("pass", target); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot index 466e9f50eee..dc849cf46e2 100644 --- a/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/order-library-reverse.sb3.tw-snapshot @@ -5,7 +5,6 @@ (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["p]KODv+)+:l=%NT~j3/d-order"]; const b1 = stage.variables["p]KODv+)+:l=%NT~j3/d-wait"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); @@ -18,21 +17,20 @@ yield; thread.timer = null; b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "]4hbk*5ix]V00h|!x1oy", null); +runtime.ext_scratch3_looks._say("pass order is correct (1)", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 1 != " + ("" + b0.value)),}, b2, false, false, "H=x@7SpNJeX|!}8x5y4,", null); +runtime.ext_scratch3_looks._say(("fail order is incorrect 1 != " + ("" + b0.value)), target); } retire(); return; }; }) // Sprite3 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["p]KODv+)+:l=%NT~j3/d-wait"]; +const b0 = stage.variables["p]KODv+)+:l=%NT~j3/d-wait"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "1Ba%a0GIK#hwJ46y=WVt", null); +runtime.ext_scratch3_looks._say("plan 2", target); thread.timer = timer(); -var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a0 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { @@ -40,7 +38,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a1 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a1 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a1) { @@ -48,14 +46,14 @@ yield; } thread.timer = null; thread.timer = timer(); -var a2 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a2 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a2) { yield; } thread.timer = null; -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "}-I/zE+.RSi`:h[RxMvQ", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -63,7 +61,6 @@ retire(); return; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["p]KODv+)+:l=%NT~j3/d-order"]; const b1 = stage.variables["p]KODv+)+:l=%NT~j3/d-wait"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); @@ -76,9 +73,9 @@ yield; thread.timer = null; b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "0i[-T:vYTt=bi47@byUE", null); +runtime.ext_scratch3_looks._say("pass order is correct (2)", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 2 != " + ("" + b0.value)),}, b2, false, false, "Coc1aZ;L9M-RyEt`syps", null); +runtime.ext_scratch3_looks._say(("fail order is incorrect 2 != " + ("" + b0.value)), target); } retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot index 49cfd33b5e1..c2b537cdcd5 100644 --- a/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/order-library.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite3 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["):/PVGTvoVRvq(ikGwRE-wait"]; +const b0 = stage.variables["):/PVGTvoVRvq(ikGwRE-wait"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "s+@:|^WPr8]N1Y9Hk2f5", null); +runtime.ext_scratch3_looks._say("plan 2", target); thread.timer = timer(); -var a0 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a0 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a0) { @@ -16,7 +15,7 @@ yield; } thread.timer = null; thread.timer = timer(); -var a1 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a1 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a1) { @@ -24,14 +23,14 @@ yield; } thread.timer = null; thread.timer = timer(); -var a2 = Math.max(0, 1000 * toNotNaN(+b1.value)); +var a2 = Math.max(0, 1000 * toNotNaN(+b0.value)); runtime.requestRedraw(); yield; while (thread.timer.timeElapsed() < a2) { yield; } thread.timer = null; -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "7e7aA!PF-sxf1uka+sh2", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -39,7 +38,6 @@ retire(); return; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["):/PVGTvoVRvq(ikGwRE-order"]; const b1 = stage.variables["):/PVGTvoVRvq(ikGwRE-wait"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); @@ -52,9 +50,9 @@ yield; thread.timer = null; b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (1)",}, b2, false, false, "RSQ{nVCc)6E)(`KlnFCF", null); +runtime.ext_scratch3_looks._say("pass order is correct (1)", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 1 != " + ("" + b0.value)),}, b2, false, false, "8k^j~`c^|YO@hkFd?~2d", null); +runtime.ext_scratch3_looks._say(("fail order is incorrect 1 != " + ("" + b0.value)), target); } retire(); return; }; }) @@ -63,7 +61,6 @@ retire(); return; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["):/PVGTvoVRvq(ikGwRE-order"]; const b1 = stage.variables["):/PVGTvoVRvq(ikGwRE-wait"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { b0.value = 0; thread.timer = timer(); @@ -76,9 +73,9 @@ yield; thread.timer = null; b0.value = (toNotNaN(+b0.value) + 1); if ((b0.value === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass order is correct (2)",}, b2, false, false, "KP?op(=Vg2#;@]!,C#.~", null); +runtime.ext_scratch3_looks._say("pass order is correct (2)", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":("fail order is incorrect 2 != " + ("" + b0.value)),}, b2, false, false, "=]|}L~4uQXTNtwJKw_;R", null); +runtime.ext_scratch3_looks._say(("fail order is incorrect 2 != " + ("" + b0.value)), target); } retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot index a760bbe3a6b..19888e5845d 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-NaN.sb3.tw-snapshot @@ -3,72 +3,71 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 21",}, b0, false, false, "B", null); +runtime.ext_scratch3_looks._say("plan 21", target); if (!(("" + (0 / 0)).toLowerCase() === "0".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aA", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + (0 * Infinity)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "/", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN((0 * Infinity)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "?", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + ((Math.acos(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "=", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(((Math.acos(1.01) * 180) / Math.PI)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "]", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + ((Math.asin(1.01) * 180) / Math.PI)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "_", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(((Math.asin(1.01) * 180) / Math.PI)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "{", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + (0 / 0)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "}", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN((0 / 0)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aa", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + Math.sqrt(-1)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ac", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(Math.sqrt(-1)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ae", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + mod(0, 0)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ag", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(mod(0, 0)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ai", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + Math.log(-1)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ak", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(Math.log(-1)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "am", null); +runtime.ext_scratch3_looks._say("pass", target); } if ((("" + (Math.log(-1) / Math.LN10)).toLowerCase() === "NaN".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ao", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN((Math.log(-1) / Math.LN10)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aq", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN((Math.round(Math.sin((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "as", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN((Math.round(Math.cos((Math.PI * (1 / 0)) / 180) * 1e10) / 1e10)) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "au", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(tan((1 / 0))) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "aw", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((toNotNaN(runtime.ext_scratch3_operators._random((-1 / 0), (1 / 0))) * 1) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "ax", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ":", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-add-can-return-nan.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-add-can-return-nan.sb3.tw-snapshot index 3652f132f3d..7ce7b186e9b 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-add-can-return-nan.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-add-can-return-nan.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "6_?4sPB-|g:DtjdOm5Q-", null); +runtime.ext_scratch3_looks._say("plan 1", target); if (!((Infinity + -Infinity) <= 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ")-u2YbbMb;gXMPOidjPj", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "zqE}hdaes.b)@mO1{R;X", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-all-at-once.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-all-at-once.sb3.tw-snapshot index 7baf88d8f09..beca8936c7b 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-all-at-once.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-all-at-once.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "1TRvh{mBarwY!BX8`o$R", null); +runtime.ext_scratch3_looks._say("plan 1", target); if (true) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "K|r`QjC126S.93lMawiD", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "QaZ%(g:;bB~D+24z:U?l", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot index 75de04704b4..32435b0af57 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-analyze-yields-due-to-direct-recursion.sb3.tw-snapshot @@ -3,17 +3,16 @@ // 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["FpLI$ida6)qR,q~y`1|*"]; +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = stage.variables["FpLI$ida6)qR,q~y`1|*"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "j", null); -b1.value = (1 + 2); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = (1 + 2); yield* thread.procedures["Znon-warp recursion %s"](2); -if ((("" + listGet(b2.value, b1.value)).toLowerCase() === "the only thing".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "t", null); +if ((("" + listGet(b1.value, b0.value)).toLowerCase() === "the only thing".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "s", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot index ac6f722391f..d3a2c80cab3 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot @@ -3,11 +3,10 @@ // 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 = target.variables["null"]; +const b0 = target.variables["null"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a", null); -b1.value = 5; -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "d", null); +runtime.ext_scratch3_looks._say("plan 0", target); +b0.value = 5; +runtime.ext_scratch3_looks._say("end", target); 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 index 2e9766c0409..153276f7b89 100644 --- 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 @@ -3,26 +3,24 @@ // 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"]; +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = 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; +runtime.ext_scratch3_looks._say("plan 2", target); +b0.value = 1; +b1.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); +runtime.ext_scratch3_looks._say("end", target); 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 ((toNotNaN(+b0.value) === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 1",}, b1, false, false, "m", null); +runtime.ext_scratch3_looks._say("pass variable 1", target); } retire(); return; }; }) @@ -30,10 +28,9 @@ 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 ((toNotNaN(+b0.value) === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass variable 2",}, b1, false, false, "q", null); +runtime.ext_scratch3_looks._say("pass variable 2", target); } retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-boolean-arguments-are-not-cast.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-boolean-arguments-are-not-cast.sb3.tw-snapshot index bb3be7cad38..b7aca7680ef 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-boolean-arguments-are-not-cast.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-boolean-arguments-are-not-cast.sb3.tw-snapshot @@ -3,22 +3,20 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "f", null); -yield* thread.procedures["ZBlock A %s"]("Hai!!!"); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "k", null); +runtime.ext_scratch3_looks._say("plan 1", target); +thread.procedures["ZBlock A %s"]("Hai!!!"); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 ZBlock A %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_Block_A_ (p0) { +return function funXYZ_Block_A_ (p0) { if ((("" + p0).toLowerCase() === "Hai!!!".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass did not cast",}, b0, false, false, "m", null); +runtime.ext_scratch3_looks._say("pass did not cast", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":"fail was casted",}, b0, false, false, "n", null); +runtime.ext_scratch3_looks._say("fail was casted", target); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-broadcast-id-and-name-desync.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-broadcast-id-and-name-desync.sb3.tw-snapshot index e08c111f3db..42f3cd396bf 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-broadcast-id-and-name-desync.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-broadcast-id-and-name-desync.sb3.tw-snapshot @@ -3,18 +3,16 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "?@x?KlY[GHB#^le;O^;Z", null); +runtime.ext_scratch3_looks._say("pass", target); retire(); return; }; }) // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "*S!`s:/sOEm#Bd%7=h7E", null); +runtime.ext_scratch3_looks._say("plan 1", target); yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" })); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g#w*ISI)$Wi.45AszY|1", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot index 89d78f7e429..4d1afe46852 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot @@ -3,20 +3,19 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "()*H*UE)$Jc!c}qb{,O)", null); +runtime.ext_scratch3_looks._say("plan 1", target); target.setSize(96); -b1.value = 0; +b0.value = 0; while (!(100 === Math.round(target.size))) { -b1.value = (toNotNaN(+b1.value) + 1); +b0.value = (toNotNaN(+b0.value) + 1); target.setSize(target.size + ((100 - Math.round(target.size)) / 10)); yield; } -if ((toNotNaN(+b1.value) === 20)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "FPDFR?Wwq)kLj0A$0D{@", null); +if ((toNotNaN(+b0.value) === 20)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "1,vLoJ4OQBv+Q#$VoYf=", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-color-input-returns-hex.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-color-input-returns-hex.sb3.tw-snapshot index 070b355da4a..56b3817737b 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-color-input-returns-hex.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-color-input-returns-hex.sb3.tw-snapshot @@ -3,14 +3,13 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); -b1.value = "#22388a"; -if ((b1.value.toLowerCase() === "#22388a".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "f", null); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = "#22388a"; +if ((b0.value.toLowerCase() === "#22388a".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "e", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot index 741ccca8ae7..cb8e0dfefbd 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot @@ -3,1773 +3,1772 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "f)", null); +runtime.ext_scratch3_looks._say("plan 0", target); if (!(("" + (0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 1: 0 should be < 0",}, b0, false, false, "tB", null); +runtime.ext_scratch3_looks._say("fail 1: 0 should be < 0", target); } if (!(("" + (0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 2: 0 should be = 0",}, b0, false, false, "tD", null); +runtime.ext_scratch3_looks._say("fail 2: 0 should be = 0", target); } if (!(("" + (0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 3: 0 should be > 0",}, b0, false, false, "tF", null); +runtime.ext_scratch3_looks._say("fail 3: 0 should be > 0", target); } if (!(("" + (0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 4: 0 should be < 0.0",}, b0, false, false, "tH", null); +runtime.ext_scratch3_looks._say("fail 4: 0 should be < 0.0", target); } if (!(("" + (0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 5: 0 should be = 0.0",}, b0, false, false, "tJ", null); +runtime.ext_scratch3_looks._say("fail 5: 0 should be = 0.0", target); } if (!(("" + (0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 6: 0 should be > 0.0",}, b0, false, false, "tL", null); +runtime.ext_scratch3_looks._say("fail 6: 0 should be > 0.0", target); } if (!(("" + (0 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 7: 0 should be < 1.23",}, b0, false, false, "tN", null); +runtime.ext_scratch3_looks._say("fail 7: 0 should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 8: 0 should be = 1.23",}, b0, false, false, "tP", null); +runtime.ext_scratch3_looks._say("fail 8: 0 should be = 1.23", target); } if (!(("" + (0 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 9: 0 should be > 1.23",}, b0, false, false, "tR", null); +runtime.ext_scratch3_looks._say("fail 9: 0 should be > 1.23", target); } if (!(("" + (0 < 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 10: 0 should be < .23",}, b0, false, false, "tT", null); +runtime.ext_scratch3_looks._say("fail 10: 0 should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 11: 0 should be = .23",}, b0, false, false, "tV", null); +runtime.ext_scratch3_looks._say("fail 11: 0 should be = .23", target); } if (!(("" + (0 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 12: 0 should be > .23",}, b0, false, false, "tX", null); +runtime.ext_scratch3_looks._say("fail 12: 0 should be > .23", target); } if (!(("" + (0 < 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 13: 0 should be < 0.123",}, b0, false, false, "tZ", null); +runtime.ext_scratch3_looks._say("fail 13: 0 should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 14: 0 should be = 0.123",}, b0, false, false, "t1", null); +runtime.ext_scratch3_looks._say("fail 14: 0 should be = 0.123", target); } if (!(("" + (0 > 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 15: 0 should be > 0.123",}, b0, false, false, "t3", null); +runtime.ext_scratch3_looks._say("fail 15: 0 should be > 0.123", target); } if (!(("" + (0 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 16: 0 should be < -0",}, b0, false, false, "t5", null); +runtime.ext_scratch3_looks._say("fail 16: 0 should be < -0", target); } if (!(("" + (0 === -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 17: 0 should be = -0",}, b0, false, false, "t7", null); +runtime.ext_scratch3_looks._say("fail 17: 0 should be = -0", target); } if (!(("" + (0 > -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 18: 0 should be > -0",}, b0, false, false, "t9", null); +runtime.ext_scratch3_looks._say("fail 18: 0 should be > -0", target); } if (!(("" + (0 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 19: 0 should be < -1",}, b0, false, false, "t#", null); +runtime.ext_scratch3_looks._say("fail 19: 0 should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 20: 0 should be = -1",}, b0, false, false, "t(", null); +runtime.ext_scratch3_looks._say("fail 20: 0 should be = -1", target); } if (!(("" + (0 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 21: 0 should be > -1",}, b0, false, false, "t*", null); +runtime.ext_scratch3_looks._say("fail 21: 0 should be > -1", target); } if (!(("" + ("0".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 22: 0 should be < true",}, b0, false, false, "t,", null); +runtime.ext_scratch3_looks._say("fail 22: 0 should be < true", target); } if (!(("" + ("0".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 23: 0 should be = true",}, b0, false, false, "t.", null); +runtime.ext_scratch3_looks._say("fail 23: 0 should be = true", target); } if (!(("" + ("0".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 24: 0 should be > true",}, b0, false, false, "t:", null); +runtime.ext_scratch3_looks._say("fail 24: 0 should be > true", target); } if (!(("" + ("0".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 25: 0 should be < false",}, b0, false, false, "t=", null); +runtime.ext_scratch3_looks._say("fail 25: 0 should be < false", target); } if (!(("" + ("0".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 26: 0 should be = false",}, b0, false, false, "t@", null); +runtime.ext_scratch3_looks._say("fail 26: 0 should be = false", target); } if (!(("" + ("0".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 27: 0 should be > false",}, b0, false, false, "t]", null); +runtime.ext_scratch3_looks._say("fail 27: 0 should be > false", target); } if (!(("" + ("0".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 28: 0 should be < NaN",}, b0, false, false, "t_", null); +runtime.ext_scratch3_looks._say("fail 28: 0 should be < NaN", target); } if (!(("" + ("0".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 29: 0 should be = NaN",}, b0, false, false, "t{", null); +runtime.ext_scratch3_looks._say("fail 29: 0 should be = NaN", target); } if (!(("" + ("0".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 30: 0 should be > NaN",}, b0, false, false, "t}", null); +runtime.ext_scratch3_looks._say("fail 30: 0 should be > NaN", target); } if (!(("" + (0 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 31: 0 should be < Infinity",}, b0, false, false, "ua", null); +runtime.ext_scratch3_looks._say("fail 31: 0 should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 32: 0 should be = Infinity",}, b0, false, false, "uc", null); +runtime.ext_scratch3_looks._say("fail 32: 0 should be = Infinity", target); } if (!(("" + (0 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 33: 0 should be > Infinity",}, b0, false, false, "ue", null); +runtime.ext_scratch3_looks._say("fail 33: 0 should be > Infinity", target); } if (!(("" + ("0".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 34: 0 should be < banana",}, b0, false, false, "ug", null); +runtime.ext_scratch3_looks._say("fail 34: 0 should be < banana", target); } if (!(("" + ("0".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 35: 0 should be = banana",}, b0, false, false, "ui", null); +runtime.ext_scratch3_looks._say("fail 35: 0 should be = banana", target); } if (!(("" + ("0".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 36: 0 should be > banana",}, b0, false, false, "uk", null); +runtime.ext_scratch3_looks._say("fail 36: 0 should be > banana", target); } if (!(("" + ("0".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 37: 0 should be < 🎉",}, b0, false, false, "um", null); +runtime.ext_scratch3_looks._say("fail 37: 0 should be < 🎉", target); } if (!(("" + ("0".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 38: 0 should be = 🎉",}, b0, false, false, "uo", null); +runtime.ext_scratch3_looks._say("fail 38: 0 should be = 🎉", target); } if (!(("" + ("0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 39: 0 should be > 🎉",}, b0, false, false, "uq", null); +runtime.ext_scratch3_looks._say("fail 39: 0 should be > 🎉", target); } if (!(("" + ("0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 40: 0 should be < ",}, b0, false, false, "us", null); +runtime.ext_scratch3_looks._say("fail 40: 0 should be < ", target); } if (!(("" + ("0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 41: 0 should be = ",}, b0, false, false, "uu", null); +runtime.ext_scratch3_looks._say("fail 41: 0 should be = ", target); } if (!(("" + ("0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 42: 0 should be > ",}, b0, false, false, "uw", null); +runtime.ext_scratch3_looks._say("fail 42: 0 should be > ", target); } if (!(("" + (0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 43: 0.0 should be < 0",}, b0, false, false, "uy", null); +runtime.ext_scratch3_looks._say("fail 43: 0.0 should be < 0", target); } if (!(("" + (0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 44: 0.0 should be = 0",}, b0, false, false, "uA", null); +runtime.ext_scratch3_looks._say("fail 44: 0.0 should be = 0", target); } if (!(("" + (0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 45: 0.0 should be > 0",}, b0, false, false, "uC", null); +runtime.ext_scratch3_looks._say("fail 45: 0.0 should be > 0", target); } if (!(("" + (0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 46: 0.0 should be < 0.0",}, b0, false, false, "uE", null); +runtime.ext_scratch3_looks._say("fail 46: 0.0 should be < 0.0", target); } if (!(("" + (0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 47: 0.0 should be = 0.0",}, b0, false, false, "uG", null); +runtime.ext_scratch3_looks._say("fail 47: 0.0 should be = 0.0", target); } if (!(("" + (0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 48: 0.0 should be > 0.0",}, b0, false, false, "uI", null); +runtime.ext_scratch3_looks._say("fail 48: 0.0 should be > 0.0", target); } if (!(("" + (0 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 49: 0.0 should be < 1.23",}, b0, false, false, "uK", null); +runtime.ext_scratch3_looks._say("fail 49: 0.0 should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 50: 0.0 should be = 1.23",}, b0, false, false, "uM", null); +runtime.ext_scratch3_looks._say("fail 50: 0.0 should be = 1.23", target); } if (!(("" + (0 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 51: 0.0 should be > 1.23",}, b0, false, false, "uO", null); +runtime.ext_scratch3_looks._say("fail 51: 0.0 should be > 1.23", target); } if (!(("" + (0 < 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 52: 0.0 should be < .23",}, b0, false, false, "uQ", null); +runtime.ext_scratch3_looks._say("fail 52: 0.0 should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 53: 0.0 should be = .23",}, b0, false, false, "uS", null); +runtime.ext_scratch3_looks._say("fail 53: 0.0 should be = .23", target); } if (!(("" + (0 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 54: 0.0 should be > .23",}, b0, false, false, "uU", null); +runtime.ext_scratch3_looks._say("fail 54: 0.0 should be > .23", target); } if (!(("" + (0 < 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 55: 0.0 should be < 0.123",}, b0, false, false, "uW", null); +runtime.ext_scratch3_looks._say("fail 55: 0.0 should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 56: 0.0 should be = 0.123",}, b0, false, false, "uY", null); +runtime.ext_scratch3_looks._say("fail 56: 0.0 should be = 0.123", target); } if (!(("" + (0 > 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 57: 0.0 should be > 0.123",}, b0, false, false, "u0", null); +runtime.ext_scratch3_looks._say("fail 57: 0.0 should be > 0.123", target); } if (!(("" + (0 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 58: 0.0 should be < -0",}, b0, false, false, "u2", null); +runtime.ext_scratch3_looks._say("fail 58: 0.0 should be < -0", target); } if (!(("" + (0 === -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 59: 0.0 should be = -0",}, b0, false, false, "u4", null); +runtime.ext_scratch3_looks._say("fail 59: 0.0 should be = -0", target); } if (!(("" + (0 > -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 60: 0.0 should be > -0",}, b0, false, false, "u6", null); +runtime.ext_scratch3_looks._say("fail 60: 0.0 should be > -0", target); } if (!(("" + (0 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 61: 0.0 should be < -1",}, b0, false, false, "u8", null); +runtime.ext_scratch3_looks._say("fail 61: 0.0 should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 62: 0.0 should be = -1",}, b0, false, false, "u!", null); +runtime.ext_scratch3_looks._say("fail 62: 0.0 should be = -1", target); } if (!(("" + (0 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 63: 0.0 should be > -1",}, b0, false, false, "u%", null); +runtime.ext_scratch3_looks._say("fail 63: 0.0 should be > -1", target); } if (!(("" + ("0.0".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 64: 0.0 should be < true",}, b0, false, false, "u)", null); +runtime.ext_scratch3_looks._say("fail 64: 0.0 should be < true", target); } if (!(("" + ("0.0".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 65: 0.0 should be = true",}, b0, false, false, "u+", null); +runtime.ext_scratch3_looks._say("fail 65: 0.0 should be = true", target); } if (!(("" + ("0.0".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 66: 0.0 should be > true",}, b0, false, false, "u-", null); +runtime.ext_scratch3_looks._say("fail 66: 0.0 should be > true", target); } if (!(("" + ("0.0".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 67: 0.0 should be < false",}, b0, false, false, "u/", null); +runtime.ext_scratch3_looks._say("fail 67: 0.0 should be < false", target); } if (!(("" + ("0.0".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 68: 0.0 should be = false",}, b0, false, false, "u;", null); +runtime.ext_scratch3_looks._say("fail 68: 0.0 should be = false", target); } if (!(("" + ("0.0".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 69: 0.0 should be > false",}, b0, false, false, "u?", null); +runtime.ext_scratch3_looks._say("fail 69: 0.0 should be > false", target); } if (!(("" + ("0.0".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 70: 0.0 should be < NaN",}, b0, false, false, "u[", null); +runtime.ext_scratch3_looks._say("fail 70: 0.0 should be < NaN", target); } if (!(("" + ("0.0".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 71: 0.0 should be = NaN",}, b0, false, false, "u^", null); +runtime.ext_scratch3_looks._say("fail 71: 0.0 should be = NaN", target); } if (!(("" + ("0.0".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 72: 0.0 should be > NaN",}, b0, false, false, "u`", null); +runtime.ext_scratch3_looks._say("fail 72: 0.0 should be > NaN", target); } if (!(("" + (0 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 73: 0.0 should be < Infinity",}, b0, false, false, "u|", null); +runtime.ext_scratch3_looks._say("fail 73: 0.0 should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 74: 0.0 should be = Infinity",}, b0, false, false, "u~", null); +runtime.ext_scratch3_looks._say("fail 74: 0.0 should be = Infinity", target); } if (!(("" + (0 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 75: 0.0 should be > Infinity",}, b0, false, false, "vb", null); +runtime.ext_scratch3_looks._say("fail 75: 0.0 should be > Infinity", target); } if (!(("" + ("0.0".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 76: 0.0 should be < banana",}, b0, false, false, "vd", null); +runtime.ext_scratch3_looks._say("fail 76: 0.0 should be < banana", target); } if (!(("" + ("0.0".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 77: 0.0 should be = banana",}, b0, false, false, "vf", null); +runtime.ext_scratch3_looks._say("fail 77: 0.0 should be = banana", target); } if (!(("" + ("0.0".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 78: 0.0 should be > banana",}, b0, false, false, "vh", null); +runtime.ext_scratch3_looks._say("fail 78: 0.0 should be > banana", target); } if (!(("" + ("0.0".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 79: 0.0 should be < 🎉",}, b0, false, false, "vj", null); +runtime.ext_scratch3_looks._say("fail 79: 0.0 should be < 🎉", target); } if (!(("" + ("0.0".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 80: 0.0 should be = 🎉",}, b0, false, false, "vl", null); +runtime.ext_scratch3_looks._say("fail 80: 0.0 should be = 🎉", target); } if (!(("" + ("0.0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 81: 0.0 should be > 🎉",}, b0, false, false, "vn", null); +runtime.ext_scratch3_looks._say("fail 81: 0.0 should be > 🎉", target); } if (!(("" + ("0.0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 82: 0.0 should be < ",}, b0, false, false, "vp", null); +runtime.ext_scratch3_looks._say("fail 82: 0.0 should be < ", target); } if (!(("" + ("0.0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 83: 0.0 should be = ",}, b0, false, false, "vr", null); +runtime.ext_scratch3_looks._say("fail 83: 0.0 should be = ", target); } if (!(("" + ("0.0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 84: 0.0 should be > ",}, b0, false, false, "vt", null); +runtime.ext_scratch3_looks._say("fail 84: 0.0 should be > ", target); } if (!(("" + (1.23 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 85: 1.23 should be < 0",}, b0, false, false, "vv", null); +runtime.ext_scratch3_looks._say("fail 85: 1.23 should be < 0", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 86: 1.23 should be = 0",}, b0, false, false, "vx", null); +runtime.ext_scratch3_looks._say("fail 86: 1.23 should be = 0", target); } if (!(("" + (1.23 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 87: 1.23 should be > 0",}, b0, false, false, "vz", null); +runtime.ext_scratch3_looks._say("fail 87: 1.23 should be > 0", target); } if (!(("" + (1.23 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 88: 1.23 should be < 0.0",}, b0, false, false, "vB", null); +runtime.ext_scratch3_looks._say("fail 88: 1.23 should be < 0.0", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 89: 1.23 should be = 0.0",}, b0, false, false, "vD", null); +runtime.ext_scratch3_looks._say("fail 89: 1.23 should be = 0.0", target); } if (!(("" + (1.23 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 90: 1.23 should be > 0.0",}, b0, false, false, "vF", null); +runtime.ext_scratch3_looks._say("fail 90: 1.23 should be > 0.0", target); } if (!(("" + (1.23 < 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 91: 1.23 should be < 1.23",}, b0, false, false, "vH", null); +runtime.ext_scratch3_looks._say("fail 91: 1.23 should be < 1.23", target); } if (!(("" + (1.23 === 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 92: 1.23 should be = 1.23",}, b0, false, false, "vJ", null); +runtime.ext_scratch3_looks._say("fail 92: 1.23 should be = 1.23", target); } if (!(("" + (1.23 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 93: 1.23 should be > 1.23",}, b0, false, false, "vL", null); +runtime.ext_scratch3_looks._say("fail 93: 1.23 should be > 1.23", target); } if (!(("" + (1.23 < 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 94: 1.23 should be < .23",}, b0, false, false, "vN", null); +runtime.ext_scratch3_looks._say("fail 94: 1.23 should be < .23", target); } if (!(("" + (1.23 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 95: 1.23 should be = .23",}, b0, false, false, "vP", null); +runtime.ext_scratch3_looks._say("fail 95: 1.23 should be = .23", target); } if (!(("" + (1.23 > 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 96: 1.23 should be > .23",}, b0, false, false, "vR", null); +runtime.ext_scratch3_looks._say("fail 96: 1.23 should be > .23", target); } if (!(("" + (1.23 < 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 97: 1.23 should be < 0.123",}, b0, false, false, "vT", null); +runtime.ext_scratch3_looks._say("fail 97: 1.23 should be < 0.123", target); } if (!(("" + (1.23 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 98: 1.23 should be = 0.123",}, b0, false, false, "vV", null); +runtime.ext_scratch3_looks._say("fail 98: 1.23 should be = 0.123", target); } if (!(("" + (1.23 > 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 99: 1.23 should be > 0.123",}, b0, false, false, "vX", null); +runtime.ext_scratch3_looks._say("fail 99: 1.23 should be > 0.123", target); } if (!(("" + (1.23 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 100: 1.23 should be < -0",}, b0, false, false, "vZ", null); +runtime.ext_scratch3_looks._say("fail 100: 1.23 should be < -0", target); } if (!(("" + (1.23 === -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 101: 1.23 should be = -0",}, b0, false, false, "v1", null); +runtime.ext_scratch3_looks._say("fail 101: 1.23 should be = -0", target); } if (!(("" + (1.23 > -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 102: 1.23 should be > -0",}, b0, false, false, "v3", null); +runtime.ext_scratch3_looks._say("fail 102: 1.23 should be > -0", target); } if (!(("" + (1.23 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 103: 1.23 should be < -1",}, b0, false, false, "v5", null); +runtime.ext_scratch3_looks._say("fail 103: 1.23 should be < -1", target); } if (!(("" + (1.23 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 104: 1.23 should be = -1",}, b0, false, false, "v7", null); +runtime.ext_scratch3_looks._say("fail 104: 1.23 should be = -1", target); } if (!(("" + (1.23 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 105: 1.23 should be > -1",}, b0, false, false, "v9", null); +runtime.ext_scratch3_looks._say("fail 105: 1.23 should be > -1", target); } if (!(("" + ("1.23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 106: 1.23 should be < true",}, b0, false, false, "v#", null); +runtime.ext_scratch3_looks._say("fail 106: 1.23 should be < true", target); } if (!(("" + (1.23 === 1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 107: 1.23 should be = true",}, b0, false, false, "v(", null); +runtime.ext_scratch3_looks._say("fail 107: 1.23 should be = true", target); } if (!(("" + ("1.23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 108: 1.23 should be > true",}, b0, false, false, "v*", null); +runtime.ext_scratch3_looks._say("fail 108: 1.23 should be > true", target); } if (!(("" + ("1.23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 109: 1.23 should be < false",}, b0, false, false, "v,", null); +runtime.ext_scratch3_looks._say("fail 109: 1.23 should be < false", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 110: 1.23 should be = false",}, b0, false, false, "v.", null); +runtime.ext_scratch3_looks._say("fail 110: 1.23 should be = false", target); } if (!(("" + ("1.23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 111: 1.23 should be > false",}, b0, false, false, "v:", null); +runtime.ext_scratch3_looks._say("fail 111: 1.23 should be > false", target); } if (!(("" + ("1.23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 112: 1.23 should be < NaN",}, b0, false, false, "v=", null); +runtime.ext_scratch3_looks._say("fail 112: 1.23 should be < NaN", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 113: 1.23 should be = NaN",}, b0, false, false, "v@", null); +runtime.ext_scratch3_looks._say("fail 113: 1.23 should be = NaN", target); } if (!(("" + ("1.23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 114: 1.23 should be > NaN",}, b0, false, false, "v]", null); +runtime.ext_scratch3_looks._say("fail 114: 1.23 should be > NaN", target); } if (!(("" + (1.23 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 115: 1.23 should be < Infinity",}, b0, false, false, "v_", null); +runtime.ext_scratch3_looks._say("fail 115: 1.23 should be < Infinity", target); } if (!(("" + (1.23 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 116: 1.23 should be = Infinity",}, b0, false, false, "v{", null); +runtime.ext_scratch3_looks._say("fail 116: 1.23 should be = Infinity", target); } if (!(("" + (1.23 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 117: 1.23 should be > Infinity",}, b0, false, false, "v}", null); +runtime.ext_scratch3_looks._say("fail 117: 1.23 should be > Infinity", target); } if (!(("" + ("1.23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 118: 1.23 should be < banana",}, b0, false, false, "wa", null); +runtime.ext_scratch3_looks._say("fail 118: 1.23 should be < banana", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 119: 1.23 should be = banana",}, b0, false, false, "wc", null); +runtime.ext_scratch3_looks._say("fail 119: 1.23 should be = banana", target); } if (!(("" + ("1.23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 120: 1.23 should be > banana",}, b0, false, false, "we", null); +runtime.ext_scratch3_looks._say("fail 120: 1.23 should be > banana", target); } if (!(("" + ("1.23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 121: 1.23 should be < 🎉",}, b0, false, false, "wg", null); +runtime.ext_scratch3_looks._say("fail 121: 1.23 should be < 🎉", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 122: 1.23 should be = 🎉",}, b0, false, false, "wi", null); +runtime.ext_scratch3_looks._say("fail 122: 1.23 should be = 🎉", target); } if (!(("" + ("1.23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 123: 1.23 should be > 🎉",}, b0, false, false, "wk", null); +runtime.ext_scratch3_looks._say("fail 123: 1.23 should be > 🎉", target); } if (!(("" + ("1.23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 124: 1.23 should be < ",}, b0, false, false, "wm", null); +runtime.ext_scratch3_looks._say("fail 124: 1.23 should be < ", target); } if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 125: 1.23 should be = ",}, b0, false, false, "wo", null); +runtime.ext_scratch3_looks._say("fail 125: 1.23 should be = ", target); } if (!(("" + ("1.23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 126: 1.23 should be > ",}, b0, false, false, "wq", null); +runtime.ext_scratch3_looks._say("fail 126: 1.23 should be > ", target); } if (!(("" + (0.23 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 127: .23 should be < 0",}, b0, false, false, "ws", null); +runtime.ext_scratch3_looks._say("fail 127: .23 should be < 0", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 128: .23 should be = 0",}, b0, false, false, "wu", null); +runtime.ext_scratch3_looks._say("fail 128: .23 should be = 0", target); } if (!(("" + (0.23 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 129: .23 should be > 0",}, b0, false, false, "ww", null); +runtime.ext_scratch3_looks._say("fail 129: .23 should be > 0", target); } if (!(("" + (0.23 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 130: .23 should be < 0.0",}, b0, false, false, "wy", null); +runtime.ext_scratch3_looks._say("fail 130: .23 should be < 0.0", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 131: .23 should be = 0.0",}, b0, false, false, "wA", null); +runtime.ext_scratch3_looks._say("fail 131: .23 should be = 0.0", target); } if (!(("" + (0.23 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 132: .23 should be > 0.0",}, b0, false, false, "wC", null); +runtime.ext_scratch3_looks._say("fail 132: .23 should be > 0.0", target); } if (!(("" + (0.23 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 133: .23 should be < 1.23",}, b0, false, false, "wE", null); +runtime.ext_scratch3_looks._say("fail 133: .23 should be < 1.23", target); } if (!(("" + (0.23 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 134: .23 should be = 1.23",}, b0, false, false, "wG", null); +runtime.ext_scratch3_looks._say("fail 134: .23 should be = 1.23", target); } if (!(("" + (0.23 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 135: .23 should be > 1.23",}, b0, false, false, "wI", null); +runtime.ext_scratch3_looks._say("fail 135: .23 should be > 1.23", target); } if (!(("" + (0.23 < 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 136: .23 should be < .23",}, b0, false, false, "wK", null); +runtime.ext_scratch3_looks._say("fail 136: .23 should be < .23", target); } if (!(("" + (0.23 === 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 137: .23 should be = .23",}, b0, false, false, "wM", null); +runtime.ext_scratch3_looks._say("fail 137: .23 should be = .23", target); } if (!(("" + (0.23 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 138: .23 should be > .23",}, b0, false, false, "wO", null); +runtime.ext_scratch3_looks._say("fail 138: .23 should be > .23", target); } if (!(("" + (0.23 < 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 139: .23 should be < 0.123",}, b0, false, false, "wQ", null); +runtime.ext_scratch3_looks._say("fail 139: .23 should be < 0.123", target); } if (!(("" + (0.23 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 140: .23 should be = 0.123",}, b0, false, false, "wS", null); +runtime.ext_scratch3_looks._say("fail 140: .23 should be = 0.123", target); } if (!(("" + (0.23 > 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 141: .23 should be > 0.123",}, b0, false, false, "wU", null); +runtime.ext_scratch3_looks._say("fail 141: .23 should be > 0.123", target); } if (!(("" + (0.23 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 142: .23 should be < -0",}, b0, false, false, "wW", null); +runtime.ext_scratch3_looks._say("fail 142: .23 should be < -0", target); } if (!(("" + (0.23 === -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 143: .23 should be = -0",}, b0, false, false, "wY", null); +runtime.ext_scratch3_looks._say("fail 143: .23 should be = -0", target); } if (!(("" + (0.23 > -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 144: .23 should be > -0",}, b0, false, false, "w0", null); +runtime.ext_scratch3_looks._say("fail 144: .23 should be > -0", target); } if (!(("" + (0.23 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 145: .23 should be < -1",}, b0, false, false, "w2", null); +runtime.ext_scratch3_looks._say("fail 145: .23 should be < -1", target); } if (!(("" + (0.23 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 146: .23 should be = -1",}, b0, false, false, "w4", null); +runtime.ext_scratch3_looks._say("fail 146: .23 should be = -1", target); } if (!(("" + (0.23 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 147: .23 should be > -1",}, b0, false, false, "w6", null); +runtime.ext_scratch3_looks._say("fail 147: .23 should be > -1", target); } if (!(("" + (".23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 148: .23 should be < true",}, b0, false, false, "w8", null); +runtime.ext_scratch3_looks._say("fail 148: .23 should be < true", target); } if (!(("" + (0.23 === 1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 149: .23 should be = true",}, b0, false, false, "w!", null); +runtime.ext_scratch3_looks._say("fail 149: .23 should be = true", target); } if (!(("" + (".23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 150: .23 should be > true",}, b0, false, false, "w%", null); +runtime.ext_scratch3_looks._say("fail 150: .23 should be > true", target); } if (!(("" + (".23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 151: .23 should be < false",}, b0, false, false, "w)", null); +runtime.ext_scratch3_looks._say("fail 151: .23 should be < false", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 152: .23 should be = false",}, b0, false, false, "w+", null); +runtime.ext_scratch3_looks._say("fail 152: .23 should be = false", target); } if (!(("" + (".23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 153: .23 should be > false",}, b0, false, false, "w-", null); +runtime.ext_scratch3_looks._say("fail 153: .23 should be > false", target); } if (!(("" + (".23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 154: .23 should be < NaN",}, b0, false, false, "w/", null); +runtime.ext_scratch3_looks._say("fail 154: .23 should be < NaN", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 155: .23 should be = NaN",}, b0, false, false, "w;", null); +runtime.ext_scratch3_looks._say("fail 155: .23 should be = NaN", target); } if (!(("" + (".23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 156: .23 should be > NaN",}, b0, false, false, "w?", null); +runtime.ext_scratch3_looks._say("fail 156: .23 should be > NaN", target); } if (!(("" + (0.23 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 157: .23 should be < Infinity",}, b0, false, false, "w[", null); +runtime.ext_scratch3_looks._say("fail 157: .23 should be < Infinity", target); } if (!(("" + (0.23 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 158: .23 should be = Infinity",}, b0, false, false, "w^", null); +runtime.ext_scratch3_looks._say("fail 158: .23 should be = Infinity", target); } if (!(("" + (0.23 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 159: .23 should be > Infinity",}, b0, false, false, "w`", null); +runtime.ext_scratch3_looks._say("fail 159: .23 should be > Infinity", target); } if (!(("" + (".23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 160: .23 should be < banana",}, b0, false, false, "w|", null); +runtime.ext_scratch3_looks._say("fail 160: .23 should be < banana", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 161: .23 should be = banana",}, b0, false, false, "w~", null); +runtime.ext_scratch3_looks._say("fail 161: .23 should be = banana", target); } if (!(("" + (".23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 162: .23 should be > banana",}, b0, false, false, "xb", null); +runtime.ext_scratch3_looks._say("fail 162: .23 should be > banana", target); } if (!(("" + (".23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 163: .23 should be < 🎉",}, b0, false, false, "xd", null); +runtime.ext_scratch3_looks._say("fail 163: .23 should be < 🎉", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 164: .23 should be = 🎉",}, b0, false, false, "xf", null); +runtime.ext_scratch3_looks._say("fail 164: .23 should be = 🎉", target); } if (!(("" + (".23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 165: .23 should be > 🎉",}, b0, false, false, "xh", null); +runtime.ext_scratch3_looks._say("fail 165: .23 should be > 🎉", target); } if (!(("" + (".23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 166: .23 should be < ",}, b0, false, false, "xj", null); +runtime.ext_scratch3_looks._say("fail 166: .23 should be < ", target); } if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 167: .23 should be = ",}, b0, false, false, "xl", null); +runtime.ext_scratch3_looks._say("fail 167: .23 should be = ", target); } if (!(("" + (".23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 168: .23 should be > ",}, b0, false, false, "xn", null); +runtime.ext_scratch3_looks._say("fail 168: .23 should be > ", target); } if (!(("" + (0.123 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 169: 0.123 should be < 0",}, b0, false, false, "xp", null); +runtime.ext_scratch3_looks._say("fail 169: 0.123 should be < 0", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 170: 0.123 should be = 0",}, b0, false, false, "xr", null); +runtime.ext_scratch3_looks._say("fail 170: 0.123 should be = 0", target); } if (!(("" + (0.123 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 171: 0.123 should be > 0",}, b0, false, false, "xt", null); +runtime.ext_scratch3_looks._say("fail 171: 0.123 should be > 0", target); } if (!(("" + (0.123 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 172: 0.123 should be < 0.0",}, b0, false, false, "xv", null); +runtime.ext_scratch3_looks._say("fail 172: 0.123 should be < 0.0", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 173: 0.123 should be = 0.0",}, b0, false, false, "xx", null); +runtime.ext_scratch3_looks._say("fail 173: 0.123 should be = 0.0", target); } if (!(("" + (0.123 > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 174: 0.123 should be > 0.0",}, b0, false, false, "xz", null); +runtime.ext_scratch3_looks._say("fail 174: 0.123 should be > 0.0", target); } if (!(("" + (0.123 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 175: 0.123 should be < 1.23",}, b0, false, false, "xB", null); +runtime.ext_scratch3_looks._say("fail 175: 0.123 should be < 1.23", target); } if (!(("" + (0.123 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 176: 0.123 should be = 1.23",}, b0, false, false, "xD", null); +runtime.ext_scratch3_looks._say("fail 176: 0.123 should be = 1.23", target); } if (!(("" + (0.123 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 177: 0.123 should be > 1.23",}, b0, false, false, "xF", null); +runtime.ext_scratch3_looks._say("fail 177: 0.123 should be > 1.23", target); } if (!(("" + (0.123 < 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 178: 0.123 should be < .23",}, b0, false, false, "xH", null); +runtime.ext_scratch3_looks._say("fail 178: 0.123 should be < .23", target); } if (!(("" + (0.123 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 179: 0.123 should be = .23",}, b0, false, false, "xJ", null); +runtime.ext_scratch3_looks._say("fail 179: 0.123 should be = .23", target); } if (!(("" + (0.123 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 180: 0.123 should be > .23",}, b0, false, false, "xL", null); +runtime.ext_scratch3_looks._say("fail 180: 0.123 should be > .23", target); } if (!(("" + (0.123 < 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 181: 0.123 should be < 0.123",}, b0, false, false, "xN", null); +runtime.ext_scratch3_looks._say("fail 181: 0.123 should be < 0.123", target); } if (!(("" + (0.123 === 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 182: 0.123 should be = 0.123",}, b0, false, false, "xP", null); +runtime.ext_scratch3_looks._say("fail 182: 0.123 should be = 0.123", target); } if (!(("" + (0.123 > 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 183: 0.123 should be > 0.123",}, b0, false, false, "xR", null); +runtime.ext_scratch3_looks._say("fail 183: 0.123 should be > 0.123", target); } if (!(("" + (0.123 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 184: 0.123 should be < -0",}, b0, false, false, "xT", null); +runtime.ext_scratch3_looks._say("fail 184: 0.123 should be < -0", target); } if (!(("" + (0.123 === -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 185: 0.123 should be = -0",}, b0, false, false, "xV", null); +runtime.ext_scratch3_looks._say("fail 185: 0.123 should be = -0", target); } if (!(("" + (0.123 > -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 186: 0.123 should be > -0",}, b0, false, false, "xX", null); +runtime.ext_scratch3_looks._say("fail 186: 0.123 should be > -0", target); } if (!(("" + (0.123 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 187: 0.123 should be < -1",}, b0, false, false, "xZ", null); +runtime.ext_scratch3_looks._say("fail 187: 0.123 should be < -1", target); } if (!(("" + (0.123 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 188: 0.123 should be = -1",}, b0, false, false, "x1", null); +runtime.ext_scratch3_looks._say("fail 188: 0.123 should be = -1", target); } if (!(("" + (0.123 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 189: 0.123 should be > -1",}, b0, false, false, "x3", null); +runtime.ext_scratch3_looks._say("fail 189: 0.123 should be > -1", target); } if (!(("" + ("0.123".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 190: 0.123 should be < true",}, b0, false, false, "x5", null); +runtime.ext_scratch3_looks._say("fail 190: 0.123 should be < true", target); } if (!(("" + (0.123 === 1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 191: 0.123 should be = true",}, b0, false, false, "x7", null); +runtime.ext_scratch3_looks._say("fail 191: 0.123 should be = true", target); } if (!(("" + ("0.123".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 192: 0.123 should be > true",}, b0, false, false, "x9", null); +runtime.ext_scratch3_looks._say("fail 192: 0.123 should be > true", target); } if (!(("" + ("0.123".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 193: 0.123 should be < false",}, b0, false, false, "x#", null); +runtime.ext_scratch3_looks._say("fail 193: 0.123 should be < false", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 194: 0.123 should be = false",}, b0, false, false, "x(", null); +runtime.ext_scratch3_looks._say("fail 194: 0.123 should be = false", target); } if (!(("" + ("0.123".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 195: 0.123 should be > false",}, b0, false, false, "x*", null); +runtime.ext_scratch3_looks._say("fail 195: 0.123 should be > false", target); } if (!(("" + ("0.123".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 196: 0.123 should be < NaN",}, b0, false, false, "x,", null); +runtime.ext_scratch3_looks._say("fail 196: 0.123 should be < NaN", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 197: 0.123 should be = NaN",}, b0, false, false, "x.", null); +runtime.ext_scratch3_looks._say("fail 197: 0.123 should be = NaN", target); } if (!(("" + ("0.123".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 198: 0.123 should be > NaN",}, b0, false, false, "x:", null); +runtime.ext_scratch3_looks._say("fail 198: 0.123 should be > NaN", target); } if (!(("" + (0.123 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 199: 0.123 should be < Infinity",}, b0, false, false, "x=", null); +runtime.ext_scratch3_looks._say("fail 199: 0.123 should be < Infinity", target); } if (!(("" + (0.123 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 200: 0.123 should be = Infinity",}, b0, false, false, "x@", null); +runtime.ext_scratch3_looks._say("fail 200: 0.123 should be = Infinity", target); } if (!(("" + (0.123 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 201: 0.123 should be > Infinity",}, b0, false, false, "x]", null); +runtime.ext_scratch3_looks._say("fail 201: 0.123 should be > Infinity", target); } if (!(("" + ("0.123".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 202: 0.123 should be < banana",}, b0, false, false, "x_", null); +runtime.ext_scratch3_looks._say("fail 202: 0.123 should be < banana", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 203: 0.123 should be = banana",}, b0, false, false, "x{", null); +runtime.ext_scratch3_looks._say("fail 203: 0.123 should be = banana", target); } if (!(("" + ("0.123".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 204: 0.123 should be > banana",}, b0, false, false, "x}", null); +runtime.ext_scratch3_looks._say("fail 204: 0.123 should be > banana", target); } if (!(("" + ("0.123".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 205: 0.123 should be < 🎉",}, b0, false, false, "ya", null); +runtime.ext_scratch3_looks._say("fail 205: 0.123 should be < 🎉", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 206: 0.123 should be = 🎉",}, b0, false, false, "yc", null); +runtime.ext_scratch3_looks._say("fail 206: 0.123 should be = 🎉", target); } if (!(("" + ("0.123".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 207: 0.123 should be > 🎉",}, b0, false, false, "ye", null); +runtime.ext_scratch3_looks._say("fail 207: 0.123 should be > 🎉", target); } if (!(("" + ("0.123".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 208: 0.123 should be < ",}, b0, false, false, "yg", null); +runtime.ext_scratch3_looks._say("fail 208: 0.123 should be < ", target); } if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 209: 0.123 should be = ",}, b0, false, false, "yi", null); +runtime.ext_scratch3_looks._say("fail 209: 0.123 should be = ", target); } if (!(("" + ("0.123".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 210: 0.123 should be > ",}, b0, false, false, "yk", null); +runtime.ext_scratch3_looks._say("fail 210: 0.123 should be > ", target); } if (!(("" + (-0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 211: -0 should be < 0",}, b0, false, false, "ym", null); +runtime.ext_scratch3_looks._say("fail 211: -0 should be < 0", target); } if (!(("" + (-0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 212: -0 should be = 0",}, b0, false, false, "yo", null); +runtime.ext_scratch3_looks._say("fail 212: -0 should be = 0", target); } if (!(("" + (-0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 213: -0 should be > 0",}, b0, false, false, "yq", null); +runtime.ext_scratch3_looks._say("fail 213: -0 should be > 0", target); } if (!(("" + (-0 < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 214: -0 should be < 0.0",}, b0, false, false, "ys", null); +runtime.ext_scratch3_looks._say("fail 214: -0 should be < 0.0", target); } if (!(("" + (-0 === 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 215: -0 should be = 0.0",}, b0, false, false, "yu", null); +runtime.ext_scratch3_looks._say("fail 215: -0 should be = 0.0", target); } if (!(("" + (-0 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 216: -0 should be > 0.0",}, b0, false, false, "yw", null); +runtime.ext_scratch3_looks._say("fail 216: -0 should be > 0.0", target); } if (!(("" + (-0 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 217: -0 should be < 1.23",}, b0, false, false, "yy", null); +runtime.ext_scratch3_looks._say("fail 217: -0 should be < 1.23", target); } if (!(("" + (-0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 218: -0 should be = 1.23",}, b0, false, false, "yA", null); +runtime.ext_scratch3_looks._say("fail 218: -0 should be = 1.23", target); } if (!(("" + (-0 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 219: -0 should be > 1.23",}, b0, false, false, "yC", null); +runtime.ext_scratch3_looks._say("fail 219: -0 should be > 1.23", target); } if (!(("" + (-0 < 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 220: -0 should be < .23",}, b0, false, false, "yE", null); +runtime.ext_scratch3_looks._say("fail 220: -0 should be < .23", target); } if (!(("" + (-0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 221: -0 should be = .23",}, b0, false, false, "yG", null); +runtime.ext_scratch3_looks._say("fail 221: -0 should be = .23", target); } if (!(("" + (-0 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 222: -0 should be > .23",}, b0, false, false, "yI", null); +runtime.ext_scratch3_looks._say("fail 222: -0 should be > .23", target); } if (!(("" + (-0 < 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 223: -0 should be < 0.123",}, b0, false, false, "yK", null); +runtime.ext_scratch3_looks._say("fail 223: -0 should be < 0.123", target); } if (!(("" + (-0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 224: -0 should be = 0.123",}, b0, false, false, "yM", null); +runtime.ext_scratch3_looks._say("fail 224: -0 should be = 0.123", target); } if (!(("" + (-0 > 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 225: -0 should be > 0.123",}, b0, false, false, "yO", null); +runtime.ext_scratch3_looks._say("fail 225: -0 should be > 0.123", target); } if (!(("" + (-0 < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 226: -0 should be < -0",}, b0, false, false, "yQ", null); +runtime.ext_scratch3_looks._say("fail 226: -0 should be < -0", target); } if (!(("" + (-0 === -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 227: -0 should be = -0",}, b0, false, false, "yS", null); +runtime.ext_scratch3_looks._say("fail 227: -0 should be = -0", target); } if (!(("" + (-0 > -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 228: -0 should be > -0",}, b0, false, false, "yU", null); +runtime.ext_scratch3_looks._say("fail 228: -0 should be > -0", target); } if (!(("" + (-0 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 229: -0 should be < -1",}, b0, false, false, "yW", null); +runtime.ext_scratch3_looks._say("fail 229: -0 should be < -1", target); } if (!(("" + (-0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 230: -0 should be = -1",}, b0, false, false, "yY", null); +runtime.ext_scratch3_looks._say("fail 230: -0 should be = -1", target); } if (!(("" + (-0 > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 231: -0 should be > -1",}, b0, false, false, "y0", null); +runtime.ext_scratch3_looks._say("fail 231: -0 should be > -1", target); } if (!(("" + ("-0".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 232: -0 should be < true",}, b0, false, false, "y2", null); +runtime.ext_scratch3_looks._say("fail 232: -0 should be < true", target); } if (!(("" + ("-0".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 233: -0 should be = true",}, b0, false, false, "y4", null); +runtime.ext_scratch3_looks._say("fail 233: -0 should be = true", target); } if (!(("" + ("-0".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 234: -0 should be > true",}, b0, false, false, "y6", null); +runtime.ext_scratch3_looks._say("fail 234: -0 should be > true", target); } if (!(("" + ("-0".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 235: -0 should be < false",}, b0, false, false, "y8", null); +runtime.ext_scratch3_looks._say("fail 235: -0 should be < false", target); } if (!(("" + ("-0".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 236: -0 should be = false",}, b0, false, false, "y!", null); +runtime.ext_scratch3_looks._say("fail 236: -0 should be = false", target); } if (!(("" + ("-0".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 237: -0 should be > false",}, b0, false, false, "y%", null); +runtime.ext_scratch3_looks._say("fail 237: -0 should be > false", target); } if (!(("" + ("-0".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 238: -0 should be < NaN",}, b0, false, false, "y)", null); +runtime.ext_scratch3_looks._say("fail 238: -0 should be < NaN", target); } if (!(("" + ("-0".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 239: -0 should be = NaN",}, b0, false, false, "y+", null); +runtime.ext_scratch3_looks._say("fail 239: -0 should be = NaN", target); } if (!(("" + ("-0".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 240: -0 should be > NaN",}, b0, false, false, "y-", null); +runtime.ext_scratch3_looks._say("fail 240: -0 should be > NaN", target); } if (!(("" + (-0 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 241: -0 should be < Infinity",}, b0, false, false, "y/", null); +runtime.ext_scratch3_looks._say("fail 241: -0 should be < Infinity", target); } if (!(("" + (-0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 242: -0 should be = Infinity",}, b0, false, false, "y;", null); +runtime.ext_scratch3_looks._say("fail 242: -0 should be = Infinity", target); } if (!(("" + (-0 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 243: -0 should be > Infinity",}, b0, false, false, "y?", null); +runtime.ext_scratch3_looks._say("fail 243: -0 should be > Infinity", target); } if (!(("" + ("-0".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 244: -0 should be < banana",}, b0, false, false, "y[", null); +runtime.ext_scratch3_looks._say("fail 244: -0 should be < banana", target); } if (!(("" + ("-0".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 245: -0 should be = banana",}, b0, false, false, "y^", null); +runtime.ext_scratch3_looks._say("fail 245: -0 should be = banana", target); } if (!(("" + ("-0".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 246: -0 should be > banana",}, b0, false, false, "y`", null); +runtime.ext_scratch3_looks._say("fail 246: -0 should be > banana", target); } if (!(("" + ("-0".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 247: -0 should be < 🎉",}, b0, false, false, "y|", null); +runtime.ext_scratch3_looks._say("fail 247: -0 should be < 🎉", target); } if (!(("" + ("-0".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 248: -0 should be = 🎉",}, b0, false, false, "y~", null); +runtime.ext_scratch3_looks._say("fail 248: -0 should be = 🎉", target); } if (!(("" + ("-0".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 249: -0 should be > 🎉",}, b0, false, false, "zb", null); +runtime.ext_scratch3_looks._say("fail 249: -0 should be > 🎉", target); } if (!(("" + ("-0".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 250: -0 should be < ",}, b0, false, false, "zd", null); +runtime.ext_scratch3_looks._say("fail 250: -0 should be < ", target); } if (!(("" + ("-0".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 251: -0 should be = ",}, b0, false, false, "zf", null); +runtime.ext_scratch3_looks._say("fail 251: -0 should be = ", target); } if (!(("" + ("-0".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 252: -0 should be > ",}, b0, false, false, "zh", null); +runtime.ext_scratch3_looks._say("fail 252: -0 should be > ", target); } if (!(("" + (-1 < 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 253: -1 should be < 0",}, b0, false, false, "zj", null); +runtime.ext_scratch3_looks._say("fail 253: -1 should be < 0", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 254: -1 should be = 0",}, b0, false, false, "zl", null); +runtime.ext_scratch3_looks._say("fail 254: -1 should be = 0", target); } if (!(("" + (-1 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 255: -1 should be > 0",}, b0, false, false, "zn", null); +runtime.ext_scratch3_looks._say("fail 255: -1 should be > 0", target); } if (!(("" + (-1 < 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 256: -1 should be < 0.0",}, b0, false, false, "zp", null); +runtime.ext_scratch3_looks._say("fail 256: -1 should be < 0.0", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 257: -1 should be = 0.0",}, b0, false, false, "zr", null); +runtime.ext_scratch3_looks._say("fail 257: -1 should be = 0.0", target); } if (!(("" + (-1 > 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 258: -1 should be > 0.0",}, b0, false, false, "zt", null); +runtime.ext_scratch3_looks._say("fail 258: -1 should be > 0.0", target); } if (!(("" + (-1 < 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 259: -1 should be < 1.23",}, b0, false, false, "zv", null); +runtime.ext_scratch3_looks._say("fail 259: -1 should be < 1.23", target); } if (!(("" + (-1 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 260: -1 should be = 1.23",}, b0, false, false, "zx", null); +runtime.ext_scratch3_looks._say("fail 260: -1 should be = 1.23", target); } if (!(("" + (-1 > 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 261: -1 should be > 1.23",}, b0, false, false, "zz", null); +runtime.ext_scratch3_looks._say("fail 261: -1 should be > 1.23", target); } if (!(("" + (-1 < 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 262: -1 should be < .23",}, b0, false, false, "zB", null); +runtime.ext_scratch3_looks._say("fail 262: -1 should be < .23", target); } if (!(("" + (-1 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 263: -1 should be = .23",}, b0, false, false, "zD", null); +runtime.ext_scratch3_looks._say("fail 263: -1 should be = .23", target); } if (!(("" + (-1 > 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 264: -1 should be > .23",}, b0, false, false, "zF", null); +runtime.ext_scratch3_looks._say("fail 264: -1 should be > .23", target); } if (!(("" + (-1 < 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 265: -1 should be < 0.123",}, b0, false, false, "zH", null); +runtime.ext_scratch3_looks._say("fail 265: -1 should be < 0.123", target); } if (!(("" + (-1 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 266: -1 should be = 0.123",}, b0, false, false, "zJ", null); +runtime.ext_scratch3_looks._say("fail 266: -1 should be = 0.123", target); } if (!(("" + (-1 > 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 267: -1 should be > 0.123",}, b0, false, false, "zL", null); +runtime.ext_scratch3_looks._say("fail 267: -1 should be > 0.123", target); } if (!(("" + (-1 < -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 268: -1 should be < -0",}, b0, false, false, "zN", null); +runtime.ext_scratch3_looks._say("fail 268: -1 should be < -0", target); } if (!(("" + (-1 === -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 269: -1 should be = -0",}, b0, false, false, "zP", null); +runtime.ext_scratch3_looks._say("fail 269: -1 should be = -0", target); } if (!(("" + (-1 > -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 270: -1 should be > -0",}, b0, false, false, "zR", null); +runtime.ext_scratch3_looks._say("fail 270: -1 should be > -0", target); } if (!(("" + (-1 < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 271: -1 should be < -1",}, b0, false, false, "zT", null); +runtime.ext_scratch3_looks._say("fail 271: -1 should be < -1", target); } if (!(("" + (-1 === -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 272: -1 should be = -1",}, b0, false, false, "zV", null); +runtime.ext_scratch3_looks._say("fail 272: -1 should be = -1", target); } if (!(("" + (-1 > -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 273: -1 should be > -1",}, b0, false, false, "zX", null); +runtime.ext_scratch3_looks._say("fail 273: -1 should be > -1", target); } if (!(("" + ("-1".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 274: -1 should be < true",}, b0, false, false, "zZ", null); +runtime.ext_scratch3_looks._say("fail 274: -1 should be < true", target); } if (!(("" + (-1 === 1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 275: -1 should be = true",}, b0, false, false, "z1", null); +runtime.ext_scratch3_looks._say("fail 275: -1 should be = true", target); } if (!(("" + ("-1".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 276: -1 should be > true",}, b0, false, false, "z3", null); +runtime.ext_scratch3_looks._say("fail 276: -1 should be > true", target); } if (!(("" + ("-1".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 277: -1 should be < false",}, b0, false, false, "z5", null); +runtime.ext_scratch3_looks._say("fail 277: -1 should be < false", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 278: -1 should be = false",}, b0, false, false, "z7", null); +runtime.ext_scratch3_looks._say("fail 278: -1 should be = false", target); } if (!(("" + ("-1".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 279: -1 should be > false",}, b0, false, false, "z9", null); +runtime.ext_scratch3_looks._say("fail 279: -1 should be > false", target); } if (!(("" + ("-1".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 280: -1 should be < NaN",}, b0, false, false, "z#", null); +runtime.ext_scratch3_looks._say("fail 280: -1 should be < NaN", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 281: -1 should be = NaN",}, b0, false, false, "z(", null); +runtime.ext_scratch3_looks._say("fail 281: -1 should be = NaN", target); } if (!(("" + ("-1".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 282: -1 should be > NaN",}, b0, false, false, "z*", null); +runtime.ext_scratch3_looks._say("fail 282: -1 should be > NaN", target); } if (!(("" + (-1 < Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 283: -1 should be < Infinity",}, b0, false, false, "z,", null); +runtime.ext_scratch3_looks._say("fail 283: -1 should be < Infinity", target); } if (!(("" + (-1 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 284: -1 should be = Infinity",}, b0, false, false, "z.", null); +runtime.ext_scratch3_looks._say("fail 284: -1 should be = Infinity", target); } if (!(("" + (-1 > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 285: -1 should be > Infinity",}, b0, false, false, "z:", null); +runtime.ext_scratch3_looks._say("fail 285: -1 should be > Infinity", target); } if (!(("" + ("-1".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 286: -1 should be < banana",}, b0, false, false, "z=", null); +runtime.ext_scratch3_looks._say("fail 286: -1 should be < banana", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 287: -1 should be = banana",}, b0, false, false, "z@", null); +runtime.ext_scratch3_looks._say("fail 287: -1 should be = banana", target); } if (!(("" + ("-1".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 288: -1 should be > banana",}, b0, false, false, "z]", null); +runtime.ext_scratch3_looks._say("fail 288: -1 should be > banana", target); } if (!(("" + ("-1".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 289: -1 should be < 🎉",}, b0, false, false, "z_", null); +runtime.ext_scratch3_looks._say("fail 289: -1 should be < 🎉", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 290: -1 should be = 🎉",}, b0, false, false, "z{", null); +runtime.ext_scratch3_looks._say("fail 290: -1 should be = 🎉", target); } if (!(("" + ("-1".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 291: -1 should be > 🎉",}, b0, false, false, "z}", null); +runtime.ext_scratch3_looks._say("fail 291: -1 should be > 🎉", target); } if (!(("" + ("-1".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 292: -1 should be < ",}, b0, false, false, "Aa", null); +runtime.ext_scratch3_looks._say("fail 292: -1 should be < ", target); } if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 293: -1 should be = ",}, b0, false, false, "Ac", null); +runtime.ext_scratch3_looks._say("fail 293: -1 should be = ", target); } if (!(("" + ("-1".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 294: -1 should be > ",}, b0, false, false, "Ae", null); +runtime.ext_scratch3_looks._say("fail 294: -1 should be > ", target); } if (!(("" + ("true".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 295: true should be < 0",}, b0, false, false, "Ag", null); +runtime.ext_scratch3_looks._say("fail 295: true should be < 0", target); } if (!(("" + ("true".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 296: true should be = 0",}, b0, false, false, "Ai", null); +runtime.ext_scratch3_looks._say("fail 296: true should be = 0", target); } if (!(("" + ("true".toLowerCase() > "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 297: true should be > 0",}, b0, false, false, "Ak", null); +runtime.ext_scratch3_looks._say("fail 297: true should be > 0", target); } if (!(("" + ("true".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 298: true should be < 0.0",}, b0, false, false, "Am", null); +runtime.ext_scratch3_looks._say("fail 298: true should be < 0.0", target); } if (!(("" + ("true".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 299: true should be = 0.0",}, b0, false, false, "Ao", null); +runtime.ext_scratch3_looks._say("fail 299: true should be = 0.0", target); } if (!(("" + ("true".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 300: true should be > 0.0",}, b0, false, false, "Aq", null); +runtime.ext_scratch3_looks._say("fail 300: true should be > 0.0", target); } if (!(("" + ("true".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 301: true should be < 1.23",}, b0, false, false, "As", null); +runtime.ext_scratch3_looks._say("fail 301: true should be < 1.23", target); } if (!(("" + (1 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 302: true should be = 1.23",}, b0, false, false, "Au", null); +runtime.ext_scratch3_looks._say("fail 302: true should be = 1.23", target); } if (!(("" + ("true".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 303: true should be > 1.23",}, b0, false, false, "Aw", null); +runtime.ext_scratch3_looks._say("fail 303: true should be > 1.23", target); } if (!(("" + ("true".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 304: true should be < .23",}, b0, false, false, "Ay", null); +runtime.ext_scratch3_looks._say("fail 304: true should be < .23", target); } if (!(("" + (1 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 305: true should be = .23",}, b0, false, false, "AA", null); +runtime.ext_scratch3_looks._say("fail 305: true should be = .23", target); } if (!(("" + ("true".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 306: true should be > .23",}, b0, false, false, "AC", null); +runtime.ext_scratch3_looks._say("fail 306: true should be > .23", target); } if (!(("" + ("true".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 307: true should be < 0.123",}, b0, false, false, "AE", null); +runtime.ext_scratch3_looks._say("fail 307: true should be < 0.123", target); } if (!(("" + (1 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 308: true should be = 0.123",}, b0, false, false, "AG", null); +runtime.ext_scratch3_looks._say("fail 308: true should be = 0.123", target); } if (!(("" + ("true".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 309: true should be > 0.123",}, b0, false, false, "AI", null); +runtime.ext_scratch3_looks._say("fail 309: true should be > 0.123", target); } if (!(("" + ("true".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 310: true should be < -0",}, b0, false, false, "AK", null); +runtime.ext_scratch3_looks._say("fail 310: true should be < -0", target); } if (!(("" + ("true".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 311: true should be = -0",}, b0, false, false, "AM", null); +runtime.ext_scratch3_looks._say("fail 311: true should be = -0", target); } if (!(("" + ("true".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 312: true should be > -0",}, b0, false, false, "AO", null); +runtime.ext_scratch3_looks._say("fail 312: true should be > -0", target); } if (!(("" + ("true".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 313: true should be < -1",}, b0, false, false, "AQ", null); +runtime.ext_scratch3_looks._say("fail 313: true should be < -1", target); } if (!(("" + (1 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 314: true should be = -1",}, b0, false, false, "AS", null); +runtime.ext_scratch3_looks._say("fail 314: true should be = -1", target); } if (!(("" + ("true".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 315: true should be > -1",}, b0, false, false, "AU", null); +runtime.ext_scratch3_looks._say("fail 315: true should be > -1", target); } if (!(("" + ("true".toLowerCase() < "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 316: true should be < true",}, b0, false, false, "AW", null); +runtime.ext_scratch3_looks._say("fail 316: true should be < true", target); } if (!(("" + ("true".toLowerCase() === "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 317: true should be = true",}, b0, false, false, "AY", null); +runtime.ext_scratch3_looks._say("fail 317: true should be = true", target); } if (!(("" + ("true".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 318: true should be > true",}, b0, false, false, "A0", null); +runtime.ext_scratch3_looks._say("fail 318: true should be > true", target); } if (!(("" + ("true".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 319: true should be < false",}, b0, false, false, "A2", null); +runtime.ext_scratch3_looks._say("fail 319: true should be < false", target); } if (!(("" + ("true".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 320: true should be = false",}, b0, false, false, "A4", null); +runtime.ext_scratch3_looks._say("fail 320: true should be = false", target); } if (!(("" + ("true".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 321: true should be > false",}, b0, false, false, "A6", null); +runtime.ext_scratch3_looks._say("fail 321: true should be > false", target); } if (!(("" + ("true".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 322: true should be < NaN",}, b0, false, false, "A8", null); +runtime.ext_scratch3_looks._say("fail 322: true should be < NaN", target); } if (!(("" + ("true".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 323: true should be = NaN",}, b0, false, false, "A!", null); +runtime.ext_scratch3_looks._say("fail 323: true should be = NaN", target); } if (!(("" + ("true".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 324: true should be > NaN",}, b0, false, false, "A%", null); +runtime.ext_scratch3_looks._say("fail 324: true should be > NaN", target); } if (!(("" + ("true".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 325: true should be < Infinity",}, b0, false, false, "A)", null); +runtime.ext_scratch3_looks._say("fail 325: true should be < Infinity", target); } if (!(("" + (1 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 326: true should be = Infinity",}, b0, false, false, "A+", null); +runtime.ext_scratch3_looks._say("fail 326: true should be = Infinity", target); } if (!(("" + ("true".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 327: true should be > Infinity",}, b0, false, false, "A-", null); +runtime.ext_scratch3_looks._say("fail 327: true should be > Infinity", target); } if (!(("" + ("true".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 328: true should be < banana",}, b0, false, false, "A/", null); +runtime.ext_scratch3_looks._say("fail 328: true should be < banana", target); } if (!(("" + ("true".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 329: true should be = banana",}, b0, false, false, "A;", null); +runtime.ext_scratch3_looks._say("fail 329: true should be = banana", target); } if (!(("" + ("true".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 330: true should be > banana",}, b0, false, false, "A?", null); +runtime.ext_scratch3_looks._say("fail 330: true should be > banana", target); } if (!(("" + ("true".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 331: true should be < 🎉",}, b0, false, false, "A[", null); +runtime.ext_scratch3_looks._say("fail 331: true should be < 🎉", target); } if (!(("" + ("true".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 332: true should be = 🎉",}, b0, false, false, "A^", null); +runtime.ext_scratch3_looks._say("fail 332: true should be = 🎉", target); } if (!(("" + ("true".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 333: true should be > 🎉",}, b0, false, false, "A`", null); +runtime.ext_scratch3_looks._say("fail 333: true should be > 🎉", target); } if (!(("" + ("true".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 334: true should be < ",}, b0, false, false, "A|", null); +runtime.ext_scratch3_looks._say("fail 334: true should be < ", target); } if (!(("" + ("true".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 335: true should be = ",}, b0, false, false, "A~", null); +runtime.ext_scratch3_looks._say("fail 335: true should be = ", target); } if (!(("" + ("true".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 336: true should be > ",}, b0, false, false, "Bb", null); +runtime.ext_scratch3_looks._say("fail 336: true should be > ", target); } if (!(("" + ("false".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 337: false should be < 0",}, b0, false, false, "Bd", null); +runtime.ext_scratch3_looks._say("fail 337: false should be < 0", target); } if (!(("" + ("false".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 338: false should be = 0",}, b0, false, false, "Bf", null); +runtime.ext_scratch3_looks._say("fail 338: false should be = 0", target); } if (!(("" + ("false".toLowerCase() > "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 339: false should be > 0",}, b0, false, false, "Bh", null); +runtime.ext_scratch3_looks._say("fail 339: false should be > 0", target); } if (!(("" + ("false".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 340: false should be < 0.0",}, b0, false, false, "Bj", null); +runtime.ext_scratch3_looks._say("fail 340: false should be < 0.0", target); } if (!(("" + ("false".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 341: false should be = 0.0",}, b0, false, false, "Bl", null); +runtime.ext_scratch3_looks._say("fail 341: false should be = 0.0", target); } if (!(("" + ("false".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 342: false should be > 0.0",}, b0, false, false, "Bn", null); +runtime.ext_scratch3_looks._say("fail 342: false should be > 0.0", target); } if (!(("" + ("false".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 343: false should be < 1.23",}, b0, false, false, "Bp", null); +runtime.ext_scratch3_looks._say("fail 343: false should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 344: false should be = 1.23",}, b0, false, false, "Br", null); +runtime.ext_scratch3_looks._say("fail 344: false should be = 1.23", target); } if (!(("" + ("false".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 345: false should be > 1.23",}, b0, false, false, "Bt", null); +runtime.ext_scratch3_looks._say("fail 345: false should be > 1.23", target); } if (!(("" + ("false".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 346: false should be < .23",}, b0, false, false, "Bv", null); +runtime.ext_scratch3_looks._say("fail 346: false should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 347: false should be = .23",}, b0, false, false, "Bx", null); +runtime.ext_scratch3_looks._say("fail 347: false should be = .23", target); } if (!(("" + ("false".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 348: false should be > .23",}, b0, false, false, "Bz", null); +runtime.ext_scratch3_looks._say("fail 348: false should be > .23", target); } if (!(("" + ("false".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 349: false should be < 0.123",}, b0, false, false, "BB", null); +runtime.ext_scratch3_looks._say("fail 349: false should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 350: false should be = 0.123",}, b0, false, false, "BD", null); +runtime.ext_scratch3_looks._say("fail 350: false should be = 0.123", target); } if (!(("" + ("false".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 351: false should be > 0.123",}, b0, false, false, "BF", null); +runtime.ext_scratch3_looks._say("fail 351: false should be > 0.123", target); } if (!(("" + ("false".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 352: false should be < -0",}, b0, false, false, "BH", null); +runtime.ext_scratch3_looks._say("fail 352: false should be < -0", target); } if (!(("" + ("false".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 353: false should be = -0",}, b0, false, false, "BJ", null); +runtime.ext_scratch3_looks._say("fail 353: false should be = -0", target); } if (!(("" + ("false".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 354: false should be > -0",}, b0, false, false, "BL", null); +runtime.ext_scratch3_looks._say("fail 354: false should be > -0", target); } if (!(("" + ("false".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 355: false should be < -1",}, b0, false, false, "BN", null); +runtime.ext_scratch3_looks._say("fail 355: false should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 356: false should be = -1",}, b0, false, false, "BP", null); +runtime.ext_scratch3_looks._say("fail 356: false should be = -1", target); } if (!(("" + ("false".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 357: false should be > -1",}, b0, false, false, "BR", null); +runtime.ext_scratch3_looks._say("fail 357: false should be > -1", target); } if (!(("" + ("false".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 358: false should be < true",}, b0, false, false, "BT", null); +runtime.ext_scratch3_looks._say("fail 358: false should be < true", target); } if (!(("" + ("false".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 359: false should be = true",}, b0, false, false, "BV", null); +runtime.ext_scratch3_looks._say("fail 359: false should be = true", target); } if (!(("" + ("false".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 360: false should be > true",}, b0, false, false, "BX", null); +runtime.ext_scratch3_looks._say("fail 360: false should be > true", target); } if (!(("" + ("false".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 361: false should be < false",}, b0, false, false, "BZ", null); +runtime.ext_scratch3_looks._say("fail 361: false should be < false", target); } if (!(("" + ("false".toLowerCase() === "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 362: false should be = false",}, b0, false, false, "B1", null); +runtime.ext_scratch3_looks._say("fail 362: false should be = false", target); } if (!(("" + ("false".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 363: false should be > false",}, b0, false, false, "B3", null); +runtime.ext_scratch3_looks._say("fail 363: false should be > false", target); } if (!(("" + ("false".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 364: false should be < NaN",}, b0, false, false, "B5", null); +runtime.ext_scratch3_looks._say("fail 364: false should be < NaN", target); } if (!(("" + ("false".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 365: false should be = NaN",}, b0, false, false, "B7", null); +runtime.ext_scratch3_looks._say("fail 365: false should be = NaN", target); } if (!(("" + ("false".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 366: false should be > NaN",}, b0, false, false, "B9", null); +runtime.ext_scratch3_looks._say("fail 366: false should be > NaN", target); } if (!(("" + ("false".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 367: false should be < Infinity",}, b0, false, false, "B#", null); +runtime.ext_scratch3_looks._say("fail 367: false should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 368: false should be = Infinity",}, b0, false, false, "B(", null); +runtime.ext_scratch3_looks._say("fail 368: false should be = Infinity", target); } if (!(("" + ("false".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 369: false should be > Infinity",}, b0, false, false, "B*", null); +runtime.ext_scratch3_looks._say("fail 369: false should be > Infinity", target); } if (!(("" + ("false".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 370: false should be < banana",}, b0, false, false, "B,", null); +runtime.ext_scratch3_looks._say("fail 370: false should be < banana", target); } if (!(("" + ("false".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 371: false should be = banana",}, b0, false, false, "B.", null); +runtime.ext_scratch3_looks._say("fail 371: false should be = banana", target); } if (!(("" + ("false".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 372: false should be > banana",}, b0, false, false, "B:", null); +runtime.ext_scratch3_looks._say("fail 372: false should be > banana", target); } if (!(("" + ("false".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 373: false should be < 🎉",}, b0, false, false, "B=", null); +runtime.ext_scratch3_looks._say("fail 373: false should be < 🎉", target); } if (!(("" + ("false".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 374: false should be = 🎉",}, b0, false, false, "B@", null); +runtime.ext_scratch3_looks._say("fail 374: false should be = 🎉", target); } if (!(("" + ("false".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 375: false should be > 🎉",}, b0, false, false, "B]", null); +runtime.ext_scratch3_looks._say("fail 375: false should be > 🎉", target); } if (!(("" + ("false".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 376: false should be < ",}, b0, false, false, "B_", null); +runtime.ext_scratch3_looks._say("fail 376: false should be < ", target); } if (!(("" + ("false".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 377: false should be = ",}, b0, false, false, "B{", null); +runtime.ext_scratch3_looks._say("fail 377: false should be = ", target); } if (!(("" + ("false".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 378: false should be > ",}, b0, false, false, "B}", null); +runtime.ext_scratch3_looks._say("fail 378: false should be > ", target); } if (!(("" + ("NaN".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 379: NaN should be < 0",}, b0, false, false, "Ca", null); +runtime.ext_scratch3_looks._say("fail 379: NaN should be < 0", target); } if (!(("" + ("NaN".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 380: NaN should be = 0",}, b0, false, false, "Cc", null); +runtime.ext_scratch3_looks._say("fail 380: NaN should be = 0", target); } if (!(("" + ("NaN".toLowerCase() > "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 381: NaN should be > 0",}, b0, false, false, "Ce", null); +runtime.ext_scratch3_looks._say("fail 381: NaN should be > 0", target); } if (!(("" + ("NaN".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 382: NaN should be < 0.0",}, b0, false, false, "Cg", null); +runtime.ext_scratch3_looks._say("fail 382: NaN should be < 0.0", target); } if (!(("" + ("NaN".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 383: NaN should be = 0.0",}, b0, false, false, "Ci", null); +runtime.ext_scratch3_looks._say("fail 383: NaN should be = 0.0", target); } if (!(("" + ("NaN".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 384: NaN should be > 0.0",}, b0, false, false, "Ck", null); +runtime.ext_scratch3_looks._say("fail 384: NaN should be > 0.0", target); } if (!(("" + ("NaN".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 385: NaN should be < 1.23",}, b0, false, false, "Cm", null); +runtime.ext_scratch3_looks._say("fail 385: NaN should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 386: NaN should be = 1.23",}, b0, false, false, "Co", null); +runtime.ext_scratch3_looks._say("fail 386: NaN should be = 1.23", target); } if (!(("" + ("NaN".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 387: NaN should be > 1.23",}, b0, false, false, "Cq", null); +runtime.ext_scratch3_looks._say("fail 387: NaN should be > 1.23", target); } if (!(("" + ("NaN".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 388: NaN should be < .23",}, b0, false, false, "Cs", null); +runtime.ext_scratch3_looks._say("fail 388: NaN should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 389: NaN should be = .23",}, b0, false, false, "Cu", null); +runtime.ext_scratch3_looks._say("fail 389: NaN should be = .23", target); } if (!(("" + ("NaN".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 390: NaN should be > .23",}, b0, false, false, "Cw", null); +runtime.ext_scratch3_looks._say("fail 390: NaN should be > .23", target); } if (!(("" + ("NaN".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 391: NaN should be < 0.123",}, b0, false, false, "Cy", null); +runtime.ext_scratch3_looks._say("fail 391: NaN should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 392: NaN should be = 0.123",}, b0, false, false, "CA", null); +runtime.ext_scratch3_looks._say("fail 392: NaN should be = 0.123", target); } if (!(("" + ("NaN".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 393: NaN should be > 0.123",}, b0, false, false, "CC", null); +runtime.ext_scratch3_looks._say("fail 393: NaN should be > 0.123", target); } if (!(("" + ("NaN".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 394: NaN should be < -0",}, b0, false, false, "CE", null); +runtime.ext_scratch3_looks._say("fail 394: NaN should be < -0", target); } if (!(("" + ("NaN".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 395: NaN should be = -0",}, b0, false, false, "CG", null); +runtime.ext_scratch3_looks._say("fail 395: NaN should be = -0", target); } if (!(("" + ("NaN".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 396: NaN should be > -0",}, b0, false, false, "CI", null); +runtime.ext_scratch3_looks._say("fail 396: NaN should be > -0", target); } if (!(("" + ("NaN".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 397: NaN should be < -1",}, b0, false, false, "CK", null); +runtime.ext_scratch3_looks._say("fail 397: NaN should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 398: NaN should be = -1",}, b0, false, false, "CM", null); +runtime.ext_scratch3_looks._say("fail 398: NaN should be = -1", target); } if (!(("" + ("NaN".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 399: NaN should be > -1",}, b0, false, false, "CO", null); +runtime.ext_scratch3_looks._say("fail 399: NaN should be > -1", target); } if (!(("" + ("NaN".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 400: NaN should be < true",}, b0, false, false, "CQ", null); +runtime.ext_scratch3_looks._say("fail 400: NaN should be < true", target); } if (!(("" + ("NaN".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 401: NaN should be = true",}, b0, false, false, "CS", null); +runtime.ext_scratch3_looks._say("fail 401: NaN should be = true", target); } if (!(("" + ("NaN".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 402: NaN should be > true",}, b0, false, false, "CU", null); +runtime.ext_scratch3_looks._say("fail 402: NaN should be > true", target); } if (!(("" + ("NaN".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 403: NaN should be < false",}, b0, false, false, "CW", null); +runtime.ext_scratch3_looks._say("fail 403: NaN should be < false", target); } if (!(("" + ("NaN".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 404: NaN should be = false",}, b0, false, false, "CY", null); +runtime.ext_scratch3_looks._say("fail 404: NaN should be = false", target); } if (!(("" + ("NaN".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 405: NaN should be > false",}, b0, false, false, "C0", null); +runtime.ext_scratch3_looks._say("fail 405: NaN should be > false", target); } if (!(("" + ("NaN".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 406: NaN should be < NaN",}, b0, false, false, "C2", null); +runtime.ext_scratch3_looks._say("fail 406: NaN should be < NaN", target); } if (!(("" + ("NaN".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 407: NaN should be = NaN",}, b0, false, false, "C4", null); +runtime.ext_scratch3_looks._say("fail 407: NaN should be = NaN", target); } if (!(("" + ("NaN".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 408: NaN should be > NaN",}, b0, false, false, "C6", null); +runtime.ext_scratch3_looks._say("fail 408: NaN should be > NaN", target); } if (!(("" + ("NaN".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 409: NaN should be < Infinity",}, b0, false, false, "C8", null); +runtime.ext_scratch3_looks._say("fail 409: NaN should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 410: NaN should be = Infinity",}, b0, false, false, "C!", null); +runtime.ext_scratch3_looks._say("fail 410: NaN should be = Infinity", target); } if (!(("" + ("NaN".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 411: NaN should be > Infinity",}, b0, false, false, "C%", null); +runtime.ext_scratch3_looks._say("fail 411: NaN should be > Infinity", target); } if (!(("" + ("NaN".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 412: NaN should be < banana",}, b0, false, false, "C)", null); +runtime.ext_scratch3_looks._say("fail 412: NaN should be < banana", target); } if (!(("" + ("NaN".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 413: NaN should be = banana",}, b0, false, false, "C+", null); +runtime.ext_scratch3_looks._say("fail 413: NaN should be = banana", target); } if (!(("" + ("NaN".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 414: NaN should be > banana",}, b0, false, false, "C-", null); +runtime.ext_scratch3_looks._say("fail 414: NaN should be > banana", target); } if (!(("" + ("NaN".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 415: NaN should be < 🎉",}, b0, false, false, "C/", null); +runtime.ext_scratch3_looks._say("fail 415: NaN should be < 🎉", target); } if (!(("" + ("NaN".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 416: NaN should be = 🎉",}, b0, false, false, "C;", null); +runtime.ext_scratch3_looks._say("fail 416: NaN should be = 🎉", target); } if (!(("" + ("NaN".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 417: NaN should be > 🎉",}, b0, false, false, "C?", null); +runtime.ext_scratch3_looks._say("fail 417: NaN should be > 🎉", target); } if (!(("" + ("NaN".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 418: NaN should be < ",}, b0, false, false, "C[", null); +runtime.ext_scratch3_looks._say("fail 418: NaN should be < ", target); } if (!(("" + ("NaN".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 419: NaN should be = ",}, b0, false, false, "C^", null); +runtime.ext_scratch3_looks._say("fail 419: NaN should be = ", target); } if (!(("" + ("NaN".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 420: NaN should be > ",}, b0, false, false, "C`", null); +runtime.ext_scratch3_looks._say("fail 420: NaN should be > ", target); } if (!(("" + (Infinity < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 421: Infinity should be < 0",}, b0, false, false, "C|", null); +runtime.ext_scratch3_looks._say("fail 421: Infinity should be < 0", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 422: Infinity should be = 0",}, b0, false, false, "C~", null); +runtime.ext_scratch3_looks._say("fail 422: Infinity should be = 0", target); } if (!(("" + (Infinity > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 423: Infinity should be > 0",}, b0, false, false, "Db", null); +runtime.ext_scratch3_looks._say("fail 423: Infinity should be > 0", target); } if (!(("" + (Infinity < 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 424: Infinity should be < 0.0",}, b0, false, false, "Dd", null); +runtime.ext_scratch3_looks._say("fail 424: Infinity should be < 0.0", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 425: Infinity should be = 0.0",}, b0, false, false, "Df", null); +runtime.ext_scratch3_looks._say("fail 425: Infinity should be = 0.0", target); } if (!(("" + (Infinity > 0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 426: Infinity should be > 0.0",}, b0, false, false, "Dh", null); +runtime.ext_scratch3_looks._say("fail 426: Infinity should be > 0.0", target); } if (!(("" + (Infinity < 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 427: Infinity should be < 1.23",}, b0, false, false, "Dj", null); +runtime.ext_scratch3_looks._say("fail 427: Infinity should be < 1.23", target); } if (!(("" + (Infinity === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 428: Infinity should be = 1.23",}, b0, false, false, "Dl", null); +runtime.ext_scratch3_looks._say("fail 428: Infinity should be = 1.23", target); } if (!(("" + (Infinity > 1.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 429: Infinity should be > 1.23",}, b0, false, false, "Dn", null); +runtime.ext_scratch3_looks._say("fail 429: Infinity should be > 1.23", target); } if (!(("" + (Infinity < 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 430: Infinity should be < .23",}, b0, false, false, "Dp", null); +runtime.ext_scratch3_looks._say("fail 430: Infinity should be < .23", target); } if (!(("" + (Infinity === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 431: Infinity should be = .23",}, b0, false, false, "Dr", null); +runtime.ext_scratch3_looks._say("fail 431: Infinity should be = .23", target); } if (!(("" + (Infinity > 0.23)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 432: Infinity should be > .23",}, b0, false, false, "Dt", null); +runtime.ext_scratch3_looks._say("fail 432: Infinity should be > .23", target); } if (!(("" + (Infinity < 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 433: Infinity should be < 0.123",}, b0, false, false, "Dv", null); +runtime.ext_scratch3_looks._say("fail 433: Infinity should be < 0.123", target); } if (!(("" + (Infinity === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 434: Infinity should be = 0.123",}, b0, false, false, "Dx", null); +runtime.ext_scratch3_looks._say("fail 434: Infinity should be = 0.123", target); } if (!(("" + (Infinity > 0.123)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 435: Infinity should be > 0.123",}, b0, false, false, "Dz", null); +runtime.ext_scratch3_looks._say("fail 435: Infinity should be > 0.123", target); } if (!(("" + (Infinity < -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 436: Infinity should be < -0",}, b0, false, false, "DB", null); +runtime.ext_scratch3_looks._say("fail 436: Infinity should be < -0", target); } if (!(("" + (Infinity === -0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 437: Infinity should be = -0",}, b0, false, false, "DD", null); +runtime.ext_scratch3_looks._say("fail 437: Infinity should be = -0", target); } if (!(("" + (Infinity > -0)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 438: Infinity should be > -0",}, b0, false, false, "DF", null); +runtime.ext_scratch3_looks._say("fail 438: Infinity should be > -0", target); } if (!(("" + (Infinity < -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 439: Infinity should be < -1",}, b0, false, false, "DH", null); +runtime.ext_scratch3_looks._say("fail 439: Infinity should be < -1", target); } if (!(("" + (Infinity === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 440: Infinity should be = -1",}, b0, false, false, "DJ", null); +runtime.ext_scratch3_looks._say("fail 440: Infinity should be = -1", target); } if (!(("" + (Infinity > -1)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 441: Infinity should be > -1",}, b0, false, false, "DL", null); +runtime.ext_scratch3_looks._say("fail 441: Infinity should be > -1", target); } if (!(("" + ("Infinity".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 442: Infinity should be < true",}, b0, false, false, "DN", null); +runtime.ext_scratch3_looks._say("fail 442: Infinity should be < true", target); } if (!(("" + (Infinity === 1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 443: Infinity should be = true",}, b0, false, false, "DP", null); +runtime.ext_scratch3_looks._say("fail 443: Infinity should be = true", target); } if (!(("" + ("Infinity".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 444: Infinity should be > true",}, b0, false, false, "DR", null); +runtime.ext_scratch3_looks._say("fail 444: Infinity should be > true", target); } if (!(("" + ("Infinity".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 445: Infinity should be < false",}, b0, false, false, "DT", null); +runtime.ext_scratch3_looks._say("fail 445: Infinity should be < false", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 446: Infinity should be = false",}, b0, false, false, "DV", null); +runtime.ext_scratch3_looks._say("fail 446: Infinity should be = false", target); } if (!(("" + ("Infinity".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 447: Infinity should be > false",}, b0, false, false, "DX", null); +runtime.ext_scratch3_looks._say("fail 447: Infinity should be > false", target); } if (!(("" + ("Infinity".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 448: Infinity should be < NaN",}, b0, false, false, "DZ", null); +runtime.ext_scratch3_looks._say("fail 448: Infinity should be < NaN", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 449: Infinity should be = NaN",}, b0, false, false, "D1", null); +runtime.ext_scratch3_looks._say("fail 449: Infinity should be = NaN", target); } if (!(("" + ("Infinity".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 450: Infinity should be > NaN",}, b0, false, false, "D3", null); +runtime.ext_scratch3_looks._say("fail 450: Infinity should be > NaN", target); } if (!(("" + (Infinity < Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 451: Infinity should be < Infinity",}, b0, false, false, "D5", null); +runtime.ext_scratch3_looks._say("fail 451: Infinity should be < Infinity", target); } if (!(("" + (Infinity === Infinity)).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 452: Infinity should be = Infinity",}, b0, false, false, "D7", null); +runtime.ext_scratch3_looks._say("fail 452: Infinity should be = Infinity", target); } if (!(("" + (Infinity > Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 453: Infinity should be > Infinity",}, b0, false, false, "D9", null); +runtime.ext_scratch3_looks._say("fail 453: Infinity should be > Infinity", target); } if (!(("" + ("Infinity".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 454: Infinity should be < banana",}, b0, false, false, "D#", null); +runtime.ext_scratch3_looks._say("fail 454: Infinity should be < banana", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 455: Infinity should be = banana",}, b0, false, false, "D(", null); +runtime.ext_scratch3_looks._say("fail 455: Infinity should be = banana", target); } if (!(("" + ("Infinity".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 456: Infinity should be > banana",}, b0, false, false, "D*", null); +runtime.ext_scratch3_looks._say("fail 456: Infinity should be > banana", target); } if (!(("" + ("Infinity".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 457: Infinity should be < 🎉",}, b0, false, false, "D,", null); +runtime.ext_scratch3_looks._say("fail 457: Infinity should be < 🎉", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 458: Infinity should be = 🎉",}, b0, false, false, "D.", null); +runtime.ext_scratch3_looks._say("fail 458: Infinity should be = 🎉", target); } if (!(("" + ("Infinity".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 459: Infinity should be > 🎉",}, b0, false, false, "D:", null); +runtime.ext_scratch3_looks._say("fail 459: Infinity should be > 🎉", target); } if (!(("" + ("Infinity".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 460: Infinity should be < ",}, b0, false, false, "D=", null); +runtime.ext_scratch3_looks._say("fail 460: Infinity should be < ", target); } if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 461: Infinity should be = ",}, b0, false, false, "D@", null); +runtime.ext_scratch3_looks._say("fail 461: Infinity should be = ", target); } if (!(("" + ("Infinity".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 462: Infinity should be > ",}, b0, false, false, "D]", null); +runtime.ext_scratch3_looks._say("fail 462: Infinity should be > ", target); } if (!(("" + ("banana".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 463: banana should be < 0",}, b0, false, false, "D_", null); +runtime.ext_scratch3_looks._say("fail 463: banana should be < 0", target); } if (!(("" + ("banana".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 464: banana should be = 0",}, b0, false, false, "D{", null); +runtime.ext_scratch3_looks._say("fail 464: banana should be = 0", target); } if (!(("" + ("banana".toLowerCase() > "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 465: banana should be > 0",}, b0, false, false, "D}", null); +runtime.ext_scratch3_looks._say("fail 465: banana should be > 0", target); } if (!(("" + ("banana".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 466: banana should be < 0.0",}, b0, false, false, "Ea", null); +runtime.ext_scratch3_looks._say("fail 466: banana should be < 0.0", target); } if (!(("" + ("banana".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 467: banana should be = 0.0",}, b0, false, false, "Ec", null); +runtime.ext_scratch3_looks._say("fail 467: banana should be = 0.0", target); } if (!(("" + ("banana".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 468: banana should be > 0.0",}, b0, false, false, "Ee", null); +runtime.ext_scratch3_looks._say("fail 468: banana should be > 0.0", target); } if (!(("" + ("banana".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 469: banana should be < 1.23",}, b0, false, false, "Eg", null); +runtime.ext_scratch3_looks._say("fail 469: banana should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 470: banana should be = 1.23",}, b0, false, false, "Ei", null); +runtime.ext_scratch3_looks._say("fail 470: banana should be = 1.23", target); } if (!(("" + ("banana".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 471: banana should be > 1.23",}, b0, false, false, "Ek", null); +runtime.ext_scratch3_looks._say("fail 471: banana should be > 1.23", target); } if (!(("" + ("banana".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 472: banana should be < .23",}, b0, false, false, "Em", null); +runtime.ext_scratch3_looks._say("fail 472: banana should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 473: banana should be = .23",}, b0, false, false, "Eo", null); +runtime.ext_scratch3_looks._say("fail 473: banana should be = .23", target); } if (!(("" + ("banana".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 474: banana should be > .23",}, b0, false, false, "Eq", null); +runtime.ext_scratch3_looks._say("fail 474: banana should be > .23", target); } if (!(("" + ("banana".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 475: banana should be < 0.123",}, b0, false, false, "Es", null); +runtime.ext_scratch3_looks._say("fail 475: banana should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 476: banana should be = 0.123",}, b0, false, false, "Eu", null); +runtime.ext_scratch3_looks._say("fail 476: banana should be = 0.123", target); } if (!(("" + ("banana".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 477: banana should be > 0.123",}, b0, false, false, "Ew", null); +runtime.ext_scratch3_looks._say("fail 477: banana should be > 0.123", target); } if (!(("" + ("banana".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 478: banana should be < -0",}, b0, false, false, "Ey", null); +runtime.ext_scratch3_looks._say("fail 478: banana should be < -0", target); } if (!(("" + ("banana".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 479: banana should be = -0",}, b0, false, false, "EA", null); +runtime.ext_scratch3_looks._say("fail 479: banana should be = -0", target); } if (!(("" + ("banana".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 480: banana should be > -0",}, b0, false, false, "EC", null); +runtime.ext_scratch3_looks._say("fail 480: banana should be > -0", target); } if (!(("" + ("banana".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 481: banana should be < -1",}, b0, false, false, "EE", null); +runtime.ext_scratch3_looks._say("fail 481: banana should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 482: banana should be = -1",}, b0, false, false, "EG", null); +runtime.ext_scratch3_looks._say("fail 482: banana should be = -1", target); } if (!(("" + ("banana".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 483: banana should be > -1",}, b0, false, false, "EI", null); +runtime.ext_scratch3_looks._say("fail 483: banana should be > -1", target); } if (!(("" + ("banana".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 484: banana should be < true",}, b0, false, false, "EK", null); +runtime.ext_scratch3_looks._say("fail 484: banana should be < true", target); } if (!(("" + ("banana".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 485: banana should be = true",}, b0, false, false, "EM", null); +runtime.ext_scratch3_looks._say("fail 485: banana should be = true", target); } if (!(("" + ("banana".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 486: banana should be > true",}, b0, false, false, "EO", null); +runtime.ext_scratch3_looks._say("fail 486: banana should be > true", target); } if (!(("" + ("banana".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 487: banana should be < false",}, b0, false, false, "EQ", null); +runtime.ext_scratch3_looks._say("fail 487: banana should be < false", target); } if (!(("" + ("banana".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 488: banana should be = false",}, b0, false, false, "ES", null); +runtime.ext_scratch3_looks._say("fail 488: banana should be = false", target); } if (!(("" + ("banana".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 489: banana should be > false",}, b0, false, false, "EU", null); +runtime.ext_scratch3_looks._say("fail 489: banana should be > false", target); } if (!(("" + ("banana".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 490: banana should be < NaN",}, b0, false, false, "EW", null); +runtime.ext_scratch3_looks._say("fail 490: banana should be < NaN", target); } if (!(("" + ("banana".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 491: banana should be = NaN",}, b0, false, false, "EY", null); +runtime.ext_scratch3_looks._say("fail 491: banana should be = NaN", target); } if (!(("" + ("banana".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 492: banana should be > NaN",}, b0, false, false, "E0", null); +runtime.ext_scratch3_looks._say("fail 492: banana should be > NaN", target); } if (!(("" + ("banana".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 493: banana should be < Infinity",}, b0, false, false, "E2", null); +runtime.ext_scratch3_looks._say("fail 493: banana should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 494: banana should be = Infinity",}, b0, false, false, "E4", null); +runtime.ext_scratch3_looks._say("fail 494: banana should be = Infinity", target); } if (!(("" + ("banana".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 495: banana should be > Infinity",}, b0, false, false, "E6", null); +runtime.ext_scratch3_looks._say("fail 495: banana should be > Infinity", target); } if (!(("" + ("banana".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 496: banana should be < banana",}, b0, false, false, "E8", null); +runtime.ext_scratch3_looks._say("fail 496: banana should be < banana", target); } if (!(("" + ("banana".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 497: banana should be = banana",}, b0, false, false, "E!", null); +runtime.ext_scratch3_looks._say("fail 497: banana should be = banana", target); } if (!(("" + ("banana".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 498: banana should be > banana",}, b0, false, false, "E%", null); +runtime.ext_scratch3_looks._say("fail 498: banana should be > banana", target); } if (!(("" + ("banana".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 499: banana should be < 🎉",}, b0, false, false, "E)", null); +runtime.ext_scratch3_looks._say("fail 499: banana should be < 🎉", target); } if (!(("" + ("banana".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 500: banana should be = 🎉",}, b0, false, false, "E+", null); +runtime.ext_scratch3_looks._say("fail 500: banana should be = 🎉", target); } if (!(("" + ("banana".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 501: banana should be > 🎉",}, b0, false, false, "E-", null); +runtime.ext_scratch3_looks._say("fail 501: banana should be > 🎉", target); } if (!(("" + ("banana".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 502: banana should be < ",}, b0, false, false, "E/", null); +runtime.ext_scratch3_looks._say("fail 502: banana should be < ", target); } if (!(("" + ("banana".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 503: banana should be = ",}, b0, false, false, "E;", null); +runtime.ext_scratch3_looks._say("fail 503: banana should be = ", target); } if (!(("" + ("banana".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 504: banana should be > ",}, b0, false, false, "E?", null); +runtime.ext_scratch3_looks._say("fail 504: banana should be > ", target); } if (!(("" + ("🎉".toLowerCase() < "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 505: 🎉 should be < 0",}, b0, false, false, "E[", null); +runtime.ext_scratch3_looks._say("fail 505: 🎉 should be < 0", target); } if (!(("" + ("🎉".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 506: 🎉 should be = 0",}, b0, false, false, "E^", null); +runtime.ext_scratch3_looks._say("fail 506: 🎉 should be = 0", target); } if (!(("" + ("🎉".toLowerCase() > "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 507: 🎉 should be > 0",}, b0, false, false, "E`", null); +runtime.ext_scratch3_looks._say("fail 507: 🎉 should be > 0", target); } if (!(("" + ("🎉".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 508: 🎉 should be < 0.0",}, b0, false, false, "E|", null); +runtime.ext_scratch3_looks._say("fail 508: 🎉 should be < 0.0", target); } if (!(("" + ("🎉".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 509: 🎉 should be = 0.0",}, b0, false, false, "E~", null); +runtime.ext_scratch3_looks._say("fail 509: 🎉 should be = 0.0", target); } if (!(("" + ("🎉".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 510: 🎉 should be > 0.0",}, b0, false, false, "Fb", null); +runtime.ext_scratch3_looks._say("fail 510: 🎉 should be > 0.0", target); } if (!(("" + ("🎉".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 511: 🎉 should be < 1.23",}, b0, false, false, "Fd", null); +runtime.ext_scratch3_looks._say("fail 511: 🎉 should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 512: 🎉 should be = 1.23",}, b0, false, false, "Ff", null); +runtime.ext_scratch3_looks._say("fail 512: 🎉 should be = 1.23", target); } if (!(("" + ("🎉".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 513: 🎉 should be > 1.23",}, b0, false, false, "Fh", null); +runtime.ext_scratch3_looks._say("fail 513: 🎉 should be > 1.23", target); } if (!(("" + ("🎉".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 514: 🎉 should be < .23",}, b0, false, false, "Fj", null); +runtime.ext_scratch3_looks._say("fail 514: 🎉 should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 515: 🎉 should be = .23",}, b0, false, false, "Fl", null); +runtime.ext_scratch3_looks._say("fail 515: 🎉 should be = .23", target); } if (!(("" + ("🎉".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 516: 🎉 should be > .23",}, b0, false, false, "Fn", null); +runtime.ext_scratch3_looks._say("fail 516: 🎉 should be > .23", target); } if (!(("" + ("🎉".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 517: 🎉 should be < 0.123",}, b0, false, false, "Fp", null); +runtime.ext_scratch3_looks._say("fail 517: 🎉 should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 518: 🎉 should be = 0.123",}, b0, false, false, "Fr", null); +runtime.ext_scratch3_looks._say("fail 518: 🎉 should be = 0.123", target); } if (!(("" + ("🎉".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 519: 🎉 should be > 0.123",}, b0, false, false, "Ft", null); +runtime.ext_scratch3_looks._say("fail 519: 🎉 should be > 0.123", target); } if (!(("" + ("🎉".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 520: 🎉 should be < -0",}, b0, false, false, "Fv", null); +runtime.ext_scratch3_looks._say("fail 520: 🎉 should be < -0", target); } if (!(("" + ("🎉".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 521: 🎉 should be = -0",}, b0, false, false, "Fx", null); +runtime.ext_scratch3_looks._say("fail 521: 🎉 should be = -0", target); } if (!(("" + ("🎉".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 522: 🎉 should be > -0",}, b0, false, false, "Fz", null); +runtime.ext_scratch3_looks._say("fail 522: 🎉 should be > -0", target); } if (!(("" + ("🎉".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 523: 🎉 should be < -1",}, b0, false, false, "FB", null); +runtime.ext_scratch3_looks._say("fail 523: 🎉 should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 524: 🎉 should be = -1",}, b0, false, false, "FD", null); +runtime.ext_scratch3_looks._say("fail 524: 🎉 should be = -1", target); } if (!(("" + ("🎉".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 525: 🎉 should be > -1",}, b0, false, false, "FF", null); +runtime.ext_scratch3_looks._say("fail 525: 🎉 should be > -1", target); } if (!(("" + ("🎉".toLowerCase() < "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 526: 🎉 should be < true",}, b0, false, false, "FH", null); +runtime.ext_scratch3_looks._say("fail 526: 🎉 should be < true", target); } if (!(("" + ("🎉".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 527: 🎉 should be = true",}, b0, false, false, "FJ", null); +runtime.ext_scratch3_looks._say("fail 527: 🎉 should be = true", target); } if (!(("" + ("🎉".toLowerCase() > "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 528: 🎉 should be > true",}, b0, false, false, "FL", null); +runtime.ext_scratch3_looks._say("fail 528: 🎉 should be > true", target); } if (!(("" + ("🎉".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 529: 🎉 should be < false",}, b0, false, false, "FN", null); +runtime.ext_scratch3_looks._say("fail 529: 🎉 should be < false", target); } if (!(("" + ("🎉".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 530: 🎉 should be = false",}, b0, false, false, "FP", null); +runtime.ext_scratch3_looks._say("fail 530: 🎉 should be = false", target); } if (!(("" + ("🎉".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 531: 🎉 should be > false",}, b0, false, false, "FR", null); +runtime.ext_scratch3_looks._say("fail 531: 🎉 should be > false", target); } if (!(("" + ("🎉".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 532: 🎉 should be < NaN",}, b0, false, false, "FT", null); +runtime.ext_scratch3_looks._say("fail 532: 🎉 should be < NaN", target); } if (!(("" + ("🎉".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 533: 🎉 should be = NaN",}, b0, false, false, "FV", null); +runtime.ext_scratch3_looks._say("fail 533: 🎉 should be = NaN", target); } if (!(("" + ("🎉".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 534: 🎉 should be > NaN",}, b0, false, false, "FX", null); +runtime.ext_scratch3_looks._say("fail 534: 🎉 should be > NaN", target); } if (!(("" + ("🎉".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 535: 🎉 should be < Infinity",}, b0, false, false, "FZ", null); +runtime.ext_scratch3_looks._say("fail 535: 🎉 should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 536: 🎉 should be = Infinity",}, b0, false, false, "F1", null); +runtime.ext_scratch3_looks._say("fail 536: 🎉 should be = Infinity", target); } if (!(("" + ("🎉".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 537: 🎉 should be > Infinity",}, b0, false, false, "F3", null); +runtime.ext_scratch3_looks._say("fail 537: 🎉 should be > Infinity", target); } if (!(("" + ("🎉".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 538: 🎉 should be < banana",}, b0, false, false, "F5", null); +runtime.ext_scratch3_looks._say("fail 538: 🎉 should be < banana", target); } if (!(("" + ("🎉".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 539: 🎉 should be = banana",}, b0, false, false, "F7", null); +runtime.ext_scratch3_looks._say("fail 539: 🎉 should be = banana", target); } if (!(("" + ("🎉".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 540: 🎉 should be > banana",}, b0, false, false, "F9", null); +runtime.ext_scratch3_looks._say("fail 540: 🎉 should be > banana", target); } if (!(("" + ("🎉".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 541: 🎉 should be < 🎉",}, b0, false, false, "F#", null); +runtime.ext_scratch3_looks._say("fail 541: 🎉 should be < 🎉", target); } if (!(("" + ("🎉".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 542: 🎉 should be = 🎉",}, b0, false, false, "F(", null); +runtime.ext_scratch3_looks._say("fail 542: 🎉 should be = 🎉", target); } if (!(("" + ("🎉".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 543: 🎉 should be > 🎉",}, b0, false, false, "F*", null); +runtime.ext_scratch3_looks._say("fail 543: 🎉 should be > 🎉", target); } if (!(("" + ("🎉".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 544: 🎉 should be < ",}, b0, false, false, "F,", null); +runtime.ext_scratch3_looks._say("fail 544: 🎉 should be < ", target); } if (!(("" + ("🎉".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 545: 🎉 should be = ",}, b0, false, false, "F.", null); +runtime.ext_scratch3_looks._say("fail 545: 🎉 should be = ", target); } if (!(("" + ("🎉".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 546: 🎉 should be > ",}, b0, false, false, "F:", null); +runtime.ext_scratch3_looks._say("fail 546: 🎉 should be > ", target); } if (!(("" + ("".toLowerCase() < "0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 547: should be < 0",}, b0, false, false, "F=", null); +runtime.ext_scratch3_looks._say("fail 547: should be < 0", target); } if (!(("" + ("".toLowerCase() === "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 548: should be = 0",}, b0, false, false, "F@", null); +runtime.ext_scratch3_looks._say("fail 548: should be = 0", target); } if (!(("" + ("".toLowerCase() > "0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 549: should be > 0",}, b0, false, false, "F]", null); +runtime.ext_scratch3_looks._say("fail 549: should be > 0", target); } if (!(("" + ("".toLowerCase() < "0.0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 550: should be < 0.0",}, b0, false, false, "F_", null); +runtime.ext_scratch3_looks._say("fail 550: should be < 0.0", target); } if (!(("" + ("".toLowerCase() === "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 551: should be = 0.0",}, b0, false, false, "F{", null); +runtime.ext_scratch3_looks._say("fail 551: should be = 0.0", target); } if (!(("" + ("".toLowerCase() > "0.0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 552: should be > 0.0",}, b0, false, false, "F}", null); +runtime.ext_scratch3_looks._say("fail 552: should be > 0.0", target); } if (!(("" + ("".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 553: should be < 1.23",}, b0, false, false, "Ga", null); +runtime.ext_scratch3_looks._say("fail 553: should be < 1.23", target); } if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 554: should be = 1.23",}, b0, false, false, "Gc", null); +runtime.ext_scratch3_looks._say("fail 554: should be = 1.23", target); } if (!(("" + ("".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 555: should be > 1.23",}, b0, false, false, "Ge", null); +runtime.ext_scratch3_looks._say("fail 555: should be > 1.23", target); } if (!(("" + ("".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 556: should be < .23",}, b0, false, false, "Gg", null); +runtime.ext_scratch3_looks._say("fail 556: should be < .23", target); } if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 557: should be = .23",}, b0, false, false, "Gi", null); +runtime.ext_scratch3_looks._say("fail 557: should be = .23", target); } if (!(("" + ("".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 558: should be > .23",}, b0, false, false, "Gk", null); +runtime.ext_scratch3_looks._say("fail 558: should be > .23", target); } if (!(("" + ("".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 559: should be < 0.123",}, b0, false, false, "Gm", null); +runtime.ext_scratch3_looks._say("fail 559: should be < 0.123", target); } if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 560: should be = 0.123",}, b0, false, false, "Go", null); +runtime.ext_scratch3_looks._say("fail 560: should be = 0.123", target); } if (!(("" + ("".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 561: should be > 0.123",}, b0, false, false, "Gq", null); +runtime.ext_scratch3_looks._say("fail 561: should be > 0.123", target); } if (!(("" + ("".toLowerCase() < "-0".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 562: should be < -0",}, b0, false, false, "Gs", null); +runtime.ext_scratch3_looks._say("fail 562: should be < -0", target); } if (!(("" + ("".toLowerCase() === "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 563: should be = -0",}, b0, false, false, "Gu", null); +runtime.ext_scratch3_looks._say("fail 563: should be = -0", target); } if (!(("" + ("".toLowerCase() > "-0".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 564: should be > -0",}, b0, false, false, "Gw", null); +runtime.ext_scratch3_looks._say("fail 564: should be > -0", target); } if (!(("" + ("".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 565: should be < -1",}, b0, false, false, "Gy", null); +runtime.ext_scratch3_looks._say("fail 565: should be < -1", target); } if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 566: should be = -1",}, b0, false, false, "GA", null); +runtime.ext_scratch3_looks._say("fail 566: should be = -1", target); } if (!(("" + ("".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 567: should be > -1",}, b0, false, false, "GC", null); +runtime.ext_scratch3_looks._say("fail 567: should be > -1", target); } if (!(("" + ("".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 568: should be < true",}, b0, false, false, "GE", null); +runtime.ext_scratch3_looks._say("fail 568: should be < true", target); } if (!(("" + ("".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 569: should be = true",}, b0, false, false, "GG", null); +runtime.ext_scratch3_looks._say("fail 569: should be = true", target); } if (!(("" + ("".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 570: should be > true",}, b0, false, false, "GI", null); +runtime.ext_scratch3_looks._say("fail 570: should be > true", target); } if (!(("" + ("".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 571: should be < false",}, b0, false, false, "GK", null); +runtime.ext_scratch3_looks._say("fail 571: should be < false", target); } if (!(("" + ("".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 572: should be = false",}, b0, false, false, "GM", null); +runtime.ext_scratch3_looks._say("fail 572: should be = false", target); } if (!(("" + ("".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 573: should be > false",}, b0, false, false, "GO", null); +runtime.ext_scratch3_looks._say("fail 573: should be > false", target); } if (!(("" + ("".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 574: should be < NaN",}, b0, false, false, "GQ", null); +runtime.ext_scratch3_looks._say("fail 574: should be < NaN", target); } if (!(("" + ("".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 575: should be = NaN",}, b0, false, false, "GS", null); +runtime.ext_scratch3_looks._say("fail 575: should be = NaN", target); } if (!(("" + ("".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 576: should be > NaN",}, b0, false, false, "GU", null); +runtime.ext_scratch3_looks._say("fail 576: should be > NaN", target); } if (!(("" + ("".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 577: should be < Infinity",}, b0, false, false, "GW", null); +runtime.ext_scratch3_looks._say("fail 577: should be < Infinity", target); } if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 578: should be = Infinity",}, b0, false, false, "GY", null); +runtime.ext_scratch3_looks._say("fail 578: should be = Infinity", target); } if (!(("" + ("".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 579: should be > Infinity",}, b0, false, false, "G0", null); +runtime.ext_scratch3_looks._say("fail 579: should be > Infinity", target); } if (!(("" + ("".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 580: should be < banana",}, b0, false, false, "G2", null); +runtime.ext_scratch3_looks._say("fail 580: should be < banana", target); } if (!(("" + ("".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 581: should be = banana",}, b0, false, false, "G4", null); +runtime.ext_scratch3_looks._say("fail 581: should be = banana", target); } if (!(("" + ("".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 582: should be > banana",}, b0, false, false, "G6", null); +runtime.ext_scratch3_looks._say("fail 582: should be > banana", target); } if (!(("" + ("".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 583: should be < 🎉",}, b0, false, false, "G8", null); +runtime.ext_scratch3_looks._say("fail 583: should be < 🎉", target); } if (!(("" + ("".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 584: should be = 🎉",}, b0, false, false, "G!", null); +runtime.ext_scratch3_looks._say("fail 584: should be = 🎉", target); } if (!(("" + ("".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 585: should be > 🎉",}, b0, false, false, "G%", null); +runtime.ext_scratch3_looks._say("fail 585: should be > 🎉", target); } if (!(("" + ("".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 586: should be < ",}, b0, false, false, "G)", null); +runtime.ext_scratch3_looks._say("fail 586: should be < ", target); } if (!(("" + ("".toLowerCase() === "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 587: should be = ",}, b0, false, false, "G+", null); +runtime.ext_scratch3_looks._say("fail 587: should be = ", target); } if (!(("" + ("".toLowerCase() > "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail 588: should be > ",}, b0, false, false, "G.", null); +runtime.ext_scratch3_looks._say("fail 588: should be > ", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "G-", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot index 1f7c3725ee5..bccafbe8d5f 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-runtime.sb3.tw-snapshot @@ -3,11 +3,10 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "ae", null); +runtime.ext_scratch3_looks._say("plan 0", target); yield* thread.procedures["Wrun test"](); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "aZ", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -18,7 +17,6 @@ const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; const b2 = stage.variables["n^wm8jw#b24sggt.S^tD"]; const b3 = stage.variables["_]6^lq+-%H0{ov`tKt7$"]; const b4 = stage.variables["3lyKRepBc$tx)EWlpr!y"]; -const b5 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_run_test () { thread.procedures["Wsetup values"](); b0.value = 0; @@ -30,16 +28,15 @@ for (var a1 = b2.value.length; a1 > 0; a1--) { b3.value = (toNotNaN(+b3.value) + 1); b0.value = (toNotNaN(+b0.value) + 1); if (!compareEqual(compareGreaterThan(listGet(b2.value, b1.value), (b2.value[(b3.value | 0) - 1] ?? "")), (b4.value[(b0.value | 0) - 1] ?? ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be > " + ("" + (b2.value[(b3.value | 0) - 1] ?? ""))))),}, b5, true, false, "]", null); +runtime.ext_scratch3_looks._say(("fail " + (("" + listGet(b2.value, b1.value)) + (" should be > " + ("" + (b2.value[(b3.value | 0) - 1] ?? ""))))), target); } -b0.value = (toNotNaN(+b0.value) + 1); -if (!compareEqual(compareEqual(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be = " + ("" + listGet(b2.value, b3.value))))),}, b5, true, false, "|", null); +b0.value = (b0.value + 1); +if (!compareEqual(compareEqual(listGet(b2.value, b1.value), (b2.value[(b3.value | 0) - 1] ?? "")), (b4.value[(b0.value | 0) - 1] ?? ""))) { +runtime.ext_scratch3_looks._say(("fail " + (("" + listGet(b2.value, b1.value)) + (" should be = " + ("" + (b2.value[(b3.value | 0) - 1] ?? ""))))), target); } -b0.value = (toNotNaN(+b0.value) + 1); -if (!compareEqual(compareLessThan(listGet(b2.value, b1.value), listGet(b2.value, b3.value)), (b4.value[(b0.value | 0) - 1] ?? ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":("fail " + (("" + listGet(b2.value, b1.value)) + (" should be < " + ("" + listGet(b2.value, b3.value))))),}, b5, true, true, "ab", null); -if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} +b0.value = (b0.value + 1); +if (!compareEqual(compareLessThan(listGet(b2.value, b1.value), (b2.value[(b3.value | 0) - 1] ?? "")), (b4.value[(b0.value | 0) - 1] ?? ""))) { +runtime.ext_scratch3_looks._say(("fail " + (("" + listGet(b2.value, b1.value)) + (" should be < " + ("" + (b2.value[(b3.value | 0) - 1] ?? ""))))), target); } if (isStuck()) yield; } diff --git a/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot index 3cc61e9b75d..66011d00da6 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-compatibility-layer-type-barrier.sb3.tw-snapshot @@ -3,17 +3,16 @@ // 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 = runtime.getOpcodeFunction("looks_sayforsecs"); +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = runtime.getOpcodeFunction("looks_sayforsecs"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); -b1.value = (0 + 0); -yield* executeInCompatibilityLayer({"MESSAGE":"Hello!","SECS":0.1,}, b2, false, false, "d", null); -if (((toNotNaN(+b1.value) + 2) === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "i", null); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = (0 + 0); +yield* executeInCompatibilityLayer({"MESSAGE":"Hello!","SECS":0.1,}, b1, false, false, "d", null); +if (((toNotNaN(+b0.value) + 2) === 2)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "m", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-coordinate-precision.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-coordinate-precision.sb3.tw-snapshot index ecaec5b0809..446c232e2d2 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-coordinate-precision.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-coordinate-precision.sb3.tw-snapshot @@ -3,34 +3,33 @@ // 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 = runtime.getSpriteTargetByName("Sprite1"); +const b0 = runtime.getSpriteTargetByName("Sprite1"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 6",}, b0, false, false, "`f)8`e7_V%]cmRy7eZ?*", null); +runtime.ext_scratch3_looks._say("plan 6", target); target.setXY(1e-9, target.y); if ((limitPrecision(target.x) === 1e-9)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass much above x does not round",}, b0, false, false, "wnAyae772?^VZ]bq?#*p", null); +runtime.ext_scratch3_looks._say("pass much above x does not round", target); } -if (((b1 ? b1.x : 0) === 1e-9)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass initial 'of' test",}, b0, false, false, "${qf}t3_Wf_/sqC#i0WN", null); +if (((b0 ? b0.x : 0) === 1e-9)) { +runtime.ext_scratch3_looks._say("pass initial 'of' test", target); } target.setXY(target.x + 0, target.y); runtime.ext_scratch3_motion._moveSteps(0, target); target.setXY(target.x + -9e-10, target.y); -if (((b1 ? b1.x : 0) === 1.0000000000000007e-10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 'of' never rounds - positive x",}, b0, false, false, "zt/Fd,i768/rohNq-OU/", null); +if (((b0 ? b0.x : 0) === 1.0000000000000007e-10)) { +runtime.ext_scratch3_looks._say("pass 'of' never rounds - positive x", target); } if ((limitPrecision(target.x) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass x slightly above 0 rounds",}, b0, false, false, "p5a6(?e#B|B(d.fe;b6F", null); +runtime.ext_scratch3_looks._say("pass x slightly above 0 rounds", target); } target.setXY(target.x + -9e-10, target.y); target.setXY(target.x, target.y + 0); -if (((b1 ? b1.x : 0) === -7.999999999999999e-10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 'of' never rounds and change x - negative x",}, b0, false, false, "![=|9E8]xp_9QR]fu}4M", null); +if (((b0 ? b0.x : 0) === -7.999999999999999e-10)) { +runtime.ext_scratch3_looks._say("pass 'of' never rounds and change x - negative x", target); } if ((limitPrecision(target.x) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass x slightly below 0 rounds",}, b0, false, false, "4o-vB]D}HJ1/*qW~k3Cd", null); +runtime.ext_scratch3_looks._say("pass x slightly below 0 rounds", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "8We]d__[]7X;@+e*x~^@", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-counter.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-counter.sb3.tw-snapshot index abbfa97a51e..838b27fe8f0 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-counter.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-counter.sb3.tw-snapshot @@ -3,34 +3,32 @@ // 2 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { if ((runtime.ext_scratch3_control._counter === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass global",}, b0, false, false, "C", null); +runtime.ext_scratch3_looks._say("pass global", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "B", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // 1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 5",}, b0, false, false, "g", null); +runtime.ext_scratch3_looks._say("plan 5", target); if ((runtime.ext_scratch3_control._counter === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass initial value = 0",}, b0, false, false, "q", null); +runtime.ext_scratch3_looks._say("pass initial value = 0", target); } runtime.ext_scratch3_control._counter++; if ((runtime.ext_scratch3_control._counter === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass incr 1",}, b0, false, false, "s", null); +runtime.ext_scratch3_looks._say("pass incr 1", target); } runtime.ext_scratch3_control._counter++; if ((runtime.ext_scratch3_control._counter === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass incr 2",}, b0, false, false, "u", null); +runtime.ext_scratch3_looks._say("pass incr 2", target); } runtime.ext_scratch3_control._counter = 0; if ((runtime.ext_scratch3_control._counter === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass clear = 0",}, b0, false, false, "w", null); +runtime.ext_scratch3_looks._say("pass clear = 0", target); } for (var a0 = 10; a0 > 0; a0--) { runtime.ext_scratch3_control._counter++; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot index 3429d7b3b4d..d6422034fe0 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot @@ -3,19 +3,18 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); -b1.value = 0; +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = 0; for (var a0 = toNotNaN(+thread.procedures["Zblock name"]()); a0 >= 0.5; a0--) { -b1.value = (toNotNaN(+b1.value) + 1); +b0.value = (toNotNaN(+b0.value) + 1); yield; } -if ((toNotNaN(+b1.value) === 40)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "n", null); +if ((toNotNaN(+b0.value) === 40)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot index 7676e37b15c..14cf2f1aa3b 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-exit-state-accounts-for-yields-in-procedures.sb3.tw-snapshot @@ -3,17 +3,16 @@ // 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["FpLI$ida6)qR,q~y`1|*"]; +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = stage.variables["FpLI$ida6)qR,q~y`1|*"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); -b1.value = (1 + 2); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = (1 + 2); yield* thread.procedures["Zsomething that yields"](); -if ((("" + listGet(b2.value, b1.value)).toLowerCase() === "the only thing".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "o", null); +if ((("" + listGet(b1.value, b0.value)).toLowerCase() === "the only thing".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot index 5f84b8b41da..754e542daa6 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot @@ -3,21 +3,20 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 4",}, b0, false, false, "i", null); +runtime.ext_scratch3_looks._say("plan 4", target); if (compareGreaterThan(("something".toLowerCase() === "something".toLowerCase()), ("0" + ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "k", null); +runtime.ext_scratch3_looks._say("pass", target); } if (compareLessThan(("something".toLowerCase() === "else".toLowerCase()), ("1" + ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "m", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((+("something".toLowerCase() === "something".toLowerCase())) > (0 + 0))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "n", null); +runtime.ext_scratch3_looks._say("pass", target); } if (((+("something".toLowerCase() === "else".toLowerCase())) < (1 + 0))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "o", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot index 87f027a3c1c..f6f6db0a82b 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot @@ -3,26 +3,25 @@ // 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 = runtime.getOpcodeFunction("motion_pointtowards"); +const b0 = runtime.getOpcodeFunction("motion_pointtowards"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 4",}, b0, false, false, "h", null); +runtime.ext_scratch3_looks._say("plan 4", target); target.setDirection(95); if ((target.direction === 95)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 1",}, b0, false, false, "o", null); +runtime.ext_scratch3_looks._say("pass 1", target); } target.setDirection((1 / 0)); if ((target.direction === 95)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 2",}, b0, false, false, "r", null); +runtime.ext_scratch3_looks._say("pass 2", target); } target.setDirection(toNotNaN((0 / 0))); if ((target.direction === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 3",}, b0, false, false, "u", null); +runtime.ext_scratch3_looks._say("pass 3", target); } -yield* executeInCompatibilityLayer({"TOWARDS":"Sprite2",}, b1, false, false, "g", null); +yield* executeInCompatibilityLayer({"TOWARDS":"Sprite2",}, b0, false, false, "g", null); if ((target.direction === 90)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 4",}, b0, false, false, "y", null); +runtime.ext_scratch3_looks._say("pass 4", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "w", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-random-with-invalid-number-with-period.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-random-with-invalid-number-with-period.sb3.tw-snapshot index 92e17fec5ba..4fcfeee75e0 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-random-with-invalid-number-with-period.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-random-with-invalid-number-with-period.sb3.tw-snapshot @@ -3,30 +3,29 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 6",}, b0, false, false, "j", null); -b1.value = runtime.ext_scratch3_operators._random(("an invalid number" + "."), 1); -if (!(b1.value <= 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "m", null); +runtime.ext_scratch3_looks._say("plan 6", target); +b0.value = runtime.ext_scratch3_operators._random(("an invalid number" + "."), 1); +if (!(b0.value <= 0)) { +runtime.ext_scratch3_looks._say("pass", target); } -if (compareLessThan(b1.value, 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "r", null); +if ((b0.value < 1)) { +runtime.ext_scratch3_looks._say("pass", target); } -if ((("" + b1.value).toLowerCase().indexOf(".".toLowerCase()) !== -1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "s", null); +if ((("" + b0.value).toLowerCase().indexOf(".".toLowerCase()) !== -1)) { +runtime.ext_scratch3_looks._say("pass", target); } -b1.value = runtime.ext_scratch3_operators._random(1, ("an invalid number" + ".")); -if (!(b1.value <= 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "v", null); +b0.value = runtime.ext_scratch3_operators._random(1, ("an invalid number" + ".")); +if (!(b0.value <= 0)) { +runtime.ext_scratch3_looks._say("pass", target); } -if (compareLessThan(b1.value, 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "x", null); +if ((b0.value < 1)) { +runtime.ext_scratch3_looks._say("pass", target); } -if ((("" + b1.value).toLowerCase().indexOf(".".toLowerCase()) !== -1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "A", null); +if ((("" + b0.value).toLowerCase().indexOf(".".toLowerCase()) !== -1)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "y", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot index 4168b881940..5b92a63c221 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot @@ -3,21 +3,20 @@ // 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 = target.variables["gTtSj;o_E;Snkn620KF."]; -const b2 = target.variables["zShM`!CD?d_|Z,]5X}N6"]; +const b0 = target.variables["gTtSj;o_E;Snkn620KF."]; +const b1 = target.variables["zShM`!CD?d_|Z,]5X}N6"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "d", null); -b1.value = 2; -if ((b1.value === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass variable",}, b0, false, false, "k", null); +runtime.ext_scratch3_looks._say("plan 2", target); +b0.value = 2; +if ((b0.value === 2)) { +runtime.ext_scratch3_looks._say("pass variable", target); } -b2.value = []; -b2.value.push(3); -b2._monitorUpToDate = false; -if ((toNotNaN(+(b2.value[1 - 1] ?? "")) === 3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass list",}, b0, false, false, "m", null); +b1.value = []; +b1.value.push(3); +b1._monitorUpToDate = false; +if ((toNotNaN(+(b1.value[1 - 1] ?? "")) === 3)) { +runtime.ext_scratch3_looks._say("pass list", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot index b963785b05c..ec8075106ae 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot @@ -5,17 +5,16 @@ (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = runtime.getOpcodeFunction("sound_setvolumeto"); const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { yield* executeInCompatibilityLayer({"VOLUME":0,}, b0, false, false, "d", null); b1.value = 0; -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b2, false, false, "g", null); +runtime.ext_scratch3_looks._say("plan 1", target); yield* thread.procedures["Wno refresh"](); yield* thread.procedures["Wruns below with no refresh"](); if (compareEqual(b1.value, 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b2, false, false, "v", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b2, false, false, "f", null); +runtime.ext_scratch3_looks._say("end", target); runtime.stopAll(); retire(); return; retire(); return; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot index 07442f3cde8..9bb8aee3462 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot @@ -3,11 +3,10 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "d", null); +runtime.ext_scratch3_looks._say("plan 0", target); thread.procedures["Zfoo %s"](""); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot index 7021f041aa5..f6de384583c 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-gh-249-quicksort.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "Z", null); +runtime.ext_scratch3_looks._say("plan 1", target); yield* thread.procedures["Wrun"](); yield* thread.procedures["Wvalidate"](); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "aw", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -33,20 +32,19 @@ const b0 = stage.variables["7AH{dO^X;}C[{[l~g-7m"]; const b1 = stage.variables["gPJ}c-PZz?Y+_L][iMU_"]; const b2 = stage.variables["EF^k=u-t@S)w60;RP?dZ-list-list"]; const b3 = stage.variables["FsKqV/2kid0gw0J+Jj(c"]; -const b4 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_validate () { b0.value = 1; b1.value = 1; for (var a0 = b2.value.length; a0 > 0; a0--) { if (!compareEqual(listGet(b2.value, b1.value), listGet(b3.value, b1.value))) { b0.value = 0; -yield* executeInCompatibilityLayer({"MESSAGE":("fail mismatch at index " + ("" + b1.value)),}, b4, true, false, ",", null); +runtime.ext_scratch3_looks._say(("fail mismatch at index " + ("" + b1.value)), target); } b1.value = (toNotNaN(+b1.value) + 1); if (isStuck()) yield; } if ((toNotNaN(+b0.value) === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass sorted",}, b4, true, false, "aE", null); +runtime.ext_scratch3_looks._say("pass sorted", target); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-list-any.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-list-any.sb3.tw-snapshot index d6988304d85..e099222961b 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-list-any.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-list-any.sb3.tw-snapshot @@ -3,36 +3,35 @@ // Sprite2 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["eFlmP1{XC+I1:h0Yln.K"]; +const b0 = stage.variables["eFlmP1{XC+I1:h0Yln.K"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 7",}, b0, false, false, "h", null); -b1.value = []; -listInsert(b1, "any", "a"); -listInsert(b1, "any", "b"); -listInsert(b1, "any", "c"); -if ((b1.value.length === 3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "s", null); +runtime.ext_scratch3_looks._say("plan 7", target); +b0.value = []; +listInsert(b0, "any", "a"); +listInsert(b0, "any", "b"); +listInsert(b0, "any", "c"); +if ((b0.value.length === 3)) { +runtime.ext_scratch3_looks._say("pass", target); } -if (listContains(b1, "a")) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "v", null); +if (listContains(b0, "a")) { +runtime.ext_scratch3_looks._say("pass", target); } -if (listContains(b1, "b")) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "x", null); +if (listContains(b0, "b")) { +runtime.ext_scratch3_looks._say("pass", target); } -if (listContains(b1, "c")) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "z", null); +if (listContains(b0, "c")) { +runtime.ext_scratch3_looks._say("pass", target); } -if (listContains(b1, listGet(b1.value, "any"))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "A", null); +if (listContains(b0, listGet(b0.value, "any"))) { +runtime.ext_scratch3_looks._say("pass", target); } -listDelete(b1, "any"); -if ((b1.value.length === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "C", null); +listDelete(b0, "any"); +if ((b0.value.length === 2)) { +runtime.ext_scratch3_looks._say("pass", target); } -if ((("" + listGet(b1.value, "*")).toLowerCase() === "".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "F", null); +if ((("" + listGet(b0.value, "*")).toLowerCase() === "".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "E", null); +runtime.ext_scratch3_looks._say("end", target); retire(); 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 index fee655b382a..ca63598431c 100644 --- 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 @@ -3,15 +3,14 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "g", null); +runtime.ext_scratch3_looks._say("plan 1", target); yield* thread.procedures["Wtest %s"]("random"); -if ((("" + b1.value).toLowerCase() === "random".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "p", null); +if ((("" + b0.value).toLowerCase() === "random".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null); +runtime.ext_scratch3_looks._say("end", target); retire(); 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 index 1a3fb7c91b1..6dda54881f6 100644 --- 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 @@ -3,27 +3,26 @@ // 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"]; +const b0 = stage.variables["%ehs:~!Y0l-5=!mnd-B?"]; +const b1 = stage.variables["=3aHfv[mKa)v,Wfpy:y?"]; +const b2 = 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 = (toNotNaN(+b2.value) + 1); -b3.value = (b1.value[(b2.value | 0) - 1] ?? ""); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = []; +b0.value.push((1 + 2)); +b0._monitorUpToDate = false; +b0.value.push("eof"); +b0._monitorUpToDate = false; +b1.value = 0; +b2.value = "bwah"; +while (!(("" + b2.value).toLowerCase() === "eof".toLowerCase())) { +b1.value = (toNotNaN(+b1.value) + 1); +b2.value = (b0.value[(b1.value | 0) - 1] ?? ""); yield; } -if ((toNotNaN(+b2.value) === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "q", null); +if ((toNotNaN(+b1.value) === 2)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-obsolete-blocks.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-obsolete-blocks.sb3.tw-snapshot index ac61a75d00a..71a44853beb 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-obsolete-blocks.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-obsolete-blocks.sb3.tw-snapshot @@ -3,31 +3,30 @@ // 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 = runtime.getOpcodeFunction("sensing_userid"); -const b3 = runtime.getOpcodeFunction("motion_xscroll"); -const b4 = runtime.getOpcodeFunction("motion_yscroll"); -const b5 = runtime.getOpcodeFunction("motion_scroll_right"); -const b6 = runtime.getOpcodeFunction("motion_scroll_up"); -const b7 = runtime.getOpcodeFunction("motion_align_scene"); -const b8 = runtime.getOpcodeFunction("looks_setstretchto"); -const b9 = runtime.getOpcodeFunction("looks_changestretchby"); -const b10 = runtime.getOpcodeFunction("looks_hideallsprites"); +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b1 = runtime.getOpcodeFunction("sensing_userid"); +const b2 = runtime.getOpcodeFunction("motion_xscroll"); +const b3 = runtime.getOpcodeFunction("motion_yscroll"); +const b4 = runtime.getOpcodeFunction("motion_scroll_right"); +const b5 = runtime.getOpcodeFunction("motion_scroll_up"); +const b6 = runtime.getOpcodeFunction("motion_align_scene"); +const b7 = runtime.getOpcodeFunction("looks_setstretchto"); +const b8 = runtime.getOpcodeFunction("looks_changestretchby"); +const b9 = runtime.getOpcodeFunction("looks_hideallsprites"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "pW2KnJW$%KXFoppMJBAi", null); -b1.value = (yield* executeInCompatibilityLayer({}, b2, false, false, "X[|X;C.(v[|^i|@0Eqy4", null)); -b1.value = (yield* executeInCompatibilityLayer({}, b3, false, false, "z;H$hVK7X;MZSyO9U/#1", null)); -b1.value = (yield* executeInCompatibilityLayer({}, b4, false, false, ";Q94_J}Jv36TqTll;ji*", null)); -yield* executeInCompatibilityLayer({"DISTANCE":10,}, b5, false, false, "_TLJeW5hG9gAtYO2c*D9", null); -yield* executeInCompatibilityLayer({"DISTANCE":10,}, b6, false, false, "o=l#1WJR!L37RN`q:`8E", null); -yield* executeInCompatibilityLayer({"ALIGNMENT":"bottom-left",}, b7, false, false, "idkZ9I+=Q:@xXm;N-2Oy", null); -yield* executeInCompatibilityLayer({"STRETCH":100,}, b8, false, false, "AMs-%pRGK*v6a[.XifN1", null); -yield* executeInCompatibilityLayer({"STRETCH":100,}, b8, false, false, "g+bBVCHp+A[-X2E7-7#|", null); -yield* executeInCompatibilityLayer({"CHANGE":10,}, b9, false, false, "ZN24~,cX56Dc2k4vt}HB", null); -yield* executeInCompatibilityLayer({"CHANGE":10,}, b9, false, false, "Zjds+5Is*:nb7wnX{rYN", null); -yield* executeInCompatibilityLayer({}, b10, false, false, "8X_d`@6,B7%wzr7.xE}t", null); -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "C/%^M/1/S`iX8*M~Q;!3", null); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "(C;YJ2L~?zR[Y)Wti?3m", null); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = (yield* executeInCompatibilityLayer({}, b1, false, false, "X[|X;C.(v[|^i|@0Eqy4", null)); +b0.value = (yield* executeInCompatibilityLayer({}, b2, false, false, "z;H$hVK7X;MZSyO9U/#1", null)); +b0.value = (yield* executeInCompatibilityLayer({}, b3, false, false, ";Q94_J}Jv36TqTll;ji*", null)); +yield* executeInCompatibilityLayer({"DISTANCE":10,}, b4, false, false, "_TLJeW5hG9gAtYO2c*D9", null); +yield* executeInCompatibilityLayer({"DISTANCE":10,}, b5, false, false, "o=l#1WJR!L37RN`q:`8E", null); +yield* executeInCompatibilityLayer({"ALIGNMENT":"bottom-left",}, b6, false, false, "idkZ9I+=Q:@xXm;N-2Oy", null); +yield* executeInCompatibilityLayer({"STRETCH":100,}, b7, false, false, "AMs-%pRGK*v6a[.XifN1", null); +yield* executeInCompatibilityLayer({"STRETCH":100,}, b7, false, false, "g+bBVCHp+A[-X2E7-7#|", null); +yield* executeInCompatibilityLayer({"CHANGE":10,}, b8, false, false, "ZN24~,cX56Dc2k4vt}HB", null); +yield* executeInCompatibilityLayer({"CHANGE":10,}, b8, false, false, "Zjds+5Is*:nb7wnX{rYN", null); +yield* executeInCompatibilityLayer({}, b9, false, false, "8X_d`@6,B7%wzr7.xE}t", null); +runtime.ext_scratch3_looks._say("pass", target); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-one-divide-negative-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-one-divide-negative-zero.sb3.tw-snapshot index d87b4b227fe..3e2eeffa931 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-one-divide-negative-zero.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-one-divide-negative-zero.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "@|B*yJ0zKh!acN`7L-N5", null); +runtime.ext_scratch3_looks._say("plan 1", target); if (((1 / -0) === -Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "=enYDFG11Nj/0BL:y56w", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",Cpv8W0RH0RgNky[1xb:", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot index 0f6a49f62b7..3b2521664aa 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot @@ -4,13 +4,12 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["PsY$$vp$IVH;dDAr[q2h"]; -const b1 = runtime.getOpcodeFunction("looks_say"); -const b2 = stage.variables["l^q!%fq]Bv;72dlGf}^Z"]; +const b1 = stage.variables["l^q!%fq]Bv;72dlGf}^Z"]; return function* genXYZ () { b0.value = 0; -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b1, false, false, "}fY]VN(X|v/[G`P0?@s2", null); +runtime.ext_scratch3_looks._say("plan 0", target); for (var a0 = 30; a0 > 0; a0--) { -b2.value = runtime.ioDevices.clock.projectTimer(); +b1.value = runtime.ioDevices.clock.projectTimer(); thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -22,7 +21,7 @@ thread.timer = null; yield; } b0.value = 1; -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b1, false, false, "mDG0BTTG/wwr;/Uz~u^c", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -31,7 +30,6 @@ retire(); return; const b0 = stage.variables["l^q!%fq]Bv;72dlGf}^Z"]; const b1 = runtime.getOpcodeFunction("event_whengreaterthan"); const b2 = stage.variables["PsY$$vp$IVH;dDAr[q2h"]; -const b3 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { { const resolvedValue = toBoolean((yield* executeInCompatibilityLayer({"VALUE":b0.value,"WHENGREATERTHANMENU":"TIMER",}, b1, false, false, "iNmua~6veGey6O-_UB9.", null))); @@ -45,7 +43,7 @@ retire(); return; yield; } if (compareEqual(b2.value, 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b3, false, false, "JE9*Ms@I!EKJ-|Bcga#W", null); +runtime.ext_scratch3_looks._say("fail", target); } retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot index 58b908a70ce..adf5671a8c7 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot @@ -3,18 +3,16 @@ // Player script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "#0F2+kcgu;or|hdwuT9{", null); -yield* thread.procedures["ZSet Costume"](); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Q^(MKge)QH2e:WH6b6g@", null); +runtime.ext_scratch3_looks._say("plan 1", target); +thread.procedures["ZSet Costume"](); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Player ZSet Costume (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_Set_Costume () { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "Z$W^@c(f)rHu:DL/SGuQ", null); +return function funXYZ_Set_Costume () { +runtime.ext_scratch3_looks._say("pass", target); return ""; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot index f2456f2e254..5766bd76809 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-arguments-with-same-name.sb3.tw-snapshot @@ -3,31 +3,28 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "J#qm1yA(@Z6mj%Mgh;0X", null); -yield* thread.procedures["Znumber or text %s %s"]("bad","ok"); -yield* thread.procedures["Zboolean %b %b"]("false",!false); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb(Mu?gdTIH^;kC_", null); +runtime.ext_scratch3_looks._say("plan 2", target); +thread.procedures["Znumber or text %s %s"]("bad","ok"); +thread.procedures["Zboolean %b %b"]("false",!false); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 Znumber or text %s %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_number_or_text__ (p0,p1) { +return function funXYZ_number_or_text__ (p0,p1) { if ((("" + p1).toLowerCase() === "ok".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "HH`yRe9(x5%D:eV@EmkE", null); +runtime.ext_scratch3_looks._say("pass", target); } return ""; }; }) // Sprite1 Zboolean %b %b (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); -return function* genXYZ_boolean__ (p0,p1) { +return function funXYZ_boolean__ (p0,p1) { if (toBoolean(p1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "M^!cgco]B(V)je$a6lF7", null); +runtime.ext_scratch3_looks._say("pass", target); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot index f80c51477bd..98305cc14c7 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot @@ -3,16 +3,15 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "qf{MD}-f+l?U+)KA#Vnm", null); -b1.value = ""; +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = ""; thread.procedures["Zdo something"](); -if (!(b1.value.toLowerCase() === "".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "Sgf_#7|GOpx!R]?Q3]$s", null); +if (!(b0.value.toLowerCase() === "".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",vD-ZG7f{]FoJ`,))JWh", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot index c86b1325e8f..e0e3857ecd3 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot @@ -3,9 +3,8 @@ // Apple script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a", null); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "f", null); +runtime.ext_scratch3_looks._say("plan 0", target); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot index d3a12562b1a..2cf755d294c 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existant.sb3.tw-snapshot @@ -23,19 +23,18 @@ retire(); return; // 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["Go=PJS7BFXYo_qi2S:kQ"]; +const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "o", null); -b1.value = 0; +runtime.ext_scratch3_looks._say("plan 2", target); +b0.value = 0; if (compareEqual(thread.procedures["Zinvalid params - reporter"](), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass invalid params reporter",}, b0, false, false, "L", null); +runtime.ext_scratch3_looks._say("pass invalid params reporter", target); } if (compareEqual(thread.procedures["Zinvalid params - boolean"](), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass invalid params boolean",}, b0, false, false, "N", null); +runtime.ext_scratch3_looks._say("pass invalid params boolean", target); } runtime.stopForTarget(target, thread); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "P", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existent.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existent.sb3.tw-snapshot index cea7ecccc17..7c867947149 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existent.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existent.sb3.tw-snapshot @@ -3,15 +3,14 @@ // Sprite2 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 b0 = 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 = "discard me"; -b1.value = ""; -if ((("" + b1.value).toLowerCase() === "".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent procedure returned empty string",}, b0, false, false, "h", null); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = "discard me"; +b0.value = ""; +if ((("" + b0.value).toLowerCase() === "".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass non existent procedure returned empty string", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null); +runtime.ext_scratch3_looks._say("end", target); 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 2952a58ecbc..d0e29b100c2 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 @@ -3,30 +3,29 @@ // 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["Go=PJS7BFXYo_qi2S:kQ"]; -const b2 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 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 ((toNotNaN(+b1.value) === 4)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp recursion yields",}, b0, false, false, "ao", null); +runtime.ext_scratch3_looks._say("plan 18", target); +b0.value = 0; +b1.value = (yield* thread.procedures["Znon warp recursion should yield %s"](8)); +if ((toNotNaN(+b0.value) === 4)) { +runtime.ext_scratch3_looks._say("pass non warp recursion yields", target); } -b1.value = 0; -b2.value = thread.procedures["Wwarp recursion should not yield %s"](8); -if ((b1.value === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass warp recursion does not yield",}, b0, false, false, "ar", null); +b0.value = 0; +b1.value = thread.procedures["Wwarp recursion should not yield %s"](8); +if ((b0.value === 0)) { +runtime.ext_scratch3_looks._say("pass warp recursion does not yield", target); } -b1.value = 0; -b2.value = (yield* thread.procedures["Zfib %s"](7)); -if ((toNotNaN(+b1.value) === 20)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp fib yielded",}, b0, false, false, "au", null); +b0.value = 0; +b1.value = (yield* thread.procedures["Zfib %s"](7)); +if ((toNotNaN(+b0.value) === 20)) { +runtime.ext_scratch3_looks._say("pass non warp fib yielded", target); } yield* thread.procedures["Zrecursing yields between each %s"]("initial"); yield* thread.procedures["Zrecursing arguments eval order %s %s %s %s"]("initial","","",""); runtime.stopForTarget(target, thread); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "av", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -63,21 +62,20 @@ return ""; (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_recursing_yields_bet (p0) { if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = 0; b1.value = (toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 1))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 2))) + toNotNaN((toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3))) + toNotNaN(+(yield* yieldThenCallGenerator(thread.procedures["Zrecursing yields between each %s"], 3)))))))))))); if ((toNotNaN(+b0.value) === 3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recursing between calls yields final",}, b2, false, false, "aK", null); +runtime.ext_scratch3_looks._say("pass recursing between calls yields final", target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":"fail recursing between calls yields final",}, b2, false, false, "aL", null); +runtime.ext_scratch3_looks._say("fail recursing between calls yields final", target); } } else { if (compareEqual(b0.value, p0)) { -yield* executeInCompatibilityLayer({"MESSAGE":("pass recursing between calls yields " + ("" + p0)),}, b2, false, false, "#", null); +runtime.ext_scratch3_looks._say(("pass recursing between calls yields " + ("" + p0)), target); } else { -yield* executeInCompatibilityLayer({"MESSAGE":("fail recursing between calls yields " + ("" + p0)),}, b2, false, false, "%", null); +runtime.ext_scratch3_looks._say(("fail recursing between calls yields " + ("" + p0)), target); } } return ""; @@ -88,35 +86,34 @@ return ""; const b0 = stage.variables["4HH82mPlVMOONdl(Ot*7"]; const b1 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; const b2 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; -const b3 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_recursing_arguments_ (p0,p1,p2,p3) { if ((("" + p0).toLowerCase() === "initial".toLowerCase())) { b0.value = []; b1.value = 0; b2.value = (yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 1",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 2",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 3",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 4","","","")),(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 5","","","")),(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 6","","","")))),"","")),"",(yield* yieldThenCallGenerator(thread.procedures["Zrecursing arguments eval order %s %s %s %s"], "child 7","","","")))); if ((("" + (b0.value[1 - 1] ?? "")).toLowerCase() === "1/child 4".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 1",}, b3, false, false, "aZ", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 1", target); } if ((("" + (b0.value[2 - 1] ?? "")).toLowerCase() === "1/child 5".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 2",}, b3, false, false, "a#", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 2", target); } if ((("" + (b0.value[3 - 1] ?? "")).toLowerCase() === "2/child 6".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 3",}, b3, false, false, "a(", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 3", target); } if ((("" + (b0.value[4 - 1] ?? "")).toLowerCase() === "2/child 3".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 4",}, b3, false, false, "a*", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 4", target); } if ((("" + (b0.value[5 - 1] ?? "")).toLowerCase() === "3/child 2".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 5",}, b3, false, false, "a,", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 5", target); } if ((("" + (b0.value[6 - 1] ?? "")).toLowerCase() === "3/child 7".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 6",}, b3, false, false, "a.", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 6", target); } if ((("" + (b0.value[7 - 1] ?? "")).toLowerCase() === "4/child 1".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - 7",}, b3, false, false, "a:", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - 7", target); } if ((b0.value.length === 7)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass recurse arg order - length is correct",}, b3, false, false, "a=", null); +runtime.ext_scratch3_looks._say("pass recurse arg order - length is correct", target); } } else { b0.value.push((("" + b1.value) + ("/" + ("" + p0)))); diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot index e356c359bf8..c14aa78f900 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-simple.sb3.tw-snapshot @@ -3,27 +3,26 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 8",}, b0, false, false, "x", null); +runtime.ext_scratch3_looks._say("plan 8", target); if ((("" + thread.procedures["Zsimplest"]()).toLowerCase() === "It works!".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass simplest",}, b0, false, false, ":", null); +runtime.ext_scratch3_looks._say("pass simplest", target); } if ((("" + thread.procedures["Znesting 1"]()).toLowerCase() === "42-54".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass nesting1",}, b0, false, false, "=", null); +runtime.ext_scratch3_looks._say("pass nesting1", target); } if ((toNotNaN(+thread.procedures["Wwarp fib %s"](12)) === 144)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass fib 12",}, b0, false, false, "@", null); +runtime.ext_scratch3_looks._say("pass fib 12", target); } if ((toNotNaN(+thread.procedures["Wfactorial %s"](12)) === 479001600)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass factorial 12",}, b0, false, false, "]", null); +runtime.ext_scratch3_looks._say("pass factorial 12", target); } -b1.value = (yield* thread.procedures["Zno shadowing 1 %s %s"]("f","g")); -if ((("" + b1.value).toLowerCase() === "".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass default return value",}, b0, false, false, "|", null); +b0.value = thread.procedures["Zno shadowing 1 %s %s"]("f","g"); +if ((("" + b0.value).toLowerCase() === "".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass default return value", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "`", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) @@ -61,19 +60,18 @@ return ""; // Sprite1 Zno shadowing 1 %s %s (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_no_shadowing_1__ (p0,p1) { +const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function funXYZ_no_shadowing_1__ (p0,p1) { if (((("" + p0).toLowerCase() === "f".toLowerCase()) && (("" + p1).toLowerCase() === "g".toLowerCase()))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass shadow check 1",}, b0, false, false, "aq", null); +runtime.ext_scratch3_looks._say("pass shadow check 1", target); } -b1.value = thread.procedures["Zno shadowing 2 %s %s"](1,2); +b0.value = thread.procedures["Zno shadowing 2 %s %s"](1,2); if (((("" + p0).toLowerCase() === "f".toLowerCase()) && (("" + p1).toLowerCase() === "g".toLowerCase()))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass shadow check 2",}, b0, false, false, "au", null); +runtime.ext_scratch3_looks._say("pass shadow check 2", target); } -b1.value = thread.procedures["Zno shadowing 2 %s %s"](3,4); +b0.value = thread.procedures["Zno shadowing 2 %s %s"](3,4); if (((("" + p0).toLowerCase() === "f".toLowerCase()) && (("" + p1).toLowerCase() === "g".toLowerCase()))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass shadow check 3",}, b0, false, false, "ax", null); +runtime.ext_scratch3_looks._say("pass shadow check 3", target); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot index 5de5f025e88..287090d5661 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-stops-scripts.sb3.tw-snapshot @@ -3,26 +3,24 @@ // 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["PsAI*C{QHI3*4?O8p#TM"]; +const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "f", null); +runtime.ext_scratch3_looks._say("plan 2", target); yield* thread.procedures["Wreturn stops the script immediately"](); -if ((toNotNaN(+b1.value) === 25)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass return stopped the script immediately",}, b0, false, false, "u", null); +if ((toNotNaN(+b0.value) === 25)) { +runtime.ext_scratch3_looks._say("pass return stopped the script immediately", target); } yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "Test return outside of custom block" })); -if ((toNotNaN(+b1.value) === 18)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass return worked to stop outside of custom block",}, b0, false, false, "x", null); +if ((toNotNaN(+b0.value) === 18)) { +runtime.ext_scratch3_looks._say("pass return worked to stop outside of custom block", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "v", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 Wreturn stops the script immediately (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["PsAI*C{QHI3*4?O8p#TM"]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_return_stops_the_scr () { b0.value = 0; for (var a0 = 100; a0 > 0; a0--) { @@ -32,7 +30,7 @@ return "stopped!"; } if (isStuck()) yield; } -yield* executeInCompatibilityLayer({"MESSAGE":"fail return did not stop the script immediately",}, b1, true, false, "z", null); +runtime.ext_scratch3_looks._say("fail return did not stop the script immediately", target); return ""; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot index 289eeb63e3c..d6cbaab4dff 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-procedure-return-warp.sb3.tw-snapshot @@ -23,19 +23,17 @@ retire(); return; // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 3",}, b0, false, false, "k", null); +runtime.ext_scratch3_looks._say("plan 3", target); yield* thread.procedures["Znon warp"](); runtime.stopForTarget(target, thread); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "N", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 Znon warp (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_non_warp () { b0.value = 0; for (var a0 = 5; a0 > 0; a0--) { @@ -50,10 +48,10 @@ thread.timer = null; yield; } if ((toNotNaN(+b0.value) === 5)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 1",}, b1, false, false, "R", null); +runtime.ext_scratch3_looks._say("pass non warp 1", target); } if ((("" + (yield* thread.procedures["Wverify runs warp %s"]((yield* thread.procedures["Zverify runs non warp %s"]((yield* thread.procedures["Wverify runs warp %s"]("abc"))))))).toLowerCase() === "warp: non warp: warp: abc".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp and warp mix",}, b1, false, false, "S", null); +runtime.ext_scratch3_looks._say("pass non warp and warp mix", target); } b0.value = 0; for (var a2 = 5; a2 > 0; a2--) { @@ -68,7 +66,7 @@ thread.timer = null; yield; } if ((toNotNaN(+b0.value) === 5)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non warp 2",}, b1, false, false, "W", null); +runtime.ext_scratch3_looks._say("pass non warp 2", target); } return ""; }; }) @@ -76,7 +74,6 @@ return ""; // Sprite1 Wverify runs warp %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_verify_runs_warp_ (p0) { b0.value = 0; for (var a0 = 5; a0 > 0; a0--) { @@ -90,7 +87,7 @@ thread.timer = null; if (isStuck()) yield; } if (!compareEqual(b0.value, 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail did not run warp",}, b1, true, false, "Z", null); +runtime.ext_scratch3_looks._say("fail did not run warp", target); } return ("warp: " + ("" + p0)); return ""; @@ -99,7 +96,6 @@ return ""; // Sprite1 Zverify runs non warp %s (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Go=PJS7BFXYo_qi2S:kQ"]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_verify_runs_non_warp (p0) { b0.value = 0; for (var a0 = 5; a0 > 0; a0--) { @@ -114,7 +110,7 @@ thread.timer = null; yield; } if (compareEqual(b0.value, 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail ran warp",}, b1, false, false, "L", null); +runtime.ext_scratch3_looks._say("fail ran warp", target); } return ("non warp: " + ("" + p0)); return ""; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot index 4c166406d91..608f12c0515 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot @@ -5,15 +5,14 @@ (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["JbF5exWEi*m?-UEmkASS"]; const b1 = stage.variables["[G/@.KGc-4y[(GZ(bt7o"]; -const b2 = runtime.getOpcodeFunction("looks_say"); -const b3 = runtime.getOpcodeFunction("sound_seteffectto"); +const b2 = runtime.getOpcodeFunction("sound_seteffectto"); return function* genXYZ () { while (true) { if (compareEqual(b0.value, b1.value)) { } else { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b2, false, false, "89/dl$1dp$~nj81:jj@H", null); +runtime.ext_scratch3_looks._say("pass", target); b1.value = b0.value; -yield* executeInCompatibilityLayer({"VALUE":b0.value,"EFFECT":"pitch",}, b3, false, true, "*=8r,g4Pzvxo?aSMcpfX", null); +yield* executeInCompatibilityLayer({"VALUE":b0.value,"EFFECT":"pitch",}, b2, false, true, "*=8r,g4Pzvxo?aSMcpfX", null); if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} } yield; @@ -24,16 +23,15 @@ retire(); return; // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["[G/@.KGc-4y[(GZ(bt7o"]; -const b1 = runtime.getOpcodeFunction("looks_say"); -const b2 = stage.variables["JbF5exWEi*m?-UEmkASS"]; +const b1 = stage.variables["JbF5exWEi*m?-UEmkASS"]; return function* genXYZ () { b0.value = 0; -yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b1, false, false, "0/2-)Gp^^=haQ1OMD.xb", null); +runtime.ext_scratch3_looks._say("plan 15", target); for (var a0 = 15; a0 > 0; a0--) { -if ((toNotNaN(+b2.value) === 200)) { -b2.value = 50; +if ((toNotNaN(+b1.value) === 200)) { +b1.value = 50; } else { -b2.value = 200; +b1.value = 200; } thread.timer = timer(); var a1 = Math.max(0, 1000 * 0); @@ -45,7 +43,7 @@ yield; thread.timer = null; yield; } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b1, false, false, "--nBRXyJfqS0MM9`#S3}", null); +runtime.ext_scratch3_looks._say("end", target); runtime.stopAll(); retire(); return; retire(); return; diff --git a/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot index 35a0f59d7b1..e0cb864a348 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-repeat-analysis-doesnt-reanalyze.sb3.tw-snapshot @@ -3,15 +3,14 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); +runtime.ext_scratch3_looks._say("plan 1", target); yield* thread.procedures["Wa"](); -if ((("" + b1.value).toLowerCase() === "bwah".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "l", null); +if ((("" + b0.value).toLowerCase() === "bwah".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "k", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot index 08bf6005e3c..6755ac7e301 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot @@ -3,11 +3,10 @@ // Text script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a~", null); +runtime.ext_scratch3_looks._say("plan 0", target); yield* thread.procedures["Wtest 1"](); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "dh", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-restart-broadcast-threads.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-restart-broadcast-threads.sb3.tw-snapshot index 2356e02f907..8da7bc06f09 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-restart-broadcast-threads.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-restart-broadcast-threads.sb3.tw-snapshot @@ -3,11 +3,10 @@ // Sprite2 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "aQ(Y!Bs3;[rV^Q%AQ,NX", null); -b1.value = 0; +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = 0; startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); thread.timer = timer(); @@ -18,10 +17,10 @@ while (thread.timer.timeElapsed() < a0) { yield; } thread.timer = null; -if ((toNotNaN(+b1.value) === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "`SX*FG*Lwo*0_T=box-@", null); +if ((toNotNaN(+b0.value) === 1)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "|#`zzPA_x%{`FyIAQhb4", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot index d92f0cf7405..27fd3590b47 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-rotate-by-decimal-without-leading-zero.sb3.tw-snapshot @@ -3,15 +3,14 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); +runtime.ext_scratch3_looks._say("plan 1", target); target.setDirection(90); target.setDirection((target.direction + 0.25)); target.setDirection((target.direction + 0.25)); if ((target.direction === 90.5)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "i", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "h", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot index aff4757d938..98631100e00 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-safe-procedure-argument-casting.sb3.tw-snapshot @@ -3,18 +3,17 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "J#qm1yA(@Z6mj%Mgh;0X", null); +runtime.ext_scratch3_looks._say("plan 2", target); thread.procedures["Zswitch %s"]("1"); if ((((target.currentCostume + 1) === 2) && (toNotNaN(+target.getCostumes()[target.currentCostume].name) === 1))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ";DM$.QW6o-O+T/oBdqt!", null); +runtime.ext_scratch3_looks._say("pass", target); } thread.procedures["Zswitch %s"]("2"); if ((((target.currentCostume + 1) === 1) && (toNotNaN(+target.getCostumes()[target.currentCostume].name) === 2))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "71a9Slk0w=^~x;5T@nw,", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "$R-1lb(Mu?gdTIH^;kC_", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot index ff8ab6ec888..accaed1f172 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot @@ -3,13 +3,12 @@ // 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["G{NQ*NXG*qzywe1Q3?FM"]; -const b2 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +const b0 = stage.variables["G{NQ*NXG*qzywe1Q3?FM"]; +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = 0; b1.value = 0; -b2.value = 0; startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); retire(); return; }; }) @@ -18,7 +17,6 @@ retire(); return; (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["G{NQ*NXG*qzywe1Q3?FM"]; -const b2 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { if (compareEqual(b0.value, 0)) { b0.value = 1; @@ -30,9 +28,9 @@ yield; b1.value = 2; } else { if ((toNotNaN(+b1.value) === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b2, false, false, "p", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b2, false, false, "n", null); +runtime.ext_scratch3_looks._say("end", target); } retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot index b15bc894fa8..fa2c818d9ba 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot @@ -3,112 +3,111 @@ // Sprite2 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 && stage.lookupVariableByNameAndType("Stage variable", "", true); -const b2 = runtime.getSpriteTargetByName("Test sprite"); -const b3 = b2 && b2.lookupVariableByNameAndType("Private variable", "", true); -const b4 = stage && stage.lookupVariableByNameAndType("This variable used to exist", "", true); -const b5 = stage.variables["GTmK+*w8mNQP,z`4WG8#"]; -const b6 = runtime.getSpriteTargetByName("Sprite that doesn't exist"); +const b0 = stage && stage.lookupVariableByNameAndType("Stage variable", "", true); +const b1 = runtime.getSpriteTargetByName("Test sprite"); +const b2 = b1 && b1.lookupVariableByNameAndType("Private variable", "", true); +const b3 = stage && stage.lookupVariableByNameAndType("This variable used to exist", "", true); +const b4 = stage.variables["GTmK+*w8mNQP,z`4WG8#"]; +const b5 = runtime.getSpriteTargetByName("Sprite that doesn't exist"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 32",}, b0, false, false, "oX(r}qUQo7fd[u~D_4@T", null); +runtime.ext_scratch3_looks._say("plan 32", target); if (((stage.currentCostume + 1) === 2)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass backdrop #",}, b0, false, false, "T9..K[5LEO1f~{%eoPU;", null); +runtime.ext_scratch3_looks._say("pass backdrop #", target); } if ((stage.getCostumes()[stage.currentCostume].name.toLowerCase() === "Backdrop name test".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass backdrop name",}, b0, false, false, "q63|^NKAu?OMK%W-s}+~", null); +runtime.ext_scratch3_looks._say("pass backdrop name", target); } if (((stage ? stage.volume : 0) === 45)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass stage volume",}, b0, false, false, "9Coi(uM:DG!WPZ($,SnY", null); +runtime.ext_scratch3_looks._say("pass stage volume", target); } -if ((("" + (b1 ? b1.value : 0)).toLowerCase() === "Variable in stage".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass stage variable",}, b0, false, false, "D_EA]xN%|[NsTKqc4up9", null); +if ((("" + (b0 ? b0.value : 0)).toLowerCase() === "Variable in stage".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass stage variable", target); } -if (((b2 ? b2.x : 0) === 19)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass x",}, b0, false, false, "ek^n,6zjHyX;YOW;H@]?", null); +if (((b1 ? b1.x : 0) === 19)) { +runtime.ext_scratch3_looks._say("pass x", target); } -if (((b2 ? b2.y : 0) === 20)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass y",}, b0, false, false, "-DZ%ny~~x.m12l9I64~W", null); +if (((b1 ? b1.y : 0) === 20)) { +runtime.ext_scratch3_looks._say("pass y", target); } -if (((b2 ? b2.direction : 0) === 89)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass direction",}, b0, false, false, "$Y=E2o@3oa-^OHt5v:-b", null); +if (((b1 ? b1.direction : 0) === 89)) { +runtime.ext_scratch3_looks._say("pass direction", target); } -if (((b2 ? b2.currentCostume + 1 : 0) === 3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass costume #",}, b0, false, false, "+zO[+f?c7F`ZGTbD.oqI", null); +if (((b1 ? b1.currentCostume + 1 : 0) === 3)) { +runtime.ext_scratch3_looks._say("pass costume #", target); } -if (((b2 ? b2.getCostumes()[b2.currentCostume].name : 0).toLowerCase() === "Costume name test".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass costume name",}, b0, false, false, "Y6L|T0Pvwsct2gq+HGvv", null); +if (((b1 ? b1.getCostumes()[b1.currentCostume].name : 0).toLowerCase() === "Costume name test".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass costume name", target); } -if (((b2 ? b2.size : 0) === 76.01)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass size",}, b0, false, false, "IBZv@o)qX~r6)!;hqaWa", null); +if (((b1 ? b1.size : 0) === 76.01)) { +runtime.ext_scratch3_looks._say("pass size", target); } -if (((b2 ? b2.volume : 0) === 14.3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass volume",}, b0, false, false, "JBHJ,)N)@]~;;yFTY`RG", null); +if (((b1 ? b1.volume : 0) === 14.3)) { +runtime.ext_scratch3_looks._say("pass volume", target); } -if ((("" + (b3 ? b3.value : 0)).toLowerCase() === "Private variable value".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass private variable",}, b0, false, false, "#jYbx])r8^`95~ZgPtZD", null); +if ((("" + (b2 ? b2.value : 0)).toLowerCase() === "Private variable value".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass private variable", target); } -if (compareEqual((b4 ? b4.value : 0), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent variable",}, b0, false, false, ")nnN?*l+E)dC(fT5(_@q", null); +if (compareEqual((b3 ? b3.value : 0), 0)) { +runtime.ext_scratch3_looks._say("pass non existent variable", target); } -b5.value = (("" + randomInt(1, 9)) + ("" + randomInt(1, 9))); -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b5.value, PROPERTY: "backdrop #" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop #",}, b0, false, false, "UFr{fbR3@a.u_paq:r]F", null); +b4.value = (("" + randomInt(1, 9)) + ("" + randomInt(1, 9))); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "backdrop #" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE backdrop #", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "backdrop name" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop name",}, b0, false, false, "wzVsIitt0^t(wDS-V3?Z", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "backdrop name" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE backdrop name", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "volume" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE volume",}, b0, false, false, ":SZx%]xR5t`;;@M~:jT:", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "volume" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE volume", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "Stage variable" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE stage variable",}, b0, false, false, "!eEjdEJj!yYb{buag^M[", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "Stage variable" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE stage variable", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "x position" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE x",}, b0, false, false, "!6!o,FiLV=w2bS~{R|AK", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "x position" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE x", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "y position" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE y",}, b0, false, false, "5K7_7*adzRDbfFjxanQF", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "y position" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE y", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "direction" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE direction",}, b0, false, false, "D{z)e;(*H|.gAykbuSkE", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "direction" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE direction", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "costume #" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE costume #",}, b0, false, false, "WgCH3j9ObHA,;P3T=now", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "costume #" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE costume #", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "costume name" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE costume name",}, b0, false, false, "qhxQy$^wiOTOEu.=2^i)", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "costume name" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE costume name", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "size" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE size",}, b0, false, false, "+6V.t=]xZ=Gl?%-OWbFy", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "size" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE size", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "volume" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE volume",}, b0, false, false, "*E:B}?C@H2ce2uRr9.9=", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "volume" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE volume", target); } -if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: ("" + b5.value), PROPERTY: "Private variable" }), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE private variable",}, b0, false, false, "B6r;3{7R7g4Z.pzeGiCM", null); +if (compareEqual(runtime.ext_scratch3_sensing.getAttributeOf({OBJECT: b4.value, PROPERTY: "Private variable" }), 0)) { +runtime.ext_scratch3_looks._say("pass NE private variable", target); } -if (((b6 ? b6.x : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop #",}, b0, false, false, "q[X%xv.u6==Riu20?y{I", null); +if (((b5 ? b5.x : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE backdrop #", target); } -if (((b6 ? b6.y : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE backdrop name",}, b0, false, false, "?M4CH@e3~]30+$4[brH[", null); +if (((b5 ? b5.y : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE backdrop name", target); } -if (((b6 ? b6.direction : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE volume",}, b0, false, false, "H:D~v_)nZ?oJ8X|qHag#", null); +if (((b5 ? b5.direction : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE volume", target); } -if (((b6 ? b6.currentCostume + 1 : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE stage variable",}, b0, false, false, "lqwZ[26e,$PwYz,OlO0X", null); +if (((b5 ? b5.currentCostume + 1 : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE stage variable", target); } -if (compareEqual((b6 ? b6.getCostumes()[b6.currentCostume].name : 0), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE x",}, b0, false, false, "I@zdHi0kl|{:ze_J.}S_", null); +if (compareEqual((b5 ? b5.getCostumes()[b5.currentCostume].name : 0), 0)) { +runtime.ext_scratch3_looks._say("pass NE x", target); } -if (((b6 ? b6.size : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE y",}, b0, false, false, "qD{Ni|{SL:`04:Gj/A7B", null); +if (((b5 ? b5.size : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE y", target); } -if (((b6 ? b6.volume : 0) === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass NE direction",}, b0, false, false, "vvB(iq@jjvj{=_{:6DXZ", null); +if (((b5 ? b5.volume : 0) === 0)) { +runtime.ext_scratch3_looks._say("pass NE direction", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "dJRK.)mKX6,r26Jy]5qr", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot index 12e9d04658b..e0a9fa06438 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-simple-string-operations.sb3.tw-snapshot @@ -3,15 +3,14 @@ // 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["PJl9-2GypE.OstQk*B_*"]; +const b0 = stage.variables["PJl9-2GypE.OstQk*B_*"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); +runtime.ext_scratch3_looks._say("plan 1", target); yield* thread.procedures["Wa"](); -if ((("" + b1.value).toLowerCase() === "babab".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "s", null); +if ((("" + b0.value).toLowerCase() === "babab".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "q", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) 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 index 3e809112dd6..69eaca7f0d6 100644 --- 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 @@ -3,19 +3,18 @@ // 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 b0 = 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._say("plan 2", target); +b0.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._say("pass initial costume", target); } -runtime.ext_scratch3_looks._setCostume(target, b1.value); +runtime.ext_scratch3_looks._setCostume(target, b0.value); if (((target.currentCostume + 1) === 3)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass costume \"5\"",}, b0, false, false, "m", null); +runtime.ext_scratch3_looks._say("pass costume \"5\"", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-stage-cannot-move-layers.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-stage-cannot-move-layers.sb3.tw-snapshot index a19e0ba91c0..685797599df 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-stage-cannot-move-layers.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-stage-cannot-move-layers.sb3.tw-snapshot @@ -3,11 +3,10 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "5,snC%48IW(1ZVM(k0l2", null); -b1.value = "Initial"; +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = "Initial"; thread.timer = timer(); var a0 = Math.max(0, 1000 * 0); runtime.requestRedraw(); @@ -17,17 +16,16 @@ yield; } thread.timer = null; yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "Test 1" })); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "5.$W?rkoLYkKo1qX@%@?", null); +runtime.ext_scratch3_looks._say("end", target); 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).toLowerCase() === "Initial".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b1, false, false, "eR%8T)3MQjkbQkAh~L0%", null); +runtime.ext_scratch3_looks._say("pass", target); } 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 index 7530899818e..0078fee3bd0 100644 --- 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 @@ -3,16 +3,15 @@ // 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"]; +const b0 = stage.variables["KMKx1gRubgLz,!L]^TBS"]; +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); +runtime.ext_scratch3_looks._say("plan 1", target); thread.procedures["Wtest"](); -if ((("" + listGet(b1.value, b2.value)).toLowerCase() === "thing".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "m", null); +if ((("" + listGet(b0.value, b1.value)).toLowerCase() === "thing".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-subtract-can-return-nan.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-subtract-can-return-nan.sb3.tw-snapshot index e784ce8a4bd..d48db9ac3fa 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-subtract-can-return-nan.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-subtract-can-return-nan.sb3.tw-snapshot @@ -3,12 +3,11 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "6_?4sPB-|g:DtjdOm5Q-", null); +runtime.ext_scratch3_looks._say("plan 1", target); if (!((Infinity - Infinity) <= 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ")-u2YbbMb;gXMPOidjPj", null); +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "zqE}hdaes.b)@mO1{R;X", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-tab-equals-zero.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-tab-equals-zero.sb3.tw-snapshot index 119556a43f1..a55f7db71ab 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-tab-equals-zero.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-tab-equals-zero.sb3.tw-snapshot @@ -3,11 +3,10 @@ // 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["Kl,Own0m6{^v3$E{Wsc="]; +const b0 = stage.variables["Kl,Own0m6{^v3$E{Wsc="]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 6",}, b0, false, false, "i", null); -b1.value = "\t"; +runtime.ext_scratch3_looks._say("plan 6", target); +b0.value = "\t"; startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); retire(); return; }; }) @@ -15,26 +14,25 @@ retire(); return; // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["Kl,Own0m6{^v3$E{Wsc="]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { if (compareEqual(b0.value, ("0" + ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t in a variable = string 0",}, b1, false, false, "q", null); +runtime.ext_scratch3_looks._say("pass \\t in a variable = string 0", target); } if (compareEqual("\t", ("0" + ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass literal \\t = string 0",}, b1, false, false, "u", null); +runtime.ext_scratch3_looks._say("pass literal \\t = string 0", target); } if (compareEqual((" " + ("" + b0.value)), ("0" + ""))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t and other spaces = string 0",}, b1, false, false, "w", null); +runtime.ext_scratch3_looks._say("pass \\t and other spaces = string 0", target); } if (compareEqual(b0.value, (0 + 0))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t in a variable = number 0",}, b1, false, false, "z", null); +runtime.ext_scratch3_looks._say("pass \\t in a variable = number 0", target); } if ((0 === (0 + 0))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass literal \\t = number 0",}, b1, false, false, "B", null); +runtime.ext_scratch3_looks._say("pass literal \\t = number 0", target); } if (compareEqual((" " + ("" + b0.value)), (0 + 0))) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass \\t and other spaces = number 0",}, b1, false, false, "E", null); +runtime.ext_scratch3_looks._say("pass \\t and other spaces = number 0", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b1, false, false, "D", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot index 41796eb6fd9..0fae46c5922 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-tangent.sb3.tw-snapshot @@ -3,54 +3,53 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 15",}, b0, false, false, "p", null); +runtime.ext_scratch3_looks._say("plan 15", target); if (compareEqual(tan(0), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 0",}, b0, false, false, "O", null); +runtime.ext_scratch3_looks._say("pass 0", target); } if ((toNotNaN(tan(90)) === Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 90",}, b0, false, false, "G", null); +runtime.ext_scratch3_looks._say("pass 90", target); } if (compareEqual(tan(180), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 180",}, b0, false, false, "I", null); +runtime.ext_scratch3_looks._say("pass 180", target); } if ((toNotNaN(tan(270)) === -Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 270",}, b0, false, false, "K", null); +runtime.ext_scratch3_looks._say("pass 270", target); } if (compareEqual(tan(360), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 360",}, b0, false, false, "M", null); +runtime.ext_scratch3_looks._say("pass 360", target); } if ((toNotNaN(tan(450)) === Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 450",}, b0, false, false, "Q", null); +runtime.ext_scratch3_looks._say("pass 450", target); } if (compareEqual(tan(540), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 540",}, b0, false, false, "S", null); +runtime.ext_scratch3_looks._say("pass 540", target); } if ((toNotNaN(tan(630)) === -Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 630",}, b0, false, false, "U", null); +runtime.ext_scratch3_looks._say("pass 630", target); } if (compareEqual(tan(720), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 720",}, b0, false, false, "W", null); +runtime.ext_scratch3_looks._say("pass 720", target); } if ((toNotNaN(tan(810)) === Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 810",}, b0, false, false, "Y", null); +runtime.ext_scratch3_looks._say("pass 810", target); } if ((toNotNaN(tan(-90)) === -Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass -90",}, b0, false, false, "0", null); +runtime.ext_scratch3_looks._say("pass -90", target); } if (compareEqual(tan(-180), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass -180",}, b0, false, false, "2", null); +runtime.ext_scratch3_looks._say("pass -180", target); } if ((toNotNaN(tan(-270)) === Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass -270",}, b0, false, false, "4", null); +runtime.ext_scratch3_looks._say("pass -270", target); } if (compareEqual(tan(-360), 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass -360",}, b0, false, false, "6", null); +runtime.ext_scratch3_looks._say("pass -360", target); } if ((toNotNaN(tan(-450)) === -Infinity)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass -450",}, b0, false, false, "9", null); +runtime.ext_scratch3_looks._say("pass -450", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "8", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot index 014751f5d1e..060a0aa20bf 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot @@ -3,84 +3,81 @@ // Sprite2 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[",OktMIwz{~bdgWnPEa8u"]; -const b2 = stage.variables["yfy(G`K5K^fJcXAfiN4i"]; +const b0 = stage.variables[",OktMIwz{~bdgWnPEa8u"]; +const b1 = stage.variables["yfy(G`K5K^fJcXAfiN4i"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 14",}, b0, false, false, "S8W[CSRh5A:[y8s/Ridj", null); +runtime.ext_scratch3_looks._say("plan 14", target); if ((10 === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 1",}, b0, false, false, "1ove2a-$DQw7qy5PGdgq", null); +runtime.ext_scratch3_looks._say("pass 1", target); } if ((10 === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 2",}, b0, false, false, "@A5}x{mm-Gk?CVz3o0Yn", null); +runtime.ext_scratch3_looks._say("pass 2", target); } -b1.value = 10; -if ((b1.value === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 3",}, b0, false, false, "Ul:BCck-}Fvdux~x#$${", null); +b0.value = 10; +if ((b0.value === 10)) { +runtime.ext_scratch3_looks._say("pass 3", target); } -if ((toNotNaN(+b1.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 4",}, b0, false, false, "8]2$7P)o#+#Lo]mFSBbx", null); +if ((b0.value === 10)) { +runtime.ext_scratch3_looks._say("pass 4", target); } -if ((toNotNaN(+b1.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 5",}, b0, false, false, "ZU^{OfKTg|+Au$$q0[]u", null); +if ((b0.value === 10)) { +runtime.ext_scratch3_looks._say("pass 5", target); } for (var a0 = 1; a0 > 0; a0--) { -if ((toNotNaN(+b1.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 6",}, b0, false, false, "HB+_IN}6=K[*ksxKXH0`", null); +if ((toNotNaN(+b0.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 6", target); } -if ((toNotNaN(+b1.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 7",}, b0, false, false, ";73ODiwcp8IthYURTX;S", null); +if ((toNotNaN(+b0.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 7", target); } -if ((toNotNaN(+b1.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 8",}, b0, false, true, "${[MFmBL-D*1rbas9Q89", null); -if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} +if ((toNotNaN(+b0.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 8", target); } yield; } -b2.value = "010"; -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 9",}, b0, false, false, "#.`@SBj!g-c0:_q/tMZo", null); +b1.value = "010"; +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 9", target); } -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 10",}, b0, false, false, "B`o?V6/q6g),/2w};a#y", null); +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 10", target); } -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 11",}, b0, false, false, "TJ:#TkYBys*!RYiKLXb)", null); +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 11", target); } for (var a1 = 1; a1 > 0; a1--) { -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 12",}, b0, false, false, ",Z,~10Qo~j;(+VL+I3q:", null); +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 12", target); } -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 13",}, b0, false, false, "|Mqx([(26M%#ggW9)U0s", null); +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 13", target); } -if ((toNotNaN(+b2.value) === 10)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass 14",}, b0, false, true, "YvtiKF231lU8p5Qd97RP", null); -if (hasResumedFromPromise) {hasResumedFromPromise = false;continue;} +if ((toNotNaN(+b1.value) === 10)) { +runtime.ext_scratch3_looks._say("pass 14", target); } yield; } if ((0 === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "yO!,nQodLC}uqIc?212+", null); +runtime.ext_scratch3_looks._say("fail", target); } if ((1 === 0)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "XzQt!.^A,SV?q0`Ui)wG", null); +runtime.ext_scratch3_looks._say("fail", target); } if ((0 === 1)) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "rxZqw7cv8g;PDM4B%{`?", null); +runtime.ext_scratch3_looks._say("fail", target); } if ((" ".toLowerCase() === "0".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "3G|)eVw1mQm;O~cRy`}0", null); +runtime.ext_scratch3_looks._say("fail", target); } if (("0".toLowerCase() === " ".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "sd5xXX*tsW/~A_Q!0;^w", null); +runtime.ext_scratch3_looks._say("fail", target); } if (("".toLowerCase() === "0".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "7**baE=].WD9OoY1+IEu", null); +runtime.ext_scratch3_looks._say("fail", target); } if (("0".toLowerCase() === "".toLowerCase())) { -yield* executeInCompatibilityLayer({"MESSAGE":"fail",}, b0, false, false, "7!IB!=o/2H.Jqj-8Vwhz", null); +runtime.ext_scratch3_looks._say("fail", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "df{tf!WhfRwXgQ?SN_dj", null); +runtime.ext_scratch3_looks._say("end", target); retire(); 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 index 4312367087b..02b2fc4738c 100644 --- 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 @@ -3,16 +3,15 @@ // 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 b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "e", null); +runtime.ext_scratch3_looks._say("plan 0", target); startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" }); -b1.value = "bwah"; -while (!(("" + b1.value).toLowerCase() === "bleh".toLowerCase())) { +b0.value = "bwah"; +while (!(("" + b0.value).toLowerCase() === "bleh".toLowerCase())) { yield; } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "h", null); +runtime.ext_scratch3_looks._say("end", target); 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 index 68a39552235..07d15df6d08 100644 --- 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 @@ -3,23 +3,22 @@ // 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"]; +const b0 = stage.variables[";~q(!vt3c.Jrz2M]ZMy]"]; +const b1 = 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; +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = []; +b0.value.push((1 + 2)); +b0._monitorUpToDate = false; +b0.value.push((3 + 4)); +b0._monitorUpToDate = false; +b0.value.push("final"); +b0._monitorUpToDate = false; yield* thread.procedures["Wtest"](); -if ((toNotNaN(+b2.value) === 4)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "u", null); +if ((toNotNaN(+b1.value) === 4)) { +runtime.ext_scratch3_looks._say("pass", target); } -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "t", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot index 8f918a81081..90dd7011df2 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot @@ -3,18 +3,16 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); +runtime.ext_scratch3_looks._say("plan 1", target); yield* thread.procedures["Wrun without screen refresh"](); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "s", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 Wrun without screen refresh (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); const b0 = stage.variables["F?*}X,`9XBpN_[piGRrz"]; -const b1 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ_run_without_screen_r () { b0.value = ((daysSince2000() * 86400) + 3); runtime.ioDevices.clock.resetProjectTimer(); @@ -22,7 +20,7 @@ while (!((runtime.ioDevices.clock.projectTimer() > 0.1) || compareGreaterThan((d if (isStuck()) yield; } if (compareLessThan((daysSince2000() * 86400), b0.value)) { -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b1, true, false, "u", null); +runtime.ext_scratch3_looks._say("pass", target); } return ""; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot index 20e97770379..8b5cdd42bd8 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot @@ -3,17 +3,15 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Ny4npe`j3|CTeaIS.:6O", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "2T.vCF,K}vA=XNZ=kY+v", null); +runtime.ext_scratch3_looks._say("plan 0", target); runtime.ext_scratch3_looks._setBackdrop(stage, stage.currentCostume + 1, true); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot index c8479702223..a6ef03ebdb4 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot @@ -3,17 +3,15 @@ // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Ny4npe`j3|CTeaIS.:6O", null); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) // Sprite1 script (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); -const b0 = runtime.getOpcodeFunction("looks_say"); return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "2T.vCF,K}vA=XNZ=kY+v", null); +runtime.ext_scratch3_looks._say("plan 0", target); runtime.ext_scratch3_looks._setBackdrop(stage, "backdrop2"); retire(); return; }; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot index 229d2814438..7ed5bde1fc6 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-zombie-cube-escape-284516654.sb3.tw-snapshot @@ -3,19 +3,18 @@ // Sprite2 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["7qur6!bGgvC9I(Nd5.HP"]; -const b2 = stage.variables["sUOp@-6J4y0PqwiXit4!"]; +const b0 = stage.variables["7qur6!bGgvC9I(Nd5.HP"]; +const b1 = stage.variables["sUOp@-6J4y0PqwiXit4!"]; return function* genXYZ () { -yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, ",a.euo_AgQTxR+D^x0M0", null); -b1.value = 0; -b2.value = ""; -while (!(("" + b2.value).toLowerCase() > "".toLowerCase())) { +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = 0; +b1.value = ""; +while (!(("" + b1.value).toLowerCase() > "".toLowerCase())) { startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "step" }); yield; } -yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "miAC8JZ$@akv[+}KR*@B", null); -yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "gXJU#lhy3A3XA_s[-Xs$", null); +runtime.ext_scratch3_looks._say("pass", target); +runtime.ext_scratch3_looks._say("end", target); retire(); return; }; }) From 36bf998aee534735ce84c67d1ac0e00c72e44f12 Mon Sep 17 00:00:00 2001 From: 8to16 <197376797+ampelectrecuted@users.noreply.github.com> Date: Tue, 16 Dec 2025 00:51:13 +0000 Subject: [PATCH 079/106] Fix evalAndReturn with comments at the bottom of a script (#322) This is because beepbox's script: https://cdn.jsdelivr.net/npm/beepbox@4.2.0/global/beepbox_synth.min.js has a sourceMappingURL comment at the bottom for whatever reason, causing it to become //# sourceMappingURL=beepbox_synth.min.js.map;return beepbox; This is obviously going to break and might also be the case with other libraries too, hot just beepbox. Ported from AmpMod: https://codeberg.org/ampmod/ampmod/commit/0daf1021bdc8e67a1f0d08b91ce500605fcaa711 --- src/extension-support/tw-external.js | 2 +- test/unit/tw_external.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/extension-support/tw-external.js b/src/extension-support/tw-external.js index de7b3a9ad47..d4b5bf40028 100644 --- a/src/extension-support/tw-external.js +++ b/src/extension-support/tw-external.js @@ -79,7 +79,7 @@ external.blob = async url => { external.evalAndReturn = async (url, returnExpression) => { const res = await external.fetch(url); const text = await res.text(); - const js = `${text};return ${returnExpression}`; + const js = `${text}\nreturn ${returnExpression};`; const fn = new Function(js); return fn(); }; diff --git a/test/unit/tw_external.js b/test/unit/tw_external.js index 745c694bcdc..2110412d305 100644 --- a/test/unit/tw_external.js +++ b/test/unit/tw_external.js @@ -50,6 +50,13 @@ test('evalAndReturn', t => { }); }); +test('evalAndReturn with a trailing comment without newline', t => { + external.evalAndReturn('data:text/plain;,var%20x=20 // whatever', 'x').then(result => { + t.equal(result, 20); + t.end(); + }); +}); + test('relative URL throws', t => { external.fetch('./test.js').catch(err => { t.equal(err.message, `Unsupported URL: ./test.js`); From 779f0a196da280339f522d43ee92bb2abed81f4e Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 29 Dec 2025 18:47:04 -0600 Subject: [PATCH 080/106] Add no-op rAF loop to improve frame pacing It is still not perfect. Better though Fixes https://github.com/TurboWarp/scratch-vm/issues/257 Closes https://github.com/TurboWarp/scratch-vm/pull/324 (this one uses a different approach and restricts to 30 FPS and checks if the platform is known to benefit before we turn on battery draining workarounds) --- src/engine/tw-frame-loop.js | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/engine/tw-frame-loop.js b/src/engine/tw-frame-loop.js index 45423739623..bf2554b452e 100644 --- a/src/engine/tw-frame-loop.js +++ b/src/engine/tw-frame-loop.js @@ -22,6 +22,21 @@ const animationFrameWrapper = callback => { }; }; +/** + * We've found that having an empty requestAnimationFrame loop running in the background improves frame + * pacing in many situations. See https://github.com/TurboWarp/scratch-vm/issues/257. + * + * Having an extra loop running increases CPU usage and battery usage even if it's not doing anything. + * So, we only do this when the intended framerate is high enough that the user clearly wants smooth + * motion, and only if the user is on a platform where we have evidence that this helps: + * - Chrome, Edge, and other Chromium on Windows + * + * @param {number} framerate Intended framerate + * @returns {boolean} true if no-op animation frame loop should be used + */ +const shouldUseNoopAnimationFrame = framerate => + framerate >= 30 && navigator.userAgent.includes('Chrome') && navigator.userAgent.includes('Windows'); + class FrameLoop { constructor (runtime) { this.runtime = runtime; @@ -35,6 +50,7 @@ class FrameLoop { this._stepInterval = null; this._interpolationAnimation = null; this._stepAnimation = null; + this._noopAnimation = null; } setFramerate (fps) { @@ -55,6 +71,10 @@ class FrameLoop { this.runtime._renderInterpolatedPositions(); } + noopCallback () { + // intentional no-op, see shouldUseNoopAnimationFrame() + } + _restart () { if (this.running) { this.stop(); @@ -71,6 +91,8 @@ class FrameLoop { // Interpolation should never be enabled when framerate === 0 as that's just redundant if (this.interpolation) { this._interpolationAnimation = animationFrameWrapper(this.interpolationCallback); + } else if (shouldUseNoopAnimationFrame(this.framerate)) { + this._noopAnimation = animationFrameWrapper(this.noopCallback); } this._stepInterval = setInterval(this.stepCallback, 1000 / this.framerate); this.runtime.currentStepTime = 1000 / this.framerate; @@ -82,12 +104,16 @@ class FrameLoop { clearInterval(this._stepInterval); if (this._interpolationAnimation) { this._interpolationAnimation.cancel(); + this._interpolationAnimation = null; } if (this._stepAnimation) { this._stepAnimation.cancel(); + this._stepAnimation = null; + } + if (this._noopAnimation) { + this._noopAnimation.cancel(); + this._noopAnimation = null; } - this._interpolationAnimation = null; - this._stepAnimation = null; } } From 7aa8930802e6da11fb29c24939998c2a94b3d2cd Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sun, 28 Dec 2025 17:58:28 -0600 Subject: [PATCH 081/106] Fix incorrect types for sensing_of They can return 0 if the sprite does not exist Fixes https://github.com/TurboWarp/scratch-vm/issues/262 Closes https://github.com/TurboWarp/scratch-vm/pull/325 (this one uses a different fix and has tests) There are broader issues about compiled sensing_of not handling dynamic sprite create/delete. We should tackle that later. The other PR wouldn't really fix this either. --- src/compiler/irgen.js | 8 +++++--- .../tw-sensing-of-non-existent-costume-name.sb3 | Bin 0 -> 2756 bytes ...-of-non-existent-costume-name.sb3.tw-snapshot | 13 +++++++++++++ .../__snapshots__/tw-sensing-of.sb3.tw-snapshot | 2 +- ...-of-non-existent-costume-name.sb3.tw-snapshot | 13 +++++++++++++ .../warp-timer/tw-sensing-of.sb3.tw-snapshot | 2 +- 6 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/execute/tw-sensing-of-non-existent-costume-name.sb3 create mode 100644 test/snapshot/__snapshots__/tw-sensing-of-non-existent-costume-name.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-sensing-of-non-existent-costume-name.sb3.tw-snapshot diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 52411ac9765..de47f0f1c2a 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -520,6 +520,7 @@ class ScriptTreeGenerator { } if (object.isConstant('_stage_')) { + // We assume that the stage always exists, so these don't need to be able to return 0. switch (property) { case 'background #': // fallthrough for scratch 1.0 compatibility case 'backdrop #': @@ -528,6 +529,7 @@ class ScriptTreeGenerator { return new IntermediateInput(InputOpcode.SENSING_OF_BACKDROP_NAME, InputType.STRING); } } else { + // If the target sprite does not exist, these may all return 0, even the costume name one. switch (property) { case 'x position': return new IntermediateInput(InputOpcode.SENSING_OF_POS_X, InputType.NUMBER, {object}); @@ -536,11 +538,11 @@ class ScriptTreeGenerator { case 'direction': return new IntermediateInput(InputOpcode.SENSING_OF_DIRECTION, InputType.NUMBER_REAL, {object}); case 'costume #': - return new IntermediateInput(InputOpcode.SENSING_OF_COSTUME_NUMBER, InputType.NUMBER_POS_INT, {object}); + return new IntermediateInput(InputOpcode.SENSING_OF_COSTUME_NUMBER, InputType.NUMBER_POS_INT | InputType.NUMBER_ZERO, {object}); case 'costume name': - return new IntermediateInput(InputOpcode.SENSING_OF_COSTUME_NAME, InputType.STRING, {object}); + return new IntermediateInput(InputOpcode.SENSING_OF_COSTUME_NAME, InputType.STRING | InputType.NUMBER_ZERO, {object}); case 'size': - return new IntermediateInput(InputOpcode.SENSING_OF_SIZE, InputType.NUMBER_POS, {object}); + return new IntermediateInput(InputOpcode.SENSING_OF_SIZE, InputType.NUMBER_POS | InputType.NUMBER_ZERO, {object}); } } diff --git a/test/fixtures/execute/tw-sensing-of-non-existent-costume-name.sb3 b/test/fixtures/execute/tw-sensing-of-non-existent-costume-name.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..604a2ff277d99ef8164c5adb6e2c001fba454885 GIT binary patch literal 2756 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 Y;Qv8_y)_W@mx}A~&K~w*-oIY|0eAhxqW}N^ literal 0 HcmV?d00001 diff --git a/test/snapshot/__snapshots__/tw-sensing-of-non-existent-costume-name.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-sensing-of-non-existent-costume-name.sb3.tw-snapshot new file mode 100644 index 00000000000..b8c983bd5b1 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-sensing-of-non-existent-costume-name.sb3.tw-snapshot @@ -0,0 +1,13 @@ +// TW Snapshot +// Input SHA-256: c3b1a45369f15f6809142ef2a2c6d1a680b802b70524a499b347af1008730a03 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getSpriteTargetByName("Sprite2"); +return function* genXYZ () { +runtime.ext_scratch3_looks._say("plan 0", target); +if ((("" + (b0 ? b0.getCostumes()[b0.currentCostume].name : 0)).toLowerCase() === "a".toLowerCase())) { +} +runtime.ext_scratch3_looks._say("end", target); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot index fa2c818d9ba..b574fe72392 100644 --- a/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-sensing-of.sb3.tw-snapshot @@ -35,7 +35,7 @@ runtime.ext_scratch3_looks._say("pass direction", target); if (((b1 ? b1.currentCostume + 1 : 0) === 3)) { runtime.ext_scratch3_looks._say("pass costume #", target); } -if (((b1 ? b1.getCostumes()[b1.currentCostume].name : 0).toLowerCase() === "Costume name test".toLowerCase())) { +if ((("" + (b1 ? b1.getCostumes()[b1.currentCostume].name : 0)).toLowerCase() === "Costume name test".toLowerCase())) { runtime.ext_scratch3_looks._say("pass costume name", target); } if (((b1 ? b1.size : 0) === 76.01)) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-sensing-of-non-existent-costume-name.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-sensing-of-non-existent-costume-name.sb3.tw-snapshot new file mode 100644 index 00000000000..b8c983bd5b1 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-sensing-of-non-existent-costume-name.sb3.tw-snapshot @@ -0,0 +1,13 @@ +// TW Snapshot +// Input SHA-256: c3b1a45369f15f6809142ef2a2c6d1a680b802b70524a499b347af1008730a03 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getSpriteTargetByName("Sprite2"); +return function* genXYZ () { +runtime.ext_scratch3_looks._say("plan 0", target); +if ((("" + (b0 ? b0.getCostumes()[b0.currentCostume].name : 0)).toLowerCase() === "a".toLowerCase())) { +} +runtime.ext_scratch3_looks._say("end", target); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot index fa2c818d9ba..b574fe72392 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-sensing-of.sb3.tw-snapshot @@ -35,7 +35,7 @@ runtime.ext_scratch3_looks._say("pass direction", target); if (((b1 ? b1.currentCostume + 1 : 0) === 3)) { runtime.ext_scratch3_looks._say("pass costume #", target); } -if (((b1 ? b1.getCostumes()[b1.currentCostume].name : 0).toLowerCase() === "Costume name test".toLowerCase())) { +if ((("" + (b1 ? b1.getCostumes()[b1.currentCostume].name : 0)).toLowerCase() === "Costume name test".toLowerCase())) { runtime.ext_scratch3_looks._say("pass costume name", target); } if (((b1 ? b1.size : 0) === 76.01)) { From c3a47de57558782e827111f33ed2c4c1fbfe0601 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 29 Dec 2025 19:01:19 -0600 Subject: [PATCH 082/106] Fix incorrect type for looks_size It can return 0 when fencing is disabled --- src/compiler/irgen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index de47f0f1c2a..decaec72faa 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -299,7 +299,7 @@ class ScriptTreeGenerator { } return new IntermediateInput(InputOpcode.LOOKS_COSTUME_NAME, InputType.STRING); case 'looks_size': - return new IntermediateInput(InputOpcode.LOOKS_SIZE_GET, InputType.NUMBER_POS); + return new IntermediateInput(InputOpcode.LOOKS_SIZE_GET, InputType.NUMBER_POS | InputType.NUMBER_ZERO); case 'motion_direction': return new IntermediateInput(InputOpcode.MOTION_DIRECTION_GET, InputType.NUMBER_REAL); From 0e5043d4dc28568925d8834885baa4bcf28eed8c Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 29 Dec 2025 19:50:15 -0600 Subject: [PATCH 083/106] Fix missing boolean cast in control_repeat_until Fixes https://github.com/TurboWarp/scratch-vm/issues/317 --- src/compiler/irgen.js | 2 +- .../tw-repeat-until-false-item-from-list.sb3 | Bin 0 -> 3291 bytes ...until-false-item-from-list.sb3.tw-snapshot | 25 ++++++++++++++++++ ...until-false-item-from-list.sb3.tw-snapshot | 25 ++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/execute/tw-repeat-until-false-item-from-list.sb3 create mode 100644 test/snapshot/__snapshots__/tw-repeat-until-false-item-from-list.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-repeat-until-false-item-from-list.sb3.tw-snapshot diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index decaec72faa..befab712049 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -662,7 +662,7 @@ class ScriptTreeGenerator { // Dirty hack: automatically enable warp timer for this block if it uses timer // This fixes project that do things like "repeat until timer > 0.5" this.usesTimer = false; - const condition = this.descendInputOfBlock(block, 'CONDITION'); + const condition = this.descendInputOfBlock(block, 'CONDITION').toType(InputType.BOOLEAN); const needsWarpTimer = this.usesTimer; return new IntermediateStackBlock(StackOpcode.CONTROL_WHILE, { condition: new IntermediateInput(InputOpcode.OP_NOT, InputType.BOOLEAN, { diff --git a/test/fixtures/execute/tw-repeat-until-false-item-from-list.sb3 b/test/fixtures/execute/tw-repeat-until-false-item-from-list.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..9430bc8a2e78b22d8188f17eedc6d87a84a93e6b GIT binary patch literal 3291 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 literal 0 HcmV?d00001 diff --git a/test/snapshot/__snapshots__/tw-repeat-until-false-item-from-list.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-repeat-until-false-item-from-list.sb3.tw-snapshot new file mode 100644 index 00000000000..aca5b04ea85 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-repeat-until-false-item-from-list.sb3.tw-snapshot @@ -0,0 +1,25 @@ +// TW Snapshot +// Input SHA-256: 28253e645679b429a494dbf17b831edc86513cd417cf2c24c9565cacc29a8817 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["aN^sIH)1L`YhdGV*_C5P"]; +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = []; +b0.value.push(("fal" + "se")); +b0._monitorUpToDate = false; +b0.value.push((1 === 1)); +b0._monitorUpToDate = false; +b1.value = 1; +while (!toBoolean(listGet(b0.value, b1.value))) { +b1.value = (toNotNaN(+b1.value) + 1); +yield; +} +if ((toNotNaN(+b1.value) === 2)) { +runtime.ext_scratch3_looks._say("pass", target); +} +runtime.ext_scratch3_looks._say("end", target); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-repeat-until-false-item-from-list.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-repeat-until-false-item-from-list.sb3.tw-snapshot new file mode 100644 index 00000000000..aca5b04ea85 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-repeat-until-false-item-from-list.sb3.tw-snapshot @@ -0,0 +1,25 @@ +// TW Snapshot +// Input SHA-256: 28253e645679b429a494dbf17b831edc86513cd417cf2c24c9565cacc29a8817 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["aN^sIH)1L`YhdGV*_C5P"]; +const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; +return function* genXYZ () { +runtime.ext_scratch3_looks._say("plan 1", target); +b0.value = []; +b0.value.push(("fal" + "se")); +b0._monitorUpToDate = false; +b0.value.push((1 === 1)); +b0._monitorUpToDate = false; +b1.value = 1; +while (!toBoolean(listGet(b0.value, b1.value))) { +b1.value = (toNotNaN(+b1.value) + 1); +yield; +} +if ((toNotNaN(+b1.value) === 2)) { +runtime.ext_scratch3_looks._say("pass", target); +} +runtime.ext_scratch3_looks._say("end", target); +retire(); return; +}; }) From 7fefa6f6663ab83bc761601cb0bf4c1c2ea5ee63 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 29 Dec 2025 20:06:36 -0600 Subject: [PATCH 084/106] Check for either input never being numbers first in OP_EQUALS Fixes https://github.com/TurboWarp/scratch-vm/issues/311 --- src/compiler/jsgen.js | 8 +- test/fixtures/execute/tw-true-equals-1.sb3 | Bin 0 -> 3306 bytes ...w-comparison-matrix-inline.sb3.tw-snapshot | 120 +++++++++--------- .../tw-true-equals-1.sb3.tw-snapshot | 38 ++++++ .../tw-unsafe-equals.sb3.tw-snapshot | 6 +- ...w-comparison-matrix-inline.sb3.tw-snapshot | 120 +++++++++--------- .../tw-true-equals-1.sb3.tw-snapshot | 38 ++++++ .../tw-unsafe-equals.sb3.tw-snapshot | 6 +- 8 files changed, 206 insertions(+), 130 deletions(-) create mode 100644 test/fixtures/execute/tw-true-equals-1.sb3 create mode 100644 test/snapshot/__snapshots__/tw-true-equals-1.sb3.tw-snapshot create mode 100644 test/snapshot/__snapshots__/warp-timer/tw-true-equals-1.sb3.tw-snapshot diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index abc492bf19e..ebbdc6bf4f5 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -297,6 +297,10 @@ class JSGenerator { const left = node.left; const right = node.right; + // When either operand is known to never be a number, only use string comparison to avoid all number parsing. + if (!left.isSometimesType(InputType.NUMBER_INTERPRETABLE) || !right.isSometimesType(InputType.NUMBER_INTERPRETABLE)) { + return `(${this.descendInput(left.toType(InputType.STRING))}.toLowerCase() === ${this.descendInput(right.toType(InputType.STRING))}.toLowerCase())`; + } // When both operands are known to be numbers, we can use === if (left.isAlwaysType(InputType.NUMBER_INTERPRETABLE) && right.isAlwaysType(InputType.NUMBER_INTERPRETABLE)) { return `(${this.descendInput(left.toType(InputType.NUMBER))} === ${this.descendInput(right.toType(InputType.NUMBER))})`; @@ -305,10 +309,6 @@ class JSGenerator { if (isSafeInputForEqualsOptimization(left, right) || isSafeInputForEqualsOptimization(right, left)) { return `(${this.descendInput(left.toType(InputType.NUMBER))} === ${this.descendInput(right.toType(InputType.NUMBER))})`; } - // When either operand is known to never be a number, only use string comparison to avoid all number parsing. - if (!left.isSometimesType(InputType.NUMBER_INTERPRETABLE) || !right.isSometimesType(InputType.NUMBER_INTERPRETABLE)) { - return `(${this.descendInput(left.toType(InputType.STRING))}.toLowerCase() === ${this.descendInput(right.toType(InputType.STRING))}.toLowerCase())`; - } // No compile-time optimizations possible - use fallback method. return `compareEqual(${this.descendInput(left)}, ${this.descendInput(right)})`; } diff --git a/test/fixtures/execute/tw-true-equals-1.sb3 b/test/fixtures/execute/tw-true-equals-1.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..e76954b9ad01518e65570b9fbb0b8816680fbcb2 GIT binary patch literal 3306 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 DNs8Ey literal 0 HcmV?d00001 diff --git a/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot index cb8e0dfefbd..077f68f4d5d 100644 --- a/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-comparison-matrix-inline.sb3.tw-snapshot @@ -323,7 +323,7 @@ runtime.ext_scratch3_looks._say("fail 105: 1.23 should be > -1", target); if (!(("" + ("1.23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 106: 1.23 should be < true", target); } -if (!(("" + (1.23 === 1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 107: 1.23 should be = true", target); } if (!(("" + ("1.23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -332,7 +332,7 @@ runtime.ext_scratch3_looks._say("fail 108: 1.23 should be > true", target); if (!(("" + ("1.23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 109: 1.23 should be < false", target); } -if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 110: 1.23 should be = false", target); } if (!(("" + ("1.23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -341,7 +341,7 @@ runtime.ext_scratch3_looks._say("fail 111: 1.23 should be > false", target); if (!(("" + ("1.23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 112: 1.23 should be < NaN", target); } -if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 113: 1.23 should be = NaN", target); } if (!(("" + ("1.23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -359,7 +359,7 @@ runtime.ext_scratch3_looks._say("fail 117: 1.23 should be > Infinity", target); if (!(("" + ("1.23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 118: 1.23 should be < banana", target); } -if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 119: 1.23 should be = banana", target); } if (!(("" + ("1.23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -368,7 +368,7 @@ runtime.ext_scratch3_looks._say("fail 120: 1.23 should be > banana", target); if (!(("" + ("1.23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 121: 1.23 should be < 🎉", target); } -if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 122: 1.23 should be = 🎉", target); } if (!(("" + ("1.23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -377,7 +377,7 @@ runtime.ext_scratch3_looks._say("fail 123: 1.23 should be > 🎉", target); if (!(("" + ("1.23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 124: 1.23 should be < ", target); } -if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 125: 1.23 should be = ", target); } if (!(("" + ("1.23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -449,7 +449,7 @@ runtime.ext_scratch3_looks._say("fail 147: .23 should be > -1", target); if (!(("" + (".23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 148: .23 should be < true", target); } -if (!(("" + (0.23 === 1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 149: .23 should be = true", target); } if (!(("" + (".23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -458,7 +458,7 @@ runtime.ext_scratch3_looks._say("fail 150: .23 should be > true", target); if (!(("" + (".23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 151: .23 should be < false", target); } -if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 152: .23 should be = false", target); } if (!(("" + (".23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -467,7 +467,7 @@ runtime.ext_scratch3_looks._say("fail 153: .23 should be > false", target); if (!(("" + (".23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 154: .23 should be < NaN", target); } -if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 155: .23 should be = NaN", target); } if (!(("" + (".23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -485,7 +485,7 @@ runtime.ext_scratch3_looks._say("fail 159: .23 should be > Infinity", target); if (!(("" + (".23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 160: .23 should be < banana", target); } -if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 161: .23 should be = banana", target); } if (!(("" + (".23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -494,7 +494,7 @@ runtime.ext_scratch3_looks._say("fail 162: .23 should be > banana", target); if (!(("" + (".23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 163: .23 should be < 🎉", target); } -if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 164: .23 should be = 🎉", target); } if (!(("" + (".23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -503,7 +503,7 @@ runtime.ext_scratch3_looks._say("fail 165: .23 should be > 🎉", target); if (!(("" + (".23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 166: .23 should be < ", target); } -if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 167: .23 should be = ", target); } if (!(("" + (".23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -575,7 +575,7 @@ runtime.ext_scratch3_looks._say("fail 189: 0.123 should be > -1", target); if (!(("" + ("0.123".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 190: 0.123 should be < true", target); } -if (!(("" + (0.123 === 1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 191: 0.123 should be = true", target); } if (!(("" + ("0.123".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -584,7 +584,7 @@ runtime.ext_scratch3_looks._say("fail 192: 0.123 should be > true", target); if (!(("" + ("0.123".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 193: 0.123 should be < false", target); } -if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 194: 0.123 should be = false", target); } if (!(("" + ("0.123".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -593,7 +593,7 @@ runtime.ext_scratch3_looks._say("fail 195: 0.123 should be > false", target); if (!(("" + ("0.123".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 196: 0.123 should be < NaN", target); } -if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 197: 0.123 should be = NaN", target); } if (!(("" + ("0.123".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -611,7 +611,7 @@ runtime.ext_scratch3_looks._say("fail 201: 0.123 should be > Infinity", target); if (!(("" + ("0.123".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 202: 0.123 should be < banana", target); } -if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 203: 0.123 should be = banana", target); } if (!(("" + ("0.123".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -620,7 +620,7 @@ runtime.ext_scratch3_looks._say("fail 204: 0.123 should be > banana", target); if (!(("" + ("0.123".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 205: 0.123 should be < 🎉", target); } -if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 206: 0.123 should be = 🎉", target); } if (!(("" + ("0.123".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -629,7 +629,7 @@ runtime.ext_scratch3_looks._say("fail 207: 0.123 should be > 🎉", target); if (!(("" + ("0.123".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 208: 0.123 should be < ", target); } -if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 209: 0.123 should be = ", target); } if (!(("" + ("0.123".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -827,7 +827,7 @@ runtime.ext_scratch3_looks._say("fail 273: -1 should be > -1", target); if (!(("" + ("-1".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 274: -1 should be < true", target); } -if (!(("" + (-1 === 1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 275: -1 should be = true", target); } if (!(("" + ("-1".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -836,7 +836,7 @@ runtime.ext_scratch3_looks._say("fail 276: -1 should be > true", target); if (!(("" + ("-1".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 277: -1 should be < false", target); } -if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 278: -1 should be = false", target); } if (!(("" + ("-1".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -845,7 +845,7 @@ runtime.ext_scratch3_looks._say("fail 279: -1 should be > false", target); if (!(("" + ("-1".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 280: -1 should be < NaN", target); } -if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 281: -1 should be = NaN", target); } if (!(("" + ("-1".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -863,7 +863,7 @@ runtime.ext_scratch3_looks._say("fail 285: -1 should be > Infinity", target); if (!(("" + ("-1".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 286: -1 should be < banana", target); } -if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 287: -1 should be = banana", target); } if (!(("" + ("-1".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -872,7 +872,7 @@ runtime.ext_scratch3_looks._say("fail 288: -1 should be > banana", target); if (!(("" + ("-1".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 289: -1 should be < 🎉", target); } -if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 290: -1 should be = 🎉", target); } if (!(("" + ("-1".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -881,7 +881,7 @@ runtime.ext_scratch3_looks._say("fail 291: -1 should be > 🎉", target); if (!(("" + ("-1".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 292: -1 should be < ", target); } -if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 293: -1 should be = ", target); } if (!(("" + ("-1".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -908,7 +908,7 @@ runtime.ext_scratch3_looks._say("fail 300: true should be > 0.0", target); if (!(("" + ("true".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 301: true should be < 1.23", target); } -if (!(("" + (1 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("true".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 302: true should be = 1.23", target); } if (!(("" + ("true".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -917,7 +917,7 @@ runtime.ext_scratch3_looks._say("fail 303: true should be > 1.23", target); if (!(("" + ("true".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 304: true should be < .23", target); } -if (!(("" + (1 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("true".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 305: true should be = .23", target); } if (!(("" + ("true".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -926,7 +926,7 @@ runtime.ext_scratch3_looks._say("fail 306: true should be > .23", target); if (!(("" + ("true".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 307: true should be < 0.123", target); } -if (!(("" + (1 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("true".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 308: true should be = 0.123", target); } if (!(("" + ("true".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -944,7 +944,7 @@ runtime.ext_scratch3_looks._say("fail 312: true should be > -0", target); if (!(("" + ("true".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 313: true should be < -1", target); } -if (!(("" + (1 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("true".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 314: true should be = -1", target); } if (!(("" + ("true".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -980,7 +980,7 @@ runtime.ext_scratch3_looks._say("fail 324: true should be > NaN", target); if (!(("" + ("true".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 325: true should be < Infinity", target); } -if (!(("" + (1 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("true".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 326: true should be = Infinity", target); } if (!(("" + ("true".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1034,7 +1034,7 @@ runtime.ext_scratch3_looks._say("fail 342: false should be > 0.0", target); if (!(("" + ("false".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 343: false should be < 1.23", target); } -if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("false".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 344: false should be = 1.23", target); } if (!(("" + ("false".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1043,7 +1043,7 @@ runtime.ext_scratch3_looks._say("fail 345: false should be > 1.23", target); if (!(("" + ("false".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 346: false should be < .23", target); } -if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("false".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 347: false should be = .23", target); } if (!(("" + ("false".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1052,7 +1052,7 @@ runtime.ext_scratch3_looks._say("fail 348: false should be > .23", target); if (!(("" + ("false".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 349: false should be < 0.123", target); } -if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("false".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 350: false should be = 0.123", target); } if (!(("" + ("false".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1070,7 +1070,7 @@ runtime.ext_scratch3_looks._say("fail 354: false should be > -0", target); if (!(("" + ("false".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 355: false should be < -1", target); } -if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("false".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 356: false should be = -1", target); } if (!(("" + ("false".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1106,7 +1106,7 @@ runtime.ext_scratch3_looks._say("fail 366: false should be > NaN", target); if (!(("" + ("false".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 367: false should be < Infinity", target); } -if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("false".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 368: false should be = Infinity", target); } if (!(("" + ("false".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1160,7 +1160,7 @@ runtime.ext_scratch3_looks._say("fail 384: NaN should be > 0.0", target); if (!(("" + ("NaN".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 385: NaN should be < 1.23", target); } -if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("NaN".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 386: NaN should be = 1.23", target); } if (!(("" + ("NaN".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1169,7 +1169,7 @@ runtime.ext_scratch3_looks._say("fail 387: NaN should be > 1.23", target); if (!(("" + ("NaN".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 388: NaN should be < .23", target); } -if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("NaN".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 389: NaN should be = .23", target); } if (!(("" + ("NaN".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1178,7 +1178,7 @@ runtime.ext_scratch3_looks._say("fail 390: NaN should be > .23", target); if (!(("" + ("NaN".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 391: NaN should be < 0.123", target); } -if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("NaN".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 392: NaN should be = 0.123", target); } if (!(("" + ("NaN".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1196,7 +1196,7 @@ runtime.ext_scratch3_looks._say("fail 396: NaN should be > -0", target); if (!(("" + ("NaN".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 397: NaN should be < -1", target); } -if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("NaN".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 398: NaN should be = -1", target); } if (!(("" + ("NaN".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1232,7 +1232,7 @@ runtime.ext_scratch3_looks._say("fail 408: NaN should be > NaN", target); if (!(("" + ("NaN".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 409: NaN should be < Infinity", target); } -if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("NaN".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 410: NaN should be = Infinity", target); } if (!(("" + ("NaN".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1331,7 +1331,7 @@ runtime.ext_scratch3_looks._say("fail 441: Infinity should be > -1", target); if (!(("" + ("Infinity".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 442: Infinity should be < true", target); } -if (!(("" + (Infinity === 1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 443: Infinity should be = true", target); } if (!(("" + ("Infinity".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1340,7 +1340,7 @@ runtime.ext_scratch3_looks._say("fail 444: Infinity should be > true", target); if (!(("" + ("Infinity".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 445: Infinity should be < false", target); } -if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 446: Infinity should be = false", target); } if (!(("" + ("Infinity".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1349,7 +1349,7 @@ runtime.ext_scratch3_looks._say("fail 447: Infinity should be > false", target); if (!(("" + ("Infinity".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 448: Infinity should be < NaN", target); } -if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 449: Infinity should be = NaN", target); } if (!(("" + ("Infinity".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1367,7 +1367,7 @@ runtime.ext_scratch3_looks._say("fail 453: Infinity should be > Infinity", targe if (!(("" + ("Infinity".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 454: Infinity should be < banana", target); } -if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 455: Infinity should be = banana", target); } if (!(("" + ("Infinity".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1376,7 +1376,7 @@ runtime.ext_scratch3_looks._say("fail 456: Infinity should be > banana", target) if (!(("" + ("Infinity".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 457: Infinity should be < 🎉", target); } -if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 458: Infinity should be = 🎉", target); } if (!(("" + ("Infinity".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1385,7 +1385,7 @@ runtime.ext_scratch3_looks._say("fail 459: Infinity should be > 🎉", target); if (!(("" + ("Infinity".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 460: Infinity should be < ", target); } -if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 461: Infinity should be = ", target); } if (!(("" + ("Infinity".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1412,7 +1412,7 @@ runtime.ext_scratch3_looks._say("fail 468: banana should be > 0.0", target); if (!(("" + ("banana".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 469: banana should be < 1.23", target); } -if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("banana".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 470: banana should be = 1.23", target); } if (!(("" + ("banana".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1421,7 +1421,7 @@ runtime.ext_scratch3_looks._say("fail 471: banana should be > 1.23", target); if (!(("" + ("banana".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 472: banana should be < .23", target); } -if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("banana".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 473: banana should be = .23", target); } if (!(("" + ("banana".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1430,7 +1430,7 @@ runtime.ext_scratch3_looks._say("fail 474: banana should be > .23", target); if (!(("" + ("banana".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 475: banana should be < 0.123", target); } -if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("banana".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 476: banana should be = 0.123", target); } if (!(("" + ("banana".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1448,7 +1448,7 @@ runtime.ext_scratch3_looks._say("fail 480: banana should be > -0", target); if (!(("" + ("banana".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 481: banana should be < -1", target); } -if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("banana".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 482: banana should be = -1", target); } if (!(("" + ("banana".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1484,7 +1484,7 @@ runtime.ext_scratch3_looks._say("fail 492: banana should be > NaN", target); if (!(("" + ("banana".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 493: banana should be < Infinity", target); } -if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("banana".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 494: banana should be = Infinity", target); } if (!(("" + ("banana".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1538,7 +1538,7 @@ runtime.ext_scratch3_looks._say("fail 510: 🎉 should be > 0.0", target); if (!(("" + ("🎉".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 511: 🎉 should be < 1.23", target); } -if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("🎉".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 512: 🎉 should be = 1.23", target); } if (!(("" + ("🎉".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1547,7 +1547,7 @@ runtime.ext_scratch3_looks._say("fail 513: 🎉 should be > 1.23", target); if (!(("" + ("🎉".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 514: 🎉 should be < .23", target); } -if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("🎉".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 515: 🎉 should be = .23", target); } if (!(("" + ("🎉".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1556,7 +1556,7 @@ runtime.ext_scratch3_looks._say("fail 516: 🎉 should be > .23", target); if (!(("" + ("🎉".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 517: 🎉 should be < 0.123", target); } -if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("🎉".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 518: 🎉 should be = 0.123", target); } if (!(("" + ("🎉".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1574,7 +1574,7 @@ runtime.ext_scratch3_looks._say("fail 522: 🎉 should be > -0", target); if (!(("" + ("🎉".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 523: 🎉 should be < -1", target); } -if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("🎉".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 524: 🎉 should be = -1", target); } if (!(("" + ("🎉".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1610,7 +1610,7 @@ runtime.ext_scratch3_looks._say("fail 534: 🎉 should be > NaN", target); if (!(("" + ("🎉".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 535: 🎉 should be < Infinity", target); } -if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("🎉".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 536: 🎉 should be = Infinity", target); } if (!(("" + ("🎉".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1664,7 +1664,7 @@ runtime.ext_scratch3_looks._say("fail 552: should be > 0.0", target); if (!(("" + ("".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 553: should be < 1.23", target); } -if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 554: should be = 1.23", target); } if (!(("" + ("".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1673,7 +1673,7 @@ runtime.ext_scratch3_looks._say("fail 555: should be > 1.23", target); if (!(("" + ("".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 556: should be < .23", target); } -if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 557: should be = .23", target); } if (!(("" + ("".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1682,7 +1682,7 @@ runtime.ext_scratch3_looks._say("fail 558: should be > .23", target); if (!(("" + ("".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 559: should be < 0.123", target); } -if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 560: should be = 0.123", target); } if (!(("" + ("".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1700,7 +1700,7 @@ runtime.ext_scratch3_looks._say("fail 564: should be > -0", target); if (!(("" + ("".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 565: should be < -1", target); } -if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 566: should be = -1", target); } if (!(("" + ("".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1736,7 +1736,7 @@ runtime.ext_scratch3_looks._say("fail 576: should be > NaN", target); if (!(("" + ("".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 577: should be < Infinity", target); } -if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 578: should be = Infinity", target); } if (!(("" + ("".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { diff --git a/test/snapshot/__snapshots__/tw-true-equals-1.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-true-equals-1.sb3.tw-snapshot new file mode 100644 index 00000000000..e4a9a048854 --- /dev/null +++ b/test/snapshot/__snapshots__/tw-true-equals-1.sb3.tw-snapshot @@ -0,0 +1,38 @@ +// TW Snapshot +// Input SHA-256: 70cf221f35f1459c3b81ece31ed7b377098ff26eeafb66eba3788dd82c90bdd5 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["{vwNMZe-LO,q/k3(A,.`"]; +const b1 = stage.variables["DKX$)W98mALB-eeMoj(d"]; +return function* genXYZ () { +runtime.ext_scratch3_looks._say("plan 8", target); +if (!("true".toLowerCase() === "1".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); +} +if (!("1".toLowerCase() === "true".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); +} +if (((+(2 === 2)) === 1)) { +runtime.ext_scratch3_looks._say("pass", target); +} +if ((1 === (+(2 === 2)))) { +runtime.ext_scratch3_looks._say("pass", target); +} +b0.value = (2 === 2); +b1.value = ("tr" + "ue"); +if (!(toNotNaN(+b1.value) === 1)) { +runtime.ext_scratch3_looks._say("pass", target); +} +if (!(1 === toNotNaN(+b1.value))) { +runtime.ext_scratch3_looks._say("pass", target); +} +if (((+b0.value) === 1)) { +runtime.ext_scratch3_looks._say("pass", target); +} +if ((1 === (+b0.value))) { +runtime.ext_scratch3_looks._say("pass", target); +} +runtime.ext_scratch3_looks._say("end", target); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot index 060a0aa20bf..35c87417158 100644 --- a/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/tw-unsafe-equals.sb3.tw-snapshot @@ -57,13 +57,13 @@ runtime.ext_scratch3_looks._say("pass 14", target); } yield; } -if ((0 === 1)) { +if (("".toLowerCase() === "1".toLowerCase())) { runtime.ext_scratch3_looks._say("fail", target); } -if ((1 === 0)) { +if (("1".toLowerCase() === "".toLowerCase())) { runtime.ext_scratch3_looks._say("fail", target); } -if ((0 === 1)) { +if ((" ".toLowerCase() === "1".toLowerCase())) { runtime.ext_scratch3_looks._say("fail", target); } if ((" ".toLowerCase() === "0".toLowerCase())) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot index cb8e0dfefbd..077f68f4d5d 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-comparison-matrix-inline.sb3.tw-snapshot @@ -323,7 +323,7 @@ runtime.ext_scratch3_looks._say("fail 105: 1.23 should be > -1", target); if (!(("" + ("1.23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 106: 1.23 should be < true", target); } -if (!(("" + (1.23 === 1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 107: 1.23 should be = true", target); } if (!(("" + ("1.23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -332,7 +332,7 @@ runtime.ext_scratch3_looks._say("fail 108: 1.23 should be > true", target); if (!(("" + ("1.23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 109: 1.23 should be < false", target); } -if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 110: 1.23 should be = false", target); } if (!(("" + ("1.23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -341,7 +341,7 @@ runtime.ext_scratch3_looks._say("fail 111: 1.23 should be > false", target); if (!(("" + ("1.23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 112: 1.23 should be < NaN", target); } -if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 113: 1.23 should be = NaN", target); } if (!(("" + ("1.23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -359,7 +359,7 @@ runtime.ext_scratch3_looks._say("fail 117: 1.23 should be > Infinity", target); if (!(("" + ("1.23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 118: 1.23 should be < banana", target); } -if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 119: 1.23 should be = banana", target); } if (!(("" + ("1.23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -368,7 +368,7 @@ runtime.ext_scratch3_looks._say("fail 120: 1.23 should be > banana", target); if (!(("" + ("1.23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 121: 1.23 should be < 🎉", target); } -if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 122: 1.23 should be = 🎉", target); } if (!(("" + ("1.23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -377,7 +377,7 @@ runtime.ext_scratch3_looks._say("fail 123: 1.23 should be > 🎉", target); if (!(("" + ("1.23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 124: 1.23 should be < ", target); } -if (!(("" + (1.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("1.23".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 125: 1.23 should be = ", target); } if (!(("" + ("1.23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -449,7 +449,7 @@ runtime.ext_scratch3_looks._say("fail 147: .23 should be > -1", target); if (!(("" + (".23".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 148: .23 should be < true", target); } -if (!(("" + (0.23 === 1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 149: .23 should be = true", target); } if (!(("" + (".23".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -458,7 +458,7 @@ runtime.ext_scratch3_looks._say("fail 150: .23 should be > true", target); if (!(("" + (".23".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 151: .23 should be < false", target); } -if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 152: .23 should be = false", target); } if (!(("" + (".23".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -467,7 +467,7 @@ runtime.ext_scratch3_looks._say("fail 153: .23 should be > false", target); if (!(("" + (".23".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 154: .23 should be < NaN", target); } -if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 155: .23 should be = NaN", target); } if (!(("" + (".23".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -485,7 +485,7 @@ runtime.ext_scratch3_looks._say("fail 159: .23 should be > Infinity", target); if (!(("" + (".23".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 160: .23 should be < banana", target); } -if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 161: .23 should be = banana", target); } if (!(("" + (".23".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -494,7 +494,7 @@ runtime.ext_scratch3_looks._say("fail 162: .23 should be > banana", target); if (!(("" + (".23".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 163: .23 should be < 🎉", target); } -if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 164: .23 should be = 🎉", target); } if (!(("" + (".23".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -503,7 +503,7 @@ runtime.ext_scratch3_looks._say("fail 165: .23 should be > 🎉", target); if (!(("" + (".23".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 166: .23 should be < ", target); } -if (!(("" + (0.23 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + (".23".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 167: .23 should be = ", target); } if (!(("" + (".23".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -575,7 +575,7 @@ runtime.ext_scratch3_looks._say("fail 189: 0.123 should be > -1", target); if (!(("" + ("0.123".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 190: 0.123 should be < true", target); } -if (!(("" + (0.123 === 1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 191: 0.123 should be = true", target); } if (!(("" + ("0.123".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -584,7 +584,7 @@ runtime.ext_scratch3_looks._say("fail 192: 0.123 should be > true", target); if (!(("" + ("0.123".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 193: 0.123 should be < false", target); } -if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 194: 0.123 should be = false", target); } if (!(("" + ("0.123".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -593,7 +593,7 @@ runtime.ext_scratch3_looks._say("fail 195: 0.123 should be > false", target); if (!(("" + ("0.123".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 196: 0.123 should be < NaN", target); } -if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 197: 0.123 should be = NaN", target); } if (!(("" + ("0.123".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -611,7 +611,7 @@ runtime.ext_scratch3_looks._say("fail 201: 0.123 should be > Infinity", target); if (!(("" + ("0.123".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 202: 0.123 should be < banana", target); } -if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 203: 0.123 should be = banana", target); } if (!(("" + ("0.123".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -620,7 +620,7 @@ runtime.ext_scratch3_looks._say("fail 204: 0.123 should be > banana", target); if (!(("" + ("0.123".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 205: 0.123 should be < 🎉", target); } -if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 206: 0.123 should be = 🎉", target); } if (!(("" + ("0.123".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -629,7 +629,7 @@ runtime.ext_scratch3_looks._say("fail 207: 0.123 should be > 🎉", target); if (!(("" + ("0.123".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 208: 0.123 should be < ", target); } -if (!(("" + (0.123 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("0.123".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 209: 0.123 should be = ", target); } if (!(("" + ("0.123".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -827,7 +827,7 @@ runtime.ext_scratch3_looks._say("fail 273: -1 should be > -1", target); if (!(("" + ("-1".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 274: -1 should be < true", target); } -if (!(("" + (-1 === 1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 275: -1 should be = true", target); } if (!(("" + ("-1".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -836,7 +836,7 @@ runtime.ext_scratch3_looks._say("fail 276: -1 should be > true", target); if (!(("" + ("-1".toLowerCase() < "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 277: -1 should be < false", target); } -if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 278: -1 should be = false", target); } if (!(("" + ("-1".toLowerCase() > "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -845,7 +845,7 @@ runtime.ext_scratch3_looks._say("fail 279: -1 should be > false", target); if (!(("" + ("-1".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 280: -1 should be < NaN", target); } -if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 281: -1 should be = NaN", target); } if (!(("" + ("-1".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -863,7 +863,7 @@ runtime.ext_scratch3_looks._say("fail 285: -1 should be > Infinity", target); if (!(("" + ("-1".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 286: -1 should be < banana", target); } -if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 287: -1 should be = banana", target); } if (!(("" + ("-1".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -872,7 +872,7 @@ runtime.ext_scratch3_looks._say("fail 288: -1 should be > banana", target); if (!(("" + ("-1".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 289: -1 should be < 🎉", target); } -if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 290: -1 should be = 🎉", target); } if (!(("" + ("-1".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -881,7 +881,7 @@ runtime.ext_scratch3_looks._say("fail 291: -1 should be > 🎉", target); if (!(("" + ("-1".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 292: -1 should be < ", target); } -if (!(("" + (-1 === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("-1".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 293: -1 should be = ", target); } if (!(("" + ("-1".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -908,7 +908,7 @@ runtime.ext_scratch3_looks._say("fail 300: true should be > 0.0", target); if (!(("" + ("true".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 301: true should be < 1.23", target); } -if (!(("" + (1 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("true".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 302: true should be = 1.23", target); } if (!(("" + ("true".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -917,7 +917,7 @@ runtime.ext_scratch3_looks._say("fail 303: true should be > 1.23", target); if (!(("" + ("true".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 304: true should be < .23", target); } -if (!(("" + (1 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("true".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 305: true should be = .23", target); } if (!(("" + ("true".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -926,7 +926,7 @@ runtime.ext_scratch3_looks._say("fail 306: true should be > .23", target); if (!(("" + ("true".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 307: true should be < 0.123", target); } -if (!(("" + (1 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("true".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 308: true should be = 0.123", target); } if (!(("" + ("true".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -944,7 +944,7 @@ runtime.ext_scratch3_looks._say("fail 312: true should be > -0", target); if (!(("" + ("true".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 313: true should be < -1", target); } -if (!(("" + (1 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("true".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 314: true should be = -1", target); } if (!(("" + ("true".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -980,7 +980,7 @@ runtime.ext_scratch3_looks._say("fail 324: true should be > NaN", target); if (!(("" + ("true".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 325: true should be < Infinity", target); } -if (!(("" + (1 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("true".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 326: true should be = Infinity", target); } if (!(("" + ("true".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1034,7 +1034,7 @@ runtime.ext_scratch3_looks._say("fail 342: false should be > 0.0", target); if (!(("" + ("false".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 343: false should be < 1.23", target); } -if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("false".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 344: false should be = 1.23", target); } if (!(("" + ("false".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1043,7 +1043,7 @@ runtime.ext_scratch3_looks._say("fail 345: false should be > 1.23", target); if (!(("" + ("false".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 346: false should be < .23", target); } -if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("false".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 347: false should be = .23", target); } if (!(("" + ("false".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1052,7 +1052,7 @@ runtime.ext_scratch3_looks._say("fail 348: false should be > .23", target); if (!(("" + ("false".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 349: false should be < 0.123", target); } -if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("false".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 350: false should be = 0.123", target); } if (!(("" + ("false".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1070,7 +1070,7 @@ runtime.ext_scratch3_looks._say("fail 354: false should be > -0", target); if (!(("" + ("false".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 355: false should be < -1", target); } -if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("false".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 356: false should be = -1", target); } if (!(("" + ("false".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1106,7 +1106,7 @@ runtime.ext_scratch3_looks._say("fail 366: false should be > NaN", target); if (!(("" + ("false".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 367: false should be < Infinity", target); } -if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("false".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 368: false should be = Infinity", target); } if (!(("" + ("false".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1160,7 +1160,7 @@ runtime.ext_scratch3_looks._say("fail 384: NaN should be > 0.0", target); if (!(("" + ("NaN".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 385: NaN should be < 1.23", target); } -if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("NaN".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 386: NaN should be = 1.23", target); } if (!(("" + ("NaN".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1169,7 +1169,7 @@ runtime.ext_scratch3_looks._say("fail 387: NaN should be > 1.23", target); if (!(("" + ("NaN".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 388: NaN should be < .23", target); } -if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("NaN".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 389: NaN should be = .23", target); } if (!(("" + ("NaN".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1178,7 +1178,7 @@ runtime.ext_scratch3_looks._say("fail 390: NaN should be > .23", target); if (!(("" + ("NaN".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 391: NaN should be < 0.123", target); } -if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("NaN".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 392: NaN should be = 0.123", target); } if (!(("" + ("NaN".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1196,7 +1196,7 @@ runtime.ext_scratch3_looks._say("fail 396: NaN should be > -0", target); if (!(("" + ("NaN".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 397: NaN should be < -1", target); } -if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("NaN".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 398: NaN should be = -1", target); } if (!(("" + ("NaN".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1232,7 +1232,7 @@ runtime.ext_scratch3_looks._say("fail 408: NaN should be > NaN", target); if (!(("" + ("NaN".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 409: NaN should be < Infinity", target); } -if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("NaN".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 410: NaN should be = Infinity", target); } if (!(("" + ("NaN".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1331,7 +1331,7 @@ runtime.ext_scratch3_looks._say("fail 441: Infinity should be > -1", target); if (!(("" + ("Infinity".toLowerCase() < "true".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 442: Infinity should be < true", target); } -if (!(("" + (Infinity === 1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 443: Infinity should be = true", target); } if (!(("" + ("Infinity".toLowerCase() > "true".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1340,7 +1340,7 @@ runtime.ext_scratch3_looks._say("fail 444: Infinity should be > true", target); if (!(("" + ("Infinity".toLowerCase() < "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 445: Infinity should be < false", target); } -if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "false".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 446: Infinity should be = false", target); } if (!(("" + ("Infinity".toLowerCase() > "false".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1349,7 +1349,7 @@ runtime.ext_scratch3_looks._say("fail 447: Infinity should be > false", target); if (!(("" + ("Infinity".toLowerCase() < "NaN".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 448: Infinity should be < NaN", target); } -if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 449: Infinity should be = NaN", target); } if (!(("" + ("Infinity".toLowerCase() > "NaN".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1367,7 +1367,7 @@ runtime.ext_scratch3_looks._say("fail 453: Infinity should be > Infinity", targe if (!(("" + ("Infinity".toLowerCase() < "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 454: Infinity should be < banana", target); } -if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "banana".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 455: Infinity should be = banana", target); } if (!(("" + ("Infinity".toLowerCase() > "banana".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1376,7 +1376,7 @@ runtime.ext_scratch3_looks._say("fail 456: Infinity should be > banana", target) if (!(("" + ("Infinity".toLowerCase() < "🎉".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 457: Infinity should be < 🎉", target); } -if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 458: Infinity should be = 🎉", target); } if (!(("" + ("Infinity".toLowerCase() > "🎉".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1385,7 +1385,7 @@ runtime.ext_scratch3_looks._say("fail 459: Infinity should be > 🎉", target); if (!(("" + ("Infinity".toLowerCase() < "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 460: Infinity should be < ", target); } -if (!(("" + (Infinity === 0)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("Infinity".toLowerCase() === "".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 461: Infinity should be = ", target); } if (!(("" + ("Infinity".toLowerCase() > "".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1412,7 +1412,7 @@ runtime.ext_scratch3_looks._say("fail 468: banana should be > 0.0", target); if (!(("" + ("banana".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 469: banana should be < 1.23", target); } -if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("banana".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 470: banana should be = 1.23", target); } if (!(("" + ("banana".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1421,7 +1421,7 @@ runtime.ext_scratch3_looks._say("fail 471: banana should be > 1.23", target); if (!(("" + ("banana".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 472: banana should be < .23", target); } -if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("banana".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 473: banana should be = .23", target); } if (!(("" + ("banana".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1430,7 +1430,7 @@ runtime.ext_scratch3_looks._say("fail 474: banana should be > .23", target); if (!(("" + ("banana".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 475: banana should be < 0.123", target); } -if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("banana".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 476: banana should be = 0.123", target); } if (!(("" + ("banana".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1448,7 +1448,7 @@ runtime.ext_scratch3_looks._say("fail 480: banana should be > -0", target); if (!(("" + ("banana".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 481: banana should be < -1", target); } -if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("banana".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 482: banana should be = -1", target); } if (!(("" + ("banana".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1484,7 +1484,7 @@ runtime.ext_scratch3_looks._say("fail 492: banana should be > NaN", target); if (!(("" + ("banana".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 493: banana should be < Infinity", target); } -if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("banana".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 494: banana should be = Infinity", target); } if (!(("" + ("banana".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1538,7 +1538,7 @@ runtime.ext_scratch3_looks._say("fail 510: 🎉 should be > 0.0", target); if (!(("" + ("🎉".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 511: 🎉 should be < 1.23", target); } -if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("🎉".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 512: 🎉 should be = 1.23", target); } if (!(("" + ("🎉".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1547,7 +1547,7 @@ runtime.ext_scratch3_looks._say("fail 513: 🎉 should be > 1.23", target); if (!(("" + ("🎉".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 514: 🎉 should be < .23", target); } -if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("🎉".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 515: 🎉 should be = .23", target); } if (!(("" + ("🎉".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1556,7 +1556,7 @@ runtime.ext_scratch3_looks._say("fail 516: 🎉 should be > .23", target); if (!(("" + ("🎉".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 517: 🎉 should be < 0.123", target); } -if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("🎉".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 518: 🎉 should be = 0.123", target); } if (!(("" + ("🎉".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1574,7 +1574,7 @@ runtime.ext_scratch3_looks._say("fail 522: 🎉 should be > -0", target); if (!(("" + ("🎉".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 523: 🎉 should be < -1", target); } -if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("🎉".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 524: 🎉 should be = -1", target); } if (!(("" + ("🎉".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1610,7 +1610,7 @@ runtime.ext_scratch3_looks._say("fail 534: 🎉 should be > NaN", target); if (!(("" + ("🎉".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 535: 🎉 should be < Infinity", target); } -if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("🎉".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 536: 🎉 should be = Infinity", target); } if (!(("" + ("🎉".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { @@ -1664,7 +1664,7 @@ runtime.ext_scratch3_looks._say("fail 552: should be > 0.0", target); if (!(("" + ("".toLowerCase() < "1.23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 553: should be < 1.23", target); } -if (!(("" + (0 === 1.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 554: should be = 1.23", target); } if (!(("" + ("".toLowerCase() > "1.23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1673,7 +1673,7 @@ runtime.ext_scratch3_looks._say("fail 555: should be > 1.23", target); if (!(("" + ("".toLowerCase() < ".23".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 556: should be < .23", target); } -if (!(("" + (0 === 0.23)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 557: should be = .23", target); } if (!(("" + ("".toLowerCase() > ".23".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1682,7 +1682,7 @@ runtime.ext_scratch3_looks._say("fail 558: should be > .23", target); if (!(("" + ("".toLowerCase() < "0.123".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 559: should be < 0.123", target); } -if (!(("" + (0 === 0.123)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 560: should be = 0.123", target); } if (!(("" + ("".toLowerCase() > "0.123".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1700,7 +1700,7 @@ runtime.ext_scratch3_looks._say("fail 564: should be > -0", target); if (!(("" + ("".toLowerCase() < "-1".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 565: should be < -1", target); } -if (!(("" + (0 === -1)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 566: should be = -1", target); } if (!(("" + ("".toLowerCase() > "-1".toLowerCase())).toLowerCase() === "false".toLowerCase())) { @@ -1736,7 +1736,7 @@ runtime.ext_scratch3_looks._say("fail 576: should be > NaN", target); if (!(("" + ("".toLowerCase() < "Infinity".toLowerCase())).toLowerCase() === "true".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 577: should be < Infinity", target); } -if (!(("" + (0 === Infinity)).toLowerCase() === "false".toLowerCase())) { +if (!(("" + ("".toLowerCase() === "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { runtime.ext_scratch3_looks._say("fail 578: should be = Infinity", target); } if (!(("" + ("".toLowerCase() > "Infinity".toLowerCase())).toLowerCase() === "false".toLowerCase())) { diff --git a/test/snapshot/__snapshots__/warp-timer/tw-true-equals-1.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-true-equals-1.sb3.tw-snapshot new file mode 100644 index 00000000000..e4a9a048854 --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-true-equals-1.sb3.tw-snapshot @@ -0,0 +1,38 @@ +// TW Snapshot +// Input SHA-256: 70cf221f35f1459c3b81ece31ed7b377098ff26eeafb66eba3788dd82c90bdd5 + +// Sprite1 script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = stage.variables["{vwNMZe-LO,q/k3(A,.`"]; +const b1 = stage.variables["DKX$)W98mALB-eeMoj(d"]; +return function* genXYZ () { +runtime.ext_scratch3_looks._say("plan 8", target); +if (!("true".toLowerCase() === "1".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); +} +if (!("1".toLowerCase() === "true".toLowerCase())) { +runtime.ext_scratch3_looks._say("pass", target); +} +if (((+(2 === 2)) === 1)) { +runtime.ext_scratch3_looks._say("pass", target); +} +if ((1 === (+(2 === 2)))) { +runtime.ext_scratch3_looks._say("pass", target); +} +b0.value = (2 === 2); +b1.value = ("tr" + "ue"); +if (!(toNotNaN(+b1.value) === 1)) { +runtime.ext_scratch3_looks._say("pass", target); +} +if (!(1 === toNotNaN(+b1.value))) { +runtime.ext_scratch3_looks._say("pass", target); +} +if (((+b0.value) === 1)) { +runtime.ext_scratch3_looks._say("pass", target); +} +if ((1 === (+b0.value))) { +runtime.ext_scratch3_looks._say("pass", target); +} +runtime.ext_scratch3_looks._say("end", target); +retire(); return; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot index 060a0aa20bf..35c87417158 100644 --- a/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot +++ b/test/snapshot/__snapshots__/warp-timer/tw-unsafe-equals.sb3.tw-snapshot @@ -57,13 +57,13 @@ runtime.ext_scratch3_looks._say("pass 14", target); } yield; } -if ((0 === 1)) { +if (("".toLowerCase() === "1".toLowerCase())) { runtime.ext_scratch3_looks._say("fail", target); } -if ((1 === 0)) { +if (("1".toLowerCase() === "".toLowerCase())) { runtime.ext_scratch3_looks._say("fail", target); } -if ((0 === 1)) { +if ((" ".toLowerCase() === "1".toLowerCase())) { runtime.ext_scratch3_looks._say("fail", target); } if ((" ".toLowerCase() === "0".toLowerCase())) { From 553a2a434d4b5ecb077a00fec652e3d934ea7f76 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Fri, 9 Jan 2026 22:23:46 -0600 Subject: [PATCH 085/106] Use safe stringify from -gui for visual reports Fixes stringifying -0, objects, arrays --- src/engine/runtime.js | 6 +++++- src/util/tw-safe-stringify.js | 30 ++++++++++++++++++++++++++++++ test/unit/engine_runtime_tw.js | 19 +++++++++++++++++++ test/unit/tw_safe_stringify.js | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/util/tw-safe-stringify.js create mode 100644 test/unit/tw_safe_stringify.js diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 503a1fbc449..ab70486582d 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -23,6 +23,7 @@ const ScratchLinkWebSocket = require('../util/scratch-link-websocket'); const FontManager = require('./tw-font-manager'); const fetchWithTimeout = require('../util/fetch-with-timeout'); const platform = require('./tw-platform.js'); +const safeStringify = require('../util/tw-safe-stringify.js'); // Virtual I/O devices. const Clock = require('../io/clock'); @@ -3084,7 +3085,10 @@ class Runtime extends EventEmitter { */ visualReport (target, blockId, value) { if (target === this.getEditingTarget()) { - this.emit(Runtime.VISUAL_REPORT, {id: blockId, value: String(value)}); + this.emit(Runtime.VISUAL_REPORT, { + id: blockId, + value: safeStringify(value) + }); } } diff --git a/src/util/tw-safe-stringify.js b/src/util/tw-safe-stringify.js new file mode 100644 index 00000000000..6491986ab7f --- /dev/null +++ b/src/util/tw-safe-stringify.js @@ -0,0 +1,30 @@ +const circularReplacer = () => { + const seen = new WeakSet(); + return (_, value) => { + if (typeof value === 'object' && value !== null) { + if (seen.has(value)) { + return Array.isArray(value) ? '[...]' : '{...}'; + } + seen.add(value); + } + return value; + }; +}; + +/** + * Safely stringify, properly handling circular relations and -0. + * @param {unknown} input Any value + * @returns {string} A stringified version of the input. + */ +const safeStringify = input => { + if (typeof input === 'object' && input !== null) { + return JSON.stringify(input, circularReplacer()); + } + // -0 stringifies as "0" by default. + if (Object.is(input, -0)) { + return '-0'; + } + return `${input}`; +}; + +module.exports = safeStringify; diff --git a/test/unit/engine_runtime_tw.js b/test/unit/engine_runtime_tw.js index 179b4f365f2..273f815b7e8 100644 --- a/test/unit/engine_runtime_tw.js +++ b/test/unit/engine_runtime_tw.js @@ -2,6 +2,7 @@ const tap = require('tap'); const Runtime = require('../../src/engine/runtime'); const {Map} = require('immutable'); const makeTestStorage = require('../fixtures/make-test-storage'); +const Target = require('../../src/engine/target'); const test = tap.test; @@ -253,3 +254,21 @@ test('convertToPackagedRuntime and attachStorage call order', t => { rt2.attachStorage(makeTestStorage()); t.end(); }); + +test('visual report -0', t => { + t.plan(1); + + const rt = new Runtime(); + const target = new Target(); + rt.setEditingTarget(target); + + rt.on(Runtime.VISUAL_REPORT, report => { + t.same(report, { + id: 'blockid', + value: '-0' + }); + }); + rt.visualReport(target, 'blockid', -0); + + t.end(); +}); diff --git a/test/unit/tw_safe_stringify.js b/test/unit/tw_safe_stringify.js new file mode 100644 index 00000000000..8307d6ea64a --- /dev/null +++ b/test/unit/tw_safe_stringify.js @@ -0,0 +1,32 @@ +const {test} = require('tap'); +const safeStringify = require('../../src/util/tw-safe-stringify'); + +test('safeStringify', t => { + t.equal(safeStringify(''), ''); + t.equal(safeStringify('a'), 'a'); + + t.equal(safeStringify(true), 'true'); + t.equal(safeStringify(false), 'false'); + + t.equal(safeStringify(0), '0'); + t.equal(safeStringify(-0), '-0'); + t.equal(safeStringify(1), '1'); + t.equal(safeStringify(Infinity), 'Infinity'); + t.equal(safeStringify(-Infinity), '-Infinity'); + t.equal(safeStringify(NaN), 'NaN'); + + t.equal(safeStringify(null), 'null'); + t.equal(safeStringify(undefined), 'undefined'); + + t.equal(safeStringify({}), '{}'); + t.equal(safeStringify({a: 'b'}), '{"a":"b"}'); + + t.equal(safeStringify([]), '[]'); + t.equal(safeStringify([1, 2, 3]), '[1,2,3]'); + + const circular = {}; + circular.circular = circular; + t.equal(safeStringify(circular), '{"circular":"{...}"}'); + + t.end(); +}); From 6abc33d7874c0e908dc0d88ab46c7a0412ea1d7f Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Fri, 9 Jan 2026 22:30:18 -0600 Subject: [PATCH 086/106] Remove immutable.js (#329) Why: * We use immutable.js 3.8.2 which is ancient and not getting updates * immutable.js adds 55KB to the bundle, of which we use almost nothing * immutable.js's treatment of 0 and -0 is nonsensical and would require weird workarounds like https://github.com/TurboWarp/scratch-vm/pull/320 * We don't benefit from the whole immutability thing What we're doing instead: * We have our own MonitorState and MonitorRecord classes * We track dirty-ness at modification time instead of equality checking every tick * scratch-gui and packager can continue to think we use immutable.js without causing issues in either direction * our objects have enough stubs that immutable.js-expecting consumers are ok * when receiving an object, we check if it looks like an immutable.js one and ask for the plain JS version so that works okay too --- package-lock.json | 9 - package.json | 1 - src/blocks/scratch3_data.js | 2 +- src/engine/blocks.js | 7 +- src/engine/execute.js | 5 +- src/engine/monitor-record.js | 217 ++++++++++++++++-- src/engine/runtime.js | 79 +++---- src/engine/target.js | 5 +- src/engine/tw-monitor-state.js | 118 ++++++++++ src/serialization/sb2.js | 2 +- src/serialization/sb3.js | 7 +- ...erialize_extension_only_used_by_monitor.js | 8 +- .../tw_serialize_hidden_monitors.js | 4 +- test/unit/engine_runtime.js | 22 +- test/unit/engine_runtime_tw.js | 12 +- test/unit/tw_monitor_record.js | 56 +++++ test/unit/tw_monitor_state.js | 115 ++++++++++ webpack.config.js | 1 - 18 files changed, 553 insertions(+), 117 deletions(-) create mode 100644 src/engine/tw-monitor-state.js create mode 100644 test/unit/tw_monitor_record.js create mode 100644 test/unit/tw_monitor_state.js diff --git a/package-lock.json b/package-lock.json index c64871a087e..d6759c7ad58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,6 @@ "diff-match-patch": "1.0.4", "format-message": "6.2.1", "htmlparser2": "3.10.0", - "immutable": "3.8.2", "scratch-parser": "github:TurboWarp/scratch-parser#master", "scratch-sb1-converter": "0.2.7", "scratch-translate-extension-languages": "^1.0.7", @@ -8999,14 +8998,6 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, - "node_modules/immutable": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", - "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", diff --git a/package.json b/package.json index c126de34260..a22e531a254 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "diff-match-patch": "1.0.4", "format-message": "6.2.1", "htmlparser2": "3.10.0", - "immutable": "3.8.2", "scratch-parser": "github:TurboWarp/scratch-parser#master", "scratch-sb1-converter": "0.2.7", "scratch-translate-extension-languages": "^1.0.7", diff --git a/src/blocks/scratch3_data.js b/src/blocks/scratch3_data.js index 1a2e5b86eea..1290434b430 100644 --- a/src/blocks/scratch3_data.js +++ b/src/blocks/scratch3_data.js @@ -99,7 +99,7 @@ class Scratch3DataBlocks { // Return original list value if up-to-date, which doesn't trigger monitor update. if (list._monitorUpToDate) return list.value; // If value changed, reset the flag and return a copy to trigger monitor update. - // Because monitors use Immutable data structures, only new objects trigger updates. + // MonitorState only detects updates when the object changes. list._monitorUpToDate = true; return list.value.slice(); } diff --git a/src/engine/blocks.js b/src/engine/blocks.js index 71ace3a205f..68b3e606e7a 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -3,7 +3,6 @@ const mutationAdapter = require('./mutation-adapter'); const xmlEscape = require('../util/xml-escape'); const MonitorRecord = require('./monitor-record'); const Clone = require('../util/clone'); -const {Map} = require('immutable'); const BlocksExecuteCache = require('./blocks-execute-cache'); const BlocksRuntimeCache = require('./blocks-runtime-cache'); const log = require('../util/log'); @@ -711,10 +710,10 @@ class Blocks { const flyoutBlock = block.shadow && block.parent ? this._blocks[block.parent] : block; if (flyoutBlock.isMonitored) { - this.runtime.requestUpdateMonitor(Map({ + this.runtime.requestUpdateMonitor({ id: flyoutBlock.id, params: this._getBlockParams(flyoutBlock) - })); + }); } } break; @@ -773,7 +772,7 @@ class Blocks { } else if (!wasMonitored && block.isMonitored) { // Tries to show the monitor for specified block. If it doesn't exist, add the monitor. if (!this.runtime.requestShowMonitor(block.id)) { - this.runtime.requestAddMonitor(MonitorRecord({ + this.runtime.requestAddMonitor(new MonitorRecord({ id: block.id, targetId: block.targetId, spriteName: block.targetId ? this.runtime.getTargetById(block.targetId).getName() : null, diff --git a/src/engine/execute.js b/src/engine/execute.js index c411f244c93..c9f2f115e06 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -2,7 +2,6 @@ const BlockUtility = require('./block-utility'); const BlocksExecuteCache = require('./blocks-execute-cache'); const log = require('../util/log'); const Thread = require('./thread'); -const {Map} = require('immutable'); const cast = require('../util/cast'); /** @@ -100,11 +99,11 @@ const handleReport = function (resolvedValue, sequencer, thread, blockCached, la // Target no longer exists return; } - sequencer.runtime.requestUpdateMonitor(Map({ + sequencer.runtime.requestUpdateMonitor({ id: currentBlockId, spriteName: targetId ? sequencer.runtime.getTargetById(targetId).getName() : null, value: resolvedValue - })); + }); } } // Finished any yields. diff --git a/src/engine/monitor-record.js b/src/engine/monitor-record.js index 1259d525290..694bcd8464e 100644 --- a/src/engine/monitor-record.js +++ b/src/engine/monitor-record.js @@ -1,23 +1,198 @@ -const {Record} = require('immutable'); - -const MonitorRecord = Record({ - id: null, // Block Id - /** Present only if the monitor is sprite-specific, such as x position */ - spriteName: null, - /** Present only if the monitor is sprite-specific, such as x position */ - targetId: null, - opcode: null, - value: null, - params: null, - mode: 'default', - sliderMin: 0, - sliderMax: 100, - isDiscrete: true, - x: null, // (x: null, y: null) Indicates that the monitor should be auto-positioned - y: null, - width: 0, - height: 0, - visible: true -}); +/** + * @param {unknown} obj + * @returns {boolean} + */ +const defined = obj => typeof obj !== 'undefined' && obj !== null; + +/** + * @typedef JSDelta Delta object using regular JS object. + * @property {string|null} [id] + * @property {string|null} [spriteName] + * @property {string|null} [targetId] + * @property {string|null} [opcode] + * @property {unknown} [value] + * @property {unknown} [params] + * @property {string|null} [mode] + * @property {number|null} [sliderMin] + * @property {number|null} [sliderMax] + * @property {boolean|null} [isDiscrete] + * @property {number|null} [x] + * @property {number|null} [y] + * @property {number|null} [width] + * @property {number|null} [height] + * @property {boolean|null} [visible] + */ + +/** + * @typedef ImmutableJSDelta Delta object that is an immutable.js Map/OrderedMap. + * @property {() => JSDelta} toJS + */ + +/** + * @typedef {JSDelta|ImmutableJSDelta} ExternalDelta Delta object that might be JS or immutable.js. + */ + +/** + * @implements {JSDelta} + */ +class MonitorRecord { + /** + * @param {JSDelta} delta + */ + constructor (delta) { + /** + * Block ID + */ + this.id = delta.id ?? null; + /** + * Present only if the monitor is sprite-specific, such as x position + */ + this.spriteName = delta.spriteName ?? null; + /** + * Present only if the monitor is sprite-specific, such as x position + */ + this.targetId = delta.targetId ?? null; + this.opcode = delta.opcode ?? null; + this.value = delta.value ?? null; + this.params = delta.params ?? null; + this.mode = delta.mode ?? 'default'; + this.sliderMin = delta.sliderMin ?? 0; + this.sliderMax = delta.sliderMax ?? 100; + this.isDiscrete = delta.isDiscrete ?? true; + /** + * (x: null, y: null) Indicates that the monitor should be auto-positioned + */ + this.x = delta.x ?? null; + /** + * (x: null, y: null) Indicates that the monitor should be auto-positioned + */ + this.y = delta.y ?? null; + this.width = delta.width ?? 0; + this.height = delta.height ?? 0; + this.visible = delta.visible ?? true; + } + + /** + * Exists for compatibility with code expecting an immutable.js Map + * @param {string} property + */ + get (property) { + switch (property) { + case 'id': return this.id; + case 'spriteName': return this.spriteName; + case 'targetId': return this.targetId; + case 'opcode': return this.opcode; + case 'value': return this.value; + case 'params': return this.params; + case 'mode': return this.mode; + case 'sliderMin': return this.sliderMin; + case 'sliderMax': return this.sliderMax; + case 'isDiscrete': return this.isDiscrete; + case 'x': return this.x; + case 'y': return this.y; + case 'width': return this.width; + case 'height': return this.height; + case 'visible': return this.visible; + } + return null; + } + + /** + * @param {JSDelta} delta + * @returns {boolean} true if modified + */ + merge (delta) { + let didChange = false; + + if (defined(delta.id) && !Object.is(this.id, delta.id)) { + this.id = delta.id; + didChange = true; + } + + if (defined(delta.spriteName) && !Object.is(this.spriteName, delta.spriteName)) { + this.spriteName = delta.spriteName; + didChange = true; + } + + if (defined(delta.targetId) && !Object.is(this.targetId, delta.targetId)) { + this.targetId = delta.targetId; + didChange = true; + } + + if (defined(delta.opcode) && !Object.is(this.opcode, delta.opcode)) { + this.opcode = delta.opcode; + didChange = true; + } + + if (defined(delta.value) && !Object.is(this.value, delta.value)) { + this.value = delta.value; + didChange = true; + } + + if (defined(delta.params) && !Object.is(this.params, delta.params)) { + this.params = delta.params; + didChange = true; + } + + if (defined(delta.mode) && !Object.is(this.mode, delta.mode)) { + this.mode = delta.mode; + didChange = true; + } + + if (defined(delta.sliderMin) && !Object.is(this.sliderMin, delta.sliderMin)) { + this.sliderMin = delta.sliderMin; + didChange = true; + } + + if (defined(delta.sliderMax) && !Object.is(this.sliderMax, delta.sliderMax)) { + this.sliderMax = delta.sliderMax; + didChange = true; + } + + if (defined(delta.isDiscrete) && !Object.is(this.isDiscrete, delta.isDiscrete)) { + this.isDiscrete = delta.isDiscrete; + didChange = true; + } + + if (defined(delta.x) && !Object.is(this.x, delta.x)) { + this.x = delta.x; + didChange = true; + } + + if (defined(delta.y) && !Object.is(this.y, delta.y)) { + this.y = delta.y; + didChange = true; + } + + if (defined(delta.width) && !Object.is(this.width, delta.width)) { + this.width = delta.width; + didChange = true; + } + + if (defined(delta.height) && !Object.is(this.height, delta.height)) { + this.height = delta.height; + didChange = true; + } + + if (defined(delta.visible) && !Object.is(this.visible, delta.visible)) { + this.visible = delta.visible; + didChange = true; + } + + return didChange; + } +} + +/** + * For compatibility, converts an immutable.js delta received from consumer to a plain JS delta for internal use. + * @param {ExternalDelta} obj + * @returns {JSDelta} + */ +MonitorRecord.externalDeltaToJS = obj => { + if (typeof obj.toJS === 'function') { + return obj.toJS(); + } + return obj; +}; module.exports = MonitorRecord; diff --git a/src/engine/runtime.js b/src/engine/runtime.js index ab70486582d..e1802a7bc31 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -1,5 +1,4 @@ const EventEmitter = require('events'); -const {OrderedMap} = require('immutable'); const ExtendedJSON = require('@turbowarp/json'); const uuid = require('uuid'); @@ -24,6 +23,7 @@ const FontManager = require('./tw-font-manager'); const fetchWithTimeout = require('../util/fetch-with-timeout'); const platform = require('./tw-platform.js'); const safeStringify = require('../util/tw-safe-stringify.js'); +const MonitorState = require('./tw-monitor-state.js'); // Virtual I/O devices. const Clock = require('../io/clock'); @@ -51,6 +51,7 @@ const defaultBlockPackages = { const interpolate = require('./tw-interpolate'); const FrameLoop = require('./tw-frame-loop'); +const MonitorRecord = require('./monitor-record.js'); const defaultExtensionColors = ['#0FBD8C', '#0DA57A', '#0B8E69']; @@ -320,14 +321,9 @@ class Runtime extends EventEmitter { this.monitorBlockInfo = {}; /** - * Ordered map of all monitors, which are MonitorReporter objects. + * Ordered map of all monitors, which are MonitorRecord objects. */ - this._monitorState = OrderedMap({}); - - /** - * Monitor state from last tick - */ - this._prevMonitorState = OrderedMap({}); + this._monitorState = new MonitorState(); /** * Whether the project is in "turbo mode." @@ -2285,10 +2281,9 @@ class Runtime extends EventEmitter { this.targets.map(this.disposeTarget, this); this.extensionStorage = {}; // tw: explicitly emit a MONITORS_UPDATE instead of relying on implicit behavior of _step() - const emptyMonitorState = OrderedMap({}); - if (!emptyMonitorState.equals(this._monitorState)) { - this._monitorState = emptyMonitorState; - this.emit(Runtime.MONITORS_UPDATE, this._monitorState); + if (!this._monitorState.empty()) { + this._monitorState = new MonitorState(); + this.emit(Runtime.MONITORS_UPDATE, this._monitorState.shallowClone()); } this.emit(Runtime.RUNTIME_DISPOSED); this.ioDevices.clock.resetProjectTimer(); @@ -2578,9 +2573,9 @@ class Runtime extends EventEmitter { this._refreshTargets = false; } - if (!this._prevMonitorState.equals(this._monitorState)) { - this.emit(Runtime.MONITORS_UPDATE, this._monitorState); - this._prevMonitorState = this._monitorState; + if (this._monitorState.dirty) { + this.emit(Runtime.MONITORS_UPDATE, this._monitorState.shallowClone()); + this._monitorState.dirty = false; } if (this.profiler !== null) { @@ -2707,12 +2702,13 @@ class Runtime extends EventEmitter { const offsetX = deltaX / 2; const offsetY = deltaY / 2; for (const monitor of this._monitorState.valueSeq()) { - const newMonitor = monitor - .set('x', monitor.get('x') + offsetX) - .set('y', monitor.get('y') + offsetY); - this.requestUpdateMonitor(newMonitor); + this.requestUpdateMonitor({ + id: monitor.id, + x: monitor.get('x') + offsetX, + y: monitor.get('y') + offsetY + }); } - this.emit(Runtime.MONITORS_UPDATE, this._monitorState); + this.emit(Runtime.MONITORS_UPDATE, this._monitorState.shallowClone()); } this.stageWidth = width; @@ -3095,34 +3091,27 @@ class Runtime extends EventEmitter { /** * Add a monitor to the state. If the monitor already exists in the state, * updates those properties that are defined in the given monitor record. - * @param {!MonitorRecord} monitor Monitor to add. + * @param {import('./monitor-record.js')} monitor Monitor to add. */ requestAddMonitor (monitor) { - const id = monitor.get('id'); if (!this.requestUpdateMonitor(monitor)) { // update monitor if it exists in the state // if the monitor did not exist in the state, add it - this._monitorState = this._monitorState.set(id, monitor); + this._monitorState.set(monitor.id, monitor); } } /** * Update a monitor in the state and report success/failure of update. - * @param {!Map} monitor Monitor values to update. Values on the monitor with overwrite - * values on the old monitor with the same ID. If a value isn't defined on the new monitor, + * @param {import('./monitor-record.js').ExternalDelta} delta Monitor values to update. Values on the monitor will + * overwrite values on the old monitor with the same ID. If a value isn't defined on the new monitor, * the old monitor will keep its old value. * @return {boolean} true if monitor exists in the state and was updated, false if it did not exist. */ - requestUpdateMonitor (monitor) { - const id = monitor.get('id'); + requestUpdateMonitor (delta) { + delta = MonitorRecord.externalDeltaToJS(delta); + const id = delta.id; if (this._monitorState.has(id)) { - this._monitorState = - // Use mergeWith here to prevent undefined values from overwriting existing ones - this._monitorState.set(id, this._monitorState.get(id).mergeWith((prev, next) => { - if (typeof next === 'undefined' || next === null) { - return prev; - } - return next; - }, monitor)); + this._monitorState.set(id, delta); return true; } return false; @@ -3134,7 +3123,7 @@ class Runtime extends EventEmitter { * @param {!string} monitorId ID of the monitor to remove. */ requestRemoveMonitor (monitorId) { - this._monitorState = this._monitorState.delete(monitorId); + this._monitorState.delete(monitorId); } /** @@ -3143,10 +3132,10 @@ class Runtime extends EventEmitter { * @return {boolean} true if monitor exists and was updated, false otherwise */ requestHideMonitor (monitorId) { - return this.requestUpdateMonitor(new Map([ - ['id', monitorId], - ['visible', false] - ])); + return this.requestUpdateMonitor({ + id: monitorId, + visible: false + }); } /** @@ -3156,10 +3145,10 @@ class Runtime extends EventEmitter { * @return {boolean} true if monitor exists and was updated, false otherwise */ requestShowMonitor (monitorId) { - return this.requestUpdateMonitor(new Map([ - ['id', monitorId], - ['visible', true] - ])); + return this.requestUpdateMonitor({ + id: monitorId, + visible: true + }); } /** @@ -3168,7 +3157,7 @@ class Runtime extends EventEmitter { * @param {!string} targetId Remove all monitors with given target ID. */ requestRemoveMonitorByTargetId (targetId) { - this._monitorState = this._monitorState.filterNot(value => value.targetId === targetId); + this._monitorState.filter(value => value.targetId !== targetId); } /** diff --git a/src/engine/target.js b/src/engine/target.js index e9cecfe0b0d..931ec3c1fc9 100644 --- a/src/engine/target.js +++ b/src/engine/target.js @@ -4,7 +4,6 @@ const Blocks = require('./blocks'); const Variable = require('../engine/variable'); const Comment = require('../engine/comment'); const uid = require('../util/uid'); -const {Map} = require('immutable'); const log = require('../util/log'); const StringUtil = require('../util/string-util'); const VariableUtil = require('../util/variable-util'); @@ -352,10 +351,10 @@ class Target extends EventEmitter { }, this.runtime); const monitorBlock = blocks.getBlock(variable.id); if (monitorBlock) { - this.runtime.requestUpdateMonitor(Map({ + this.runtime.requestUpdateMonitor({ id: id, params: blocks._getBlockParams(monitorBlock) - })); + }); } } diff --git a/src/engine/tw-monitor-state.js b/src/engine/tw-monitor-state.js new file mode 100644 index 00000000000..435db9c441f --- /dev/null +++ b/src/engine/tw-monitor-state.js @@ -0,0 +1,118 @@ +/** + * @typedef {import('./monitor-record')} MonitorRecord + */ + +const MonitorRecord = require('./monitor-record'); + +class MonitorState { + constructor () { + /** + * @type {Map} + */ + this.map = new Map(); + + /** + * True if modified. + * @type {boolean} + */ + this.dirty = false; + } + + /** + * @param {string} id + * @returns {MonitorRecord|null} + */ + get (id) { + return this.map.get(id); + } + + /** + * @param {string} id + * @returns {boolean} + */ + has (id) { + return this.map.has(id); + } + + /** + * Create or update. + * @param {string} id + * @param {MonitorRecord.JSDelta} delta + */ + set (id, delta) { + if (this.map.has(id)) { + const oldRecord = this.map.get(id); + if (oldRecord.merge(delta)) { + this.dirty = true; + } + } else { + this.map.set(id, delta instanceof MonitorRecord ? delta : new MonitorRecord(delta)); + this.dirty = true; + } + } + + /** + * @param {string} id + */ + delete (id) { + if (this.map.has(id)) { + this.map.delete(id); + this.dirty = true; + } + } + + /** + * Removes monitors that do not satisfy callback. + * @param {(record: MonitorRecord) => boolean} callback Returns true to keep. + */ + filter (callback) { + for (const id of Array.from(this.map.keys())) { + const record = this.map.get(id); + if (!callback(record)) { + this.map.delete(id); + this.dirty = true; + } + } + } + + /** + * @returns {boolean} true if no monitors + */ + empty () { + return this.map.size === 0; + } + + /** + * @returns {number} + */ + get size () { + return this.map.size; + } + + /** + * @returns {MonitorRecord[]} + */ + values () { + return Array.from(this.map.values()); + } + + /** + * For compatibility with immutable.js. + * @returns {MonitorRecord[]} + */ + valueSeq () { + return this.values(); + } + + /** + * You should not perform write operations on the clone. + * @returns {MonitorState} + */ + shallowClone () { + const result = new MonitorState(); + result.map = this.map; + return result; + } +} + +module.exports = MonitorState; diff --git a/src/serialization/sb2.js b/src/serialization/sb2.js index 1cde8e26e24..5af4d4ecb8d 100644 --- a/src/serialization/sb2.js +++ b/src/serialization/sb2.js @@ -414,7 +414,7 @@ const parseMonitorObject = (object, runtime, targets, extensions) => { } // Create a monitor record for the runtime's monitorState - runtime.requestAddMonitor(MonitorRecord({ + runtime.requestAddMonitor(new MonitorRecord({ id: block.id, targetId: block.targetId, spriteName: block.targetId ? object.target : null, diff --git a/src/serialization/sb3.js b/src/serialization/sb3.js index 815c2837a4d..33c822205d2 100644 --- a/src/serialization/sb3.js +++ b/src/serialization/sb3.js @@ -699,10 +699,7 @@ const serializeMonitors = function (monitors, runtime, extensions) { serializedMonitor.isDiscrete = monitorData.isDiscrete; } return serializedMonitor; - }) - // By default the sequence is lazily evaluated, but we want it to be evaluated right - // now to update the used extension list. - .toArray(); + }); }; /** @@ -1440,7 +1437,7 @@ const deserializeMonitor = function (monitorData, runtime, targets, extensions) } } - runtime.requestAddMonitor(MonitorRecord(monitorData)); + runtime.requestAddMonitor(new MonitorRecord(monitorData)); }; // Replace variable IDs throughout the project with diff --git a/test/integration/tw_serialize_extension_only_used_by_monitor.js b/test/integration/tw_serialize_extension_only_used_by_monitor.js index a10cf18b1ca..05d55420423 100644 --- a/test/integration/tw_serialize_extension_only_used_by_monitor.js +++ b/test/integration/tw_serialize_extension_only_used_by_monitor.js @@ -4,12 +4,12 @@ const MonitorRecord = require('../../src/engine/monitor-record'); test('Correctly serializes native extension only used by monitors', t => { const vm = new VM(); - vm.runtime.requestAddMonitor(MonitorRecord({ + vm.runtime.requestAddMonitor(new MonitorRecord({ id: 'fakeblock1', opcode: 'pen_fakeblock', visiblle: true })); - vm.runtime.requestAddMonitor(MonitorRecord({ + vm.runtime.requestAddMonitor(new MonitorRecord({ id: 'fakeblock2', opcode: 'translate_fakeblock', visiblle: false @@ -22,12 +22,12 @@ test('Correctly serializes native extension only used by monitors', t => { test('Correctly serializes custom extension only used by monitors', t => { const vm = new VM(); - vm.runtime.requestAddMonitor(MonitorRecord({ + vm.runtime.requestAddMonitor(new MonitorRecord({ id: 'fakeblock1', opcode: 'fetch_fakeblock', visible: true })); - vm.runtime.requestAddMonitor(MonitorRecord({ + vm.runtime.requestAddMonitor(new MonitorRecord({ // should not be serialized at all id: 'fakeblock2', opcode: 'bitwise_fakeblock', diff --git a/test/integration/tw_serialize_hidden_monitors.js b/test/integration/tw_serialize_hidden_monitors.js index 66e41155db8..ea110549823 100644 --- a/test/integration/tw_serialize_hidden_monitors.js +++ b/test/integration/tw_serialize_hidden_monitors.js @@ -5,12 +5,12 @@ const MonitorRecord = require('../../src/engine/monitor-record'); test('does not serialize hidden monitors from extensions', t => { const rt = new Runtime(); - rt.requestAddMonitor(MonitorRecord({ + rt.requestAddMonitor(new MonitorRecord({ id: 'timer', opcode: 'sensing_timer', visible: true })); - rt.requestAddMonitor(MonitorRecord({ + rt.requestAddMonitor(new MonitorRecord({ id: 'other_monitor', opcode: 'tw_someOpcodeThatIsntPartOfACoreExtension', visible: true diff --git a/test/unit/engine_runtime.js b/test/unit/engine_runtime.js index 68341c29833..d99ecbe5930 100644 --- a/test/unit/engine_runtime.js +++ b/test/unit/engine_runtime.js @@ -4,7 +4,6 @@ const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer const VirtualMachine = require('../../src/virtual-machine'); const Runtime = require('../../src/engine/runtime'); const MonitorRecord = require('../../src/engine/monitor-record'); -const {Map} = require('immutable'); const test = tap.test; @@ -28,15 +27,15 @@ test('spec', t => { test('monitorStateEquals', t => { const r = new Runtime(); const id = 'xklj4#!'; - const prevMonitorState = MonitorRecord({ + const prevMonitorState = new MonitorRecord({ id, opcode: 'turtle whereabouts', value: '25' }); - const newMonitorDelta = Map({ + const newMonitorDelta = { id, value: String(25) - }); + }; r.requestAddMonitor(prevMonitorState); r.requestUpdateMonitor(newMonitorDelta); @@ -49,31 +48,32 @@ test('monitorStateDoesNotEqual', t => { const r = new Runtime(); const id = 'xklj4#!'; const params = {seven: 7}; - const prevMonitorState = MonitorRecord({ + const prevMonitorState = new MonitorRecord({ id, opcode: 'turtle whereabouts', value: '25' }); // Value change - let newMonitorDelta = Map({ + let newMonitorDelta = { id, value: String(24) - }); + }; r.requestAddMonitor(prevMonitorState); r.requestUpdateMonitor(newMonitorDelta); - t.equals(false, prevMonitorState.equals(r._monitorState.get(id))); + t.equals(true, r._monitorState.dirty); t.equals(String(24), r._monitorState.get(id).get('value')); // Prop change - newMonitorDelta = Map({ + r._monitorState.dirty = false; + newMonitorDelta = { id: 'xklj4#!', params: params - }); + }; r.requestUpdateMonitor(newMonitorDelta); - t.equals(false, prevMonitorState.equals(r._monitorState.get(id))); + t.equals(true, r._monitorState.dirty); t.equals(String(24), r._monitorState.get(id).value); t.equals(params, r._monitorState.get(id).params); diff --git a/test/unit/engine_runtime_tw.js b/test/unit/engine_runtime_tw.js index 273f815b7e8..e69e736a6fe 100644 --- a/test/unit/engine_runtime_tw.js +++ b/test/unit/engine_runtime_tw.js @@ -1,6 +1,6 @@ const tap = require('tap'); const Runtime = require('../../src/engine/runtime'); -const {Map} = require('immutable'); +const MonitorRecord = require('../../src/engine/monitor-record'); const makeTestStorage = require('../fixtures/make-test-storage'); const Target = require('../../src/engine/target'); @@ -158,12 +158,12 @@ test('debug', t => { test('setStageSize preserves monitor position relative to center of stage', t => { const rt = new Runtime(); - rt.requestAddMonitor(new Map([ - ['id', 'abc'], + rt.requestAddMonitor(new MonitorRecord({ + id: 'abc', // top right corner - ['x', 0], - ['y', 0] - ])); + x: 0, + y: 0 + })); rt.setStageSize(640, 362); const finalState = rt.getMonitorState().get('abc'); t.equal(finalState.get('x'), 80); diff --git a/test/unit/tw_monitor_record.js b/test/unit/tw_monitor_record.js new file mode 100644 index 00000000000..59cd3a13417 --- /dev/null +++ b/test/unit/tw_monitor_record.js @@ -0,0 +1,56 @@ +const {test} = require('tap'); +const MonitorRecord = require('../../src/engine/monitor-record'); + +test('new and get', t => { + const record = new MonitorRecord({ + id: 'a', + x: 10, + y: 20 + }); + + t.equal(record.id, 'a'); + t.equal(record.x, 10); + t.equal(record.y, 20); + + t.equal(record.get('id'), 'a'); + t.equal(record.get('x'), 10); + t.equal(record.get('y'), 20); + + t.end(); +}); + +test('merge', t => { + const record = new MonitorRecord({ + id: 'a', + x: 10, + y: 20 + }); + + t.equal(record.merge({ + x: 40, + y: null + }), true); + t.equal(record.x, 40); + t.equal(record.y, 20); + + t.equal(record.merge({ + x: 40, + y: undefined + }), false); + t.equal(record.x, 40); + t.equal(record.y, 20); + + t.end(); +}); + +test('externalDeltaToJS', t => { + t.same(MonitorRecord.externalDeltaToJS({ + whatever: 'a' + }), {whatever: 'a'}); + + t.same(MonitorRecord.externalDeltaToJS({ + toJS: () => ({whatever: 'a'}) + }), {whatever: 'a'}); + + t.end(); +}); diff --git a/test/unit/tw_monitor_state.js b/test/unit/tw_monitor_state.js new file mode 100644 index 00000000000..780edb6bb26 --- /dev/null +++ b/test/unit/tw_monitor_state.js @@ -0,0 +1,115 @@ +const {test} = require('tap'); +const MonitorState = require('../../src/engine/tw-monitor-state'); +const MonitorRecord = require('../../src/engine/monitor-record'); + +test('basic operation', t => { + const state = new MonitorState(); + + t.equal(state.dirty, false); + t.equal(state.has('id'), false); + t.equal(state.size, 0); + t.equal(state.empty(), true); + + state.set('id', new MonitorRecord({ + id: 'id', + value: 0 + })); + t.equal(state.has('id'), true); + t.equal(state.get('id').id, 'id'); + t.equal(state.get('id').value, 0); + t.equal(state.size, 1); + t.equal(state.empty(), false); + t.equal(state.dirty, true); + + state.dirty = false; + state.set('id', new MonitorRecord({ + id: 'id', + value: -0 + })); + t.equal(state.get('id').value, -0); + t.equal(state.dirty, true); + + state.dirty = false; + state.set('id', new MonitorRecord({ + id: 'id', + value: -0 + })); + t.equal(state.dirty, false); + + state.dirty = false; + state.delete('id'); + t.equal(state.has('id'), false); + t.equal(state.get('id'), undefined); + t.equal(state.size, 0); + t.equal(state.empty(), true); + t.equal(state.dirty, true); + + state.dirty = false; + state.delete('id'); + t.equal(state.dirty, false); + + t.end(); +}); + +test('filter', t => { + const state = new MonitorState(); + + state.set('id1', new MonitorRecord({ + id: 'id1', + value: 5 + })); + state.set('id2', new MonitorRecord({ + id: 'id2', + value: 10 + })); + state.set('id3', new MonitorRecord({ + id: 'id3', + value: 15 + })); + + state.dirty = false; + state.filter(record => record.value !== 10); + t.equal(state.dirty, true); + t.equal(state.has('id1'), true); + t.equal(state.has('id2'), false); + t.equal(state.has('id3'), true); + + state.dirty = false; + state.filter(record => record.value !== 10); + t.equal(state.dirty, false); + + t.end(); +}); + +test('value', t => { + const state = new MonitorState(); + + const a = new MonitorRecord({ + id: 'a' + }); + const b = new MonitorRecord({ + id: 'b' + }); + state.set('a', a); + state.set('b', b); + + t.same(state.values(), [a, b]); + t.same(state.valueSeq(), [a, b]); + + t.end(); +}); + +test('shallowClone', t => { + const state = new MonitorState(); + + state.set('id', new MonitorRecord({ + id: 'id' + })); + + const clone = state.shallowClone(); + t.not(state, clone); + t.equal(state.map, clone.map); + t.equal(clone.dirty, false); + + t.end(); +}); diff --git a/webpack.config.js b/webpack.config.js index 8686f7a7d91..25d241d6730 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -69,7 +69,6 @@ module.exports = [ 'decode-html': true, 'format-message': true, 'htmlparser2': true, - 'immutable': true, 'scratch-parser': true, 'socket.io-client': true, 'text-encoding': true From 676ba53e2205a06b24c565cefb83606429a227d8 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 10 Jan 2026 09:13:14 -0600 Subject: [PATCH 087/106] Compress extension images --- src/extensions/scratch3_boost/index.js | 2 +- src/extensions/scratch3_ev3/index.js | 2 +- src/extensions/scratch3_gdx_for/index.js | 4 ++-- src/extensions/scratch3_makeymakey/index.js | 2 +- src/extensions/scratch3_microbit/index.js | 2 +- src/extensions/scratch3_music/index.js | 4 ++-- src/extensions/scratch3_pen/index.js | 2 +- src/extensions/scratch3_speech2text/index.js | 4 ++-- src/extensions/scratch3_text2speech/index.js | 4 ++-- src/extensions/scratch3_translate/index.js | 4 ++-- src/extensions/scratch3_video_sensing/index.js | 4 ++-- src/extensions/scratch3_wedo2/index.js | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/extensions/scratch3_boost/index.js b/src/extensions/scratch3_boost/index.js index 21564befb96..717940d46fd 100644 --- a/src/extensions/scratch3_boost/index.js +++ b/src/extensions/scratch3_boost/index.js @@ -19,7 +19,7 @@ const log = require('../../util/log'); * @type {string} */ // eslint-disable-next-line max-len -const iconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACpQTFRF////fIel5ufolZ62/2YavsPS+YZOkJmy9/j53+Hk6+zs6N/b6dfO////tDhMHAAAAA50Uk5T/////////////////wBFwNzIAAAA6ElEQVR42uzX2w6DIBAEUGDVtlr//3dLaLwgiwUd2z7MJPJg5EQWiGhGcAxBggQJEiT436CIfqXJPTn3MKNYYMSDFpoAmp24OaYgvwKnFgL2zvVTCwHrMoMi+nUQLFthaNCCa0iwclLkDgYVsQp0mzxuqXgK1MRzoCLWgkPXNN2wI/q6Kvt7u/cX0HtejN8x2sXpnpb8J8D3b0Keuhh3X975M+i0xNVbg3s1TIasgK21bQyGO+s2PykaGMYbge8KrNrssvkOWDXkErB8UuBHETjoYLkKBA8ZfuDkbwVBggQJEiR4MC8BBgDTtMZLx2nFCQAAAABJRU5ErkJggg=='; +const iconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACpQTFRF////6+zskJmy3+Hk6N/b+YZO/2Ya6dfO9/j5vsPSlZ62////fIel5ufo1AuBvgAAAAF0Uk5TAEDm2GYAAADNSURBVHja7dfRDoMgDIXhuQmbpbz/645JsspKOiM1u9j5E7gw8YtCSPSCEEII/VlE/aEjskeJ2LEXya6tYDLK79KOfgWm5AhOOU91HgftbJCoN46C+yJvkJ3XEKAJ6ujhBYo4BOaPblcRh0ERvUARh8A5xBhmQ2TW51uffQFDLIXciM0p1meaWCdgXLv3xfZ2eebvYO5VCWGMVVWvbIML89KA9cpmVptig1xqwHplMwso+YJuryy5bIpjZ4HZrZNA19w/OPE3gBBCCB3vCQkmeCf31OYLAAAAAElFTkSuQmCC'; /** * Boost BLE UUIDs. diff --git a/src/extensions/scratch3_ev3/index.js b/src/extensions/scratch3_ev3/index.js index 7803f2394e3..99255bc2bcf 100644 --- a/src/extensions/scratch3_ev3/index.js +++ b/src/extensions/scratch3_ev3/index.js @@ -14,7 +14,7 @@ const log = require('../../util/log'); * @type {string} */ // eslint-disable-next-line max-len -const blockIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNDBweCIgaGVpZ2h0PSI0MHB4IiB2aWV3Qm94PSIwIDAgNDAgNDAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUwLjIgKDU1MDQ3KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5ldjMtYmxvY2staWNvbjwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPjwvZGVmcz4KICAgIDxnIGlkPSJldjMtYmxvY2staWNvbiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9ImV2MyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNS41MDAwMDAsIDMuNTAwMDAwKSIgZmlsbC1ydWxlPSJub256ZXJvIj4KICAgICAgICAgICAgPHJlY3QgaWQ9IlJlY3RhbmdsZS1wYXRoIiBzdHJva2U9IiM3Qzg3QTUiIGZpbGw9IiNGRkZGRkYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgeD0iMC41IiB5PSIzLjU5IiB3aWR0aD0iMjgiIGhlaWdodD0iMjUuODEiIHJ4PSIxIj48L3JlY3Q+CiAgICAgICAgICAgIDxyZWN0IGlkPSJSZWN0YW5nbGUtcGF0aCIgc3Ryb2tlPSIjN0M4N0E1IiBmaWxsPSIjRTZFN0U4IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHg9IjIuNSIgeT0iMC41IiB3aWR0aD0iMjQiIGhlaWdodD0iMzIiIHJ4PSIxIj48L3JlY3Q+CiAgICAgICAgICAgIDxyZWN0IGlkPSJSZWN0YW5nbGUtcGF0aCIgc3Ryb2tlPSIjN0M4N0E1IiBmaWxsPSIjRkZGRkZGIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHg9IjIuNSIgeT0iMTQuNSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjEzIj48L3JlY3Q+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNC41LDEwLjUgTDE0LjUsMTQuNSIgaWQ9IlNoYXBlIiBzdHJva2U9IiM3Qzg3QTUiIGZpbGw9IiNFNkU3RTgiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PC9wYXRoPgogICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlLXBhdGgiIGZpbGw9IiM0MTQ3NTciIHg9IjQuNSIgeT0iMi41IiB3aWR0aD0iMjAiIGhlaWdodD0iMTAiIHJ4PSIxIj48L3JlY3Q+CiAgICAgICAgICAgIDxyZWN0IGlkPSJSZWN0YW5nbGUtcGF0aCIgZmlsbD0iIzdDODdBNSIgb3BhY2l0eT0iMC41IiB4PSIxMy41IiB5PSIyMC4xMyIgd2lkdGg9IjIiIGhlaWdodD0iMiIgcng9IjAuNSI+PC9yZWN0PgogICAgICAgICAgICA8cGF0aCBkPSJNOS4wNiwyMC4xMyBMMTAuNTYsMjAuMTMgQzEwLjgzNjE0MjQsMjAuMTMgMTEuMDYsMjAuMzUzODU3NiAxMS4wNiwyMC42MyBMMTEuMDYsMjEuNjMgQzExLjA2LDIxLjkwNjE0MjQgMTAuODM2MTQyNCwyMi4xMyAxMC41NiwyMi4xMyBMOS4wNiwyMi4xMyBDOC41MDc3MTUyNSwyMi4xMyA4LjA2LDIxLjY4MjI4NDcgOC4wNiwyMS4xMyBDOC4wNiwyMC41Nzc3MTUzIDguNTA3NzE1MjUsMjAuMTMgOS4wNiwyMC4xMyBaIiBpZD0iU2hhcGUiIGZpbGw9IiM3Qzg3QTUiIG9wYWNpdHk9IjAuNSI+PC9wYXRoPgogICAgICAgICAgICA8cGF0aCBkPSJNMTguOTEsMjAuMTMgTDIwLjQyLDIwLjEzIEMyMC42OTYxNDI0LDIwLjEzIDIwLjkyLDIwLjM1Mzg1NzYgMjAuOTIsMjAuNjMgTDIwLjkyLDIxLjYzIEMyMC45MiwyMS45MDYxNDI0IDIwLjY5NjE0MjQsMjIuMTMgMjAuNDIsMjIuMTMgTDE4LjkyLDIyLjEzIEMxOC4zNjc3MTUzLDIyLjEzIDE3LjkyLDIxLjY4MjI4NDcgMTcuOTIsMjEuMTMgQzE3LjkxOTk3MjYsMjAuNTgxNTk3IDE4LjM2MTYyNDUsMjAuMTM1NDg0IDE4LjkxLDIwLjEzIFoiIGlkPSJTaGFwZSIgZmlsbD0iIzdDODdBNSIgb3BhY2l0eT0iMC41IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxOS40MjAwMDAsIDIxLjEzMDAwMCkgcm90YXRlKC0xODAuMDAwMDAwKSB0cmFuc2xhdGUoLTE5LjQyMDAwMCwgLTIxLjEzMDAwMCkgIj48L3BhdGg+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik04LjIzLDE3LjUgTDUsMTcuNSBDNC43MjM4NTc2MywxNy41IDQuNSwxNy4yNzYxNDI0IDQuNSwxNyBMNC41LDE0LjUgTDEwLjUsMTQuNSBMOC42NSwxNy4yOCBDOC41NTQ2Njk2MSwxNy40MTc5MDgyIDguMzk3NjUwMDYsMTcuNTAwMTU2NiA4LjIzLDE3LjUgWiIgaWQ9IlNoYXBlIiBmaWxsPSIjN0M4N0E1IiBvcGFjaXR5PSIwLjUiPjwvcGF0aD4KICAgICAgICAgICAgPHBhdGggZD0iTTE4LjE1LDE4Ljg1IEwxNy42NSwxOS4zNSBDMTcuNTUyMzQxNiwxOS40NDQwNzU2IDE3LjQ5ODAzMzksMTkuNTc0NDE0MiAxNy41LDE5LjcxIEwxNy41LDIwIEMxNy41LDIwLjI3NjE0MjQgMTcuMjc2MTQyNCwyMC41IDE3LDIwLjUgTDE2LjUsMjAuNSBDMTYuMjIzODU3NiwyMC41IDE2LDIwLjI3NjE0MjQgMTYsMjAgQzE2LDE5LjcyMzg1NzYgMTUuNzc2MTQyNCwxOS41IDE1LjUsMTkuNSBMMTMuNSwxOS41IEMxMy4yMjM4NTc2LDE5LjUgMTMsMTkuNzIzODU3NiAxMywyMCBDMTMsMjAuMjc2MTQyNCAxMi43NzYxNDI0LDIwLjUgMTIuNSwyMC41IEwxMiwyMC41IEMxMS43MjM4NTc2LDIwLjUgMTEuNSwyMC4yNzYxNDI0IDExLjUsMjAgTDExLjUsMTkuNzEgQzExLjUwMTk2NjEsMTkuNTc0NDE0MiAxMS40NDc2NTg0LDE5LjQ0NDA3NTYgMTEuMzUsMTkuMzUgTDEwLjg1LDE4Ljg1IEMxMC42NTgyMTY3LDE4LjY1MjE4NjMgMTAuNjU4MjE2NywxOC4zMzc4MTM3IDEwLjg1LDE4LjE0IEwxMi4zNiwxNi42NSBDMTIuNDUwMjgwMywxNi41NTI4NjE3IDEyLjU3NzM5NjEsMTYuNDk4MzgzNSAxMi43MSwxNi41IEwxNi4yOSwxNi41IEMxNi40MjI2MDM5LDE2LjQ5ODM4MzUgMTYuNTQ5NzE5NywxNi41NTI4NjE3IDE2LjY0LDE2LjY1IEwxOC4xNSwxOC4xNCBDMTguMzQxNzgzMywxOC4zMzc4MTM3IDE4LjM0MTc4MzMsMTguNjUyMTg2MyAxOC4xNSwxOC44NSBaIiBpZD0iU2hhcGUiIGZpbGw9IiM3Qzg3QTUiIG9wYWNpdHk9IjAuNSI+PC9wYXRoPgogICAgICAgICAgICA8cGF0aCBkPSJNMTAuODUsMjMuNDUgTDExLjM1LDIyLjk1IEMxMS40NDc2NTg0LDIyLjg1NTkyNDQgMTEuNTAxOTY2MSwyMi43MjU1ODU4IDExLjUsMjIuNTkgTDExLjUsMjIuMyBDMTEuNSwyMi4wMjM4NTc2IDExLjcyMzg1NzYsMjEuOCAxMiwyMS44IEwxMi41LDIxLjggQzEyLjc3NjE0MjQsMjEuOCAxMywyMi4wMjM4NTc2IDEzLDIyLjMgQzEzLDIyLjU3NjE0MjQgMTMuMjIzODU3NiwyMi44IDEzLjUsMjIuOCBMMTUuNSwyMi44IEMxNS43NzYxNDI0LDIyLjggMTYsMjIuNTc2MTQyNCAxNiwyMi4zIEMxNiwyMi4wMjM4NTc2IDE2LjIyMzg1NzYsMjEuOCAxNi41LDIxLjggTDE3LDIxLjggQzE3LjI3NjE0MjQsMjEuOCAxNy41LDIyLjAyMzg1NzYgMTcuNSwyMi4zIEwxNy41LDIyLjU5IEMxNy40OTgwMzM5LDIyLjcyNTU4NTggMTcuNTUyMzQxNiwyMi44NTU5MjQ0IDE3LjY1LDIyLjk1IEwxOC4xNSwyMy40NSBDMTguMzQwNTcxNCwyMy42NDQ0MjE4IDE4LjM0MDU3MTQsMjMuOTU1NTc4MiAxOC4xNSwyNC4xNSBMMTYuNjQsMjUuNjUgQzE2LjU0OTcxOTcsMjUuNzQ3MTM4MyAxNi40MjI2MDM5LDI1LjgwMTYxNjUgMTYuMjksMjUuOCBMMTIuNzEsMjUuOCBDMTIuNTc3Mzk2MSwyNS44MDE2MTY1IDEyLjQ1MDI4MDMsMjUuNzQ3MTM4MyAxMi4zNiwyNS42NSBMMTAuODUsMjQuMTUgQzEwLjY1OTQyODYsMjMuOTU1NTc4MiAxMC42NTk0Mjg2LDIzLjY0NDQyMTggMTAuODUsMjMuNDUgWiIgaWQ9IlNoYXBlIiBmaWxsPSIjN0M4N0E1IiBvcGFjaXR5PSIwLjUiPjwvcGF0aD4KICAgICAgICAgICAgPHBhdGggZD0iTTIxLjUsMjcuNSBMMjYuNSwyNy41IEwyNi41LDMxLjUgQzI2LjUsMzIuMDUyMjg0NyAyNi4wNTIyODQ3LDMyLjUgMjUuNSwzMi41IEwyMS41LDMyLjUgTDIxLjUsMjcuNSBaIiBpZD0iU2hhcGUiIHN0cm9rZT0iI0NDNEMyMyIgZmlsbD0iI0YxNUEyOSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48L3BhdGg+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4='; +const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIj48dGl0bGU+ZXYzLWJsb2NrLWljb248L3RpdGxlPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0ibm9uemVybyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNS41IDMuNSkiPjxyZWN0IHdpZHRoPSIyOCIgaGVpZ2h0PSIyNS44MSIgeD0iLjUiIHk9IjMuNTkiIGZpbGw9IiNmZmYiIHN0cm9rZT0iIzdjODdhNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiByeD0iMSIvPjxyZWN0IHdpZHRoPSIyNCIgaGVpZ2h0PSIzMiIgeD0iMi41IiB5PSIuNSIgZmlsbD0iI2U2ZTdlOCIgc3Ryb2tlPSIjN2M4N2E1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHJ4PSIxIi8+PHBhdGggZmlsbD0iI2ZmZiIgc3Ryb2tlPSIjN2M4N2E1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGQ9Ik0yLjUgMTQuNWgyNHYxM2gtMjR6Ii8+PHBhdGggZmlsbD0iI2U2ZTdlOCIgc3Ryb2tlPSIjN2M4N2E1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGQ9Ik0xNC41IDEwLjV2NCIvPjxyZWN0IHdpZHRoPSIyMCIgaGVpZ2h0PSIxMCIgeD0iNC41IiB5PSIyLjUiIGZpbGw9IiM0MTQ3NTciIHJ4PSIxIi8+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMTMuNSIgeT0iMjAuMTMiIGZpbGw9IiM3Yzg3YTUiIG9wYWNpdHk9Ii41IiByeD0iLjUiLz48cGF0aCBmaWxsPSIjN2M4N2E1IiBkPSJNOS4wNiAyMC4xM2gxLjVhLjUuNSAwIDAgMSAuNS41djFhLjUuNSAwIDAgMS0uNS41aC0xLjVhMSAxIDAgMCAxIDAtMk0xOS45MyAyMi4xM2gtMS41MWEuNS41IDAgMCAxLS41LS41di0xYS41LjUgMCAwIDEgLjUtLjVoMS41YTEgMSAwIDAgMSAuMDEgMk04LjIzIDE3LjVINWEuNS41IDAgMCAxLS41LS41di0yLjVoNmwtMS44NSAyLjc4YS41MS41MSAwIDAgMS0uNDIuMjJNMTguMTUgMTguODVsLS41LjVhLjUuNSAwIDAgMC0uMTUuMzZWMjBhLjUuNSAwIDAgMS0uNS41aC0uNWEuNS41IDAgMCAxLS41LS41LjUuNSAwIDAgMC0uNS0uNWgtMmEuNS41IDAgMCAwLS41LjUuNS41IDAgMCAxLS41LjVIMTJhLjUuNSAwIDAgMS0uNS0uNXYtLjI5YS41LjUgMCAwIDAtLjE1LS4zNmwtLjUtLjVhLjUxLjUxIDAgMCAxIDAtLjcxbDEuNTEtMS40OWEuNDcuNDcgMCAwIDEgLjM1LS4xNWgzLjU4YS40Ny40NyAwIDAgMSAuMzUuMTVsMS41MSAxLjQ5YS41MS41MSAwIDAgMSAwIC43MU0xMC44NSAyMy40NWwuNS0uNWEuNS41IDAgMCAwIC4xNS0uMzZ2LS4yOWEuNS41IDAgMCAxIC41LS41aC41YS41LjUgMCAwIDEgLjUuNS41LjUgMCAwIDAgLjUuNWgyYS41LjUgMCAwIDAgLjUtLjUuNS41IDAgMCAxIC41LS41aC41YS41LjUgMCAwIDEgLjUuNXYuMjlhLjUuNSAwIDAgMCAuMTUuMzZsLjUuNWEuNS41IDAgMCAxIDAgLjdsLTEuNTEgMS41YS40Ny40NyAwIDAgMS0uMzUuMTVoLTMuNThhLjQ3LjQ3IDAgMCAxLS4zNS0uMTVsLTEuNTEtMS41YS41LjUgMCAwIDEgMC0uNyIgb3BhY2l0eT0iLjUiLz48cGF0aCBmaWxsPSIjZjE1YTI5IiBzdHJva2U9IiNjYzRjMjMiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0iTTIxLjUgMjcuNWg1djRhMSAxIDAgMCAxLTEgMWgtNHoiLz48L2c+PC9zdmc+'; /** * String with Ev3 expected pairing pin. diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index e88b142e639..64bfae8f00a 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -12,14 +12,14 @@ const ScratchLinkDeviceAdapter = require('./scratch-link-device-adapter'); * @type {string} */ // eslint-disable-next-line max-len -const blockIconURI = 'data:image/png;base64,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'; +const blockIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAABGdBTUEAALGPC/xhBQAABVNJREFUeNrtnH9MG1UcwMuIiWMaE7c5ptkUhyQaEzWLi8aE+BfRPxbjEowxipMlisxlTFAY9JAQoNfyG/wRGQyH9uj6AyiFzblRuohzxCmYjZ9tZaNlEGPUaNTEQZ/vW97Zs/bWwsKul3y/ySe8e+8Vvvn0vXv3jvY0NxJlHzuSSnihi9MJC1qdkagJyBlyr64+tUGjVGh5ow2SUTMgUTGBnE6YFxMp1XeSysYuUtnUHddAjpCrdCQqJlAiTypRFfKkEpUWKE1MFbA3On4EwrtbwRJSA2yWxJdAaUIv28fjEkm+KBAFytFziexvGyTv1neREr2JFBtM5J2GbpJL67K6LqLA65FtukAK622y566iWmtgn+kbFBiJV63f09F2PBD8Hbzwp1YvVJXXdj1S1ujYrtV1chxv/APaoM9e8wgKDCe/uS/4WipqrqCj43/bq+IGYQtt/4lC8pt6UaCUfaYL4q5gSfeBPVUjExUVnds4nXEJ+mabv0OBIrlHXeLom4n+N4Vp6Jv7yVkUKHKg5cyyQL3xTNT9t15wQt/9bU4UKPLmsS/Za4Xp6HeAhPHgCGzHEfgv2ce/JWz1/ZsQkqCRiUxCEmmfa7QvvAYFSimqsSxv9HnTQdnpy3cWQJ/CGguuwuEcODLAFhLBIy9Q8EKft1qdKDCcvZYRmMIBLW8MwDWfJiwqK21boR14zTqKAiNR0GQXR2FbhMXjKG2DPriVkyPn2JC4Gv+qCQuog7acjiEUKMcr3RdJicEU3A+XGUwZGhZQhrpi2kb7oMDrcfCjz9kljfE3rc78TGnNZ88ul43QhrezYrkrc7jGHByFUqCOtqHA2FbkUXLowxPksMEEQBnq8I403tJHgeoRWNhnJ64vngegjAJXQk7vV+R35x2EDGoAKEMdCoyV2v73QZwUqEOBsVLgOEGWBhNEeVCGOhS4Eo6cLCc/OzcDUF7d5ZB1lLz+6dfBOz35zQ5chWOV9XaTA/79CblIQYEyI0tWFscL5D2DiZTVmEl5vVU1AhUZWeGyKiJ8TlE9ApWXBahW4JpOw4qGaLLUL1BhWeoXqKAs9QuMLqtOVhYKZMexyEKBcgLZ8YrQNVtWAwoEZvsfhP3uqnDbd6JAr+NRsuhMXBVjPU+hQDwHosCbK3Cm72E4f60Jk/ZdKPBGmOh5AqcwTmEUiALx665RgFzjSiAkxOkFNX3hGnKOH4GiPE4FX/mHHFnOyguUPu6kVC+o56ET0tnCC/OKCYRHhkASaqZUJ1gVEwgP3uGqBAs8/kSND97heMFyyGxer1FnyJ9Tr84vRERs12CgQBSIAlEgBgpcC4HyoMAYdjb90eRxvNCHpqJHKiXth5nLozB1W1raXoBjyj2UBNQTPe4GYUPnzlWBwMtXfBMZGRk7UWLskQSykpOTHxJHIf05IpF4FyqKHltBVlZW1pNXZn3TINHt8bigjnErKgrFOjaqdlDup2xiddskEn0g8dTp0wVM4BbUxoLJSwtjo1SizWZ7AwROuT0DrP0+1LYcCeKq6/Z6z46PT3YzQSms/RY43r1nz+Mg0Ofz/8jaU1FdSGAa4PPP/UIlBdLT0x9jdUmU26Gcl5f3NAikU9nN2nagulCkgBS3x+sESQMDg0VwLOX8+WEDtF0aG7Owuu2oLRSbQUp7e/tLIMk/d/Uvp8vFZWZm7oIFhF4P6mj9NcpidV3dbibwTtQWikQ2JdOGh4drYRpTSBiLIFVyflyH2v4bt4EcoLW19cXJqamTs/65BXrO809MTvc2NjY+B22M9agrcmxg14FpMqSgvNim8yZ2nfcA417Kxnictv8ABNVN4ivCsdYAAAAASUVORK5CYII='; /** * Icon png to be displayed in the blocks category menu, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len -const menuIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABGdBTUEAALGPC/xhBQAAA9dJREFUWAnNmE2IFEcUgF/9dE/v7LoaM9kkK4JBRA0EFBIPRm85hBAvEXHXwyo5eFE87GFcReMkObgJiQnkkJzEg9n8HIJixKNe1IMKihgiCbviwV11V3d0d3pmuqsqr5ppcEnb3TNVggVFVVe9eu+r97qqq4tASqp8/fsboQgmU0TMugi571K29bPy9ovPU8Sf16HbpQj3EkYFBcJcr5Am2nZfs94AIWVfqMQeHNwhICUBZ4ypUIA/X2sbIm2AW8AJK0lkEP6TJpfqwXgg4QxmF/fB7Gtvxk1G5ZKHU1CqTgPJoSUXYJYeohSUJu+qrqdVUGh2/pVX4VFffx77WaqBZkrkEFj271+qWH0sXcU3FBzyQe/Mg7B//LbKMTRTxNiDbsMHHjTJlyM7HEJIBHXs2KXFj+oTNSdoQOCYLS5jD9IwBMm5H8NplwwPb/QV4yEIcycaAza9IuA76B38fuz1OF5RXUkmHCdu6rg0BpSMgV/sAe7DdzGFrvvdi0D3mSZjQA0wt7REQsY+iWF0XbfFzyal8SLRxuteD+Du4h4Z/flbqaBHibAQtZmQtcZaAZSMwtTylaR/4vaw1ju5YhWG10pwwAqghmp2FeHO2+t11WqyM80W0m7vAOhsM1kD7CGz8L57Jsq6bitZC/GcWgLf1H6KuHT92cTDAFy/BgXMXm0OCpgV50Bo9kK3BqiBboabQMMU/WoL5im4jToeq/AIgXsiRx5KKCjcwPEsiAv/BQMu9EwyDHXd/3kqCOSzDk6t5/YglQKKeJwq+PNRmJI8kwSTaj1HZy5AhSHqnXkIvU9mMUwEw4Q5wTM57LUtkg8QPw/cdcBJ+PhvKJ0Gj80nGq6JXrg6/XFiX97GXIBpyqTieKpKViOl+WEhWXMaUavvvdIZ8Giy5+Lh3bwKm/t+Be3JazMfxc1tldY26rastiHcsQevTG9pw0znovkAcRWHzSDKnZtaOJLSfMFLB5RqtRBS4LbCurqLCy0YPkU3C0IIPEimMqR2ei7ZX2+KQdRi/WahNT/GmfOD4Vyzhx/66pcjp85dUvcmp6J8+txldXh07PPskdkS+V6EbD0vTOKlB0x9B/O6BS8ULly9PgE6x4kDPR/XX5pyYKj8xcCucsUmkNUQE0JvKKm2VioVK5HRE7UKOHbi6B94RzP+93jtpC0vWgXUF0hr3ipuw8uadwd3jXxoA9IK4Pah8t6BneV9GgjD28Svw1mlxFobgFbeFTz13cKbth93fDryp2CEq0a4hTA+aAPQ/ESJFDdvXLzzzrqNjlTqOP6uDeFf0uhvJ0ZP2QD8D6ZzU6u8YIbBAAAAAElFTkSuQmCC'; +const menuIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABGdBTUEAALGPC/xhBQAAAppJREFUeNrtmF1r01AYx6OI4CfQG2+88BMIXnjhy5V3XoikHZq+bCsKszChsS9Lk5WONFnbbSKIm5frSdLVrhWldm4qEzoVX5CpeCFeidsnENGZs/OEhcFaxtYl67noA394esp5+uuTf05ODrNdSGrx2JBcwK4pg1ZTqnGGaTeSMkoLqrYmqjoeuTPrqEhNADSTCkJtAw4pmijlilhUNMe7l8qXsEhqCxk0vGdA0MCDBXy1+tUJkVrPsVV3vwCvVb7gwXs1M67qZkw1zPDUvEkVYDQ7YyYyaE1SSqekseIF4q2//NisSQVgsPje8hSJA/a8fL5xBMYCpY+dB+xDb3B81Pi9dW5CNf4FjA+dB+TKyzhBvBcfR0fteZAnFM2E76jw4K27j82kvLmeQQ5j1NwkIfQax1Xjjz0PchijBpArfwYfmmKmkBPkwn24QWCMGkBQUH+HAQzUq73d2ULdfZJs0WL9EohOwOuPGvj/i4MgyOnsoPJkEtQ07n/4CYeml/DNqQUcmahaPhVHjf0HbIapwCKOE7Bdy1p1rG3WMMmTqu44YFsw6fFy02ZVyrkAGJ6c24CZ3w0MyH1AMWuAbzZgZraD6QigXazljz1DfvzKuNJSddTbecB6oQ+/1L0tVZsOdQ5wDgXxos7uSE8L/V1AG7BduQzo/Hsx1HQAUEZIUHXXThbg1ELIaCNtA6Zz2nH4t24Kzn8YtwOsUKk18K+VVUvV2tKuLl0XkHpAQUVnm7wla+cY2sLD8SmPn5cYWsPri15muciyJEmHqASEAySPj6+STuoMrUG6d9jji3z3+qMXqYFiOX6AdC5sfyb5BIEcpAawh+PPE8hvPcHoCbY/dpL48IcnEDvN0BTQMdYXWSH6yfpu33Cq7jqUK06WtbQJQQAAAABJRU5ErkJggg=='; /** * Enum for Vernier godirect protocol. diff --git a/src/extensions/scratch3_makeymakey/index.js b/src/extensions/scratch3_makeymakey/index.js index e57bc76e89d..550736ea979 100644 --- a/src/extensions/scratch3_makeymakey/index.js +++ b/src/extensions/scratch3_makeymakey/index.js @@ -8,7 +8,7 @@ const Cast = require('../../util/cast'); * @type {string} */ // eslint-disable-next-line max-len -const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHN0eWxlPi5zdDJ7ZmlsbDpyZWR9LnN0M3tmaWxsOiNlMGUwZTB9LnN0NHtmaWxsOm5vbmU7c3Ryb2tlOiM2NjY7c3Ryb2tlLXdpZHRoOi41O3N0cm9rZS1taXRlcmxpbWl0OjEwfTwvc3R5bGU+PHBhdGggZD0iTTM1IDI4SDVhMSAxIDAgMCAxLTEtMVYxMmMwLS42LjQtMSAxLTFoMzBjLjUgMCAxIC40IDEgMXYxNWMwIC41LS41IDEtMSAxeiIgZmlsbD0iI2ZmZiIgaWQ9IkxheWVyXzYiLz48ZyBpZD0iTGF5ZXJfNCI+PHBhdGggY2xhc3M9InN0MiIgZD0iTTQgMjVoMzJ2Mi43SDR6TTEzIDI0aC0yLjJhMSAxIDAgMCAxLTEtMXYtOS43YzAtLjYuNC0xIDEtMUgxM2MuNiAwIDEgLjQgMSAxVjIzYzAgLjYtLjUgMS0xIDF6Ii8+PHBhdGggY2xhc3M9InN0MiIgZD0iTTYuMSAxOS4zdi0yLjJjMC0uNS40LTEgMS0xaDkuN2MuNSAwIDEgLjUgMSAxdjIuMmMwIC41LS41IDEtMSAxSDcuMWExIDEgMCAwIDEtMS0xeiIvPjxjaXJjbGUgY2xhc3M9InN0MiIgY3g9IjIyLjgiIGN5PSIxOC4yIiByPSIzLjQiLz48Y2lyY2xlIGNsYXNzPSJzdDIiIGN4PSIzMC42IiBjeT0iMTguMiIgcj0iMy40Ii8+PHBhdGggY2xhc3M9InN0MiIgZD0iTTQuMiAyN2gzMS45di43SDQuMnoiLz48L2c+PGcgaWQ9IkxheWVyXzUiPjxjaXJjbGUgY2xhc3M9InN0MyIgY3g9IjIyLjgiIGN5PSIxOC4yIiByPSIyLjMiLz48Y2lyY2xlIGNsYXNzPSJzdDMiIGN4PSIzMC42IiBjeT0iMTguMiIgcj0iMi4zIi8+PHBhdGggY2xhc3M9InN0MyIgZD0iTTEyLjUgMjIuOWgtMS4yYy0uMyAwLS41LS4yLS41LS41VjE0YzAtLjMuMi0uNS41LS41aDEuMmMuMyAwIC41LjIuNS41djguNGMwIC4zLS4yLjUtLjUuNXoiLz48cGF0aCBjbGFzcz0ic3QzIiBkPSJNNy4yIDE4Ljd2LTEuMmMwLS4zLjItLjUuNS0uNWg4LjRjLjMgMCAuNS4yLjUuNXYxLjJjMCAuMy0uMi41LS41LjVINy43Yy0uMyAwLS41LS4yLS41LS41ek00IDI2aDMydjJINHoiLz48L2c+PGcgaWQ9IkxheWVyXzMiPjxwYXRoIGNsYXNzPSJzdDQiIGQ9Ik0zNS4yIDI3LjlINC44YTEgMSAwIDAgMS0xLTFWMTIuMWMwLS42LjUtMSAxLTFoMzAuNWMuNSAwIDEgLjQgMSAxVjI3YTEgMSAwIDAgMS0xLjEuOXoiLz48cGF0aCBjbGFzcz0ic3Q0IiBkPSJNMzUuMiAyNy45SDQuOGExIDEgMCAwIDEtMS0xVjEyLjFjMC0uNi41LTEgMS0xaDMwLjVjLjUgMCAxIC40IDEgMVYyN2ExIDEgMCAwIDEtMS4xLjl6Ii8+PC9nPjwvc3ZnPg=='; +const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHN0eWxlPi5zdDJ7ZmlsbDpyZWR9LnN0M3tmaWxsOiNlMGUwZTB9LnN0NHtmaWxsOm5vbmU7c3Ryb2tlOiM2NjY7c3Ryb2tlLXdpZHRoOi41O3N0cm9rZS1taXRlcmxpbWl0OjEwfTwvc3R5bGU+PHBhdGggaWQ9IkxheWVyXzYiIGZpbGw9IiNmZmYiIGQ9Ik0zNSAyOEg1YTEgMSAwIDAgMS0xLTFWMTJjMC0uNi40LTEgMS0xaDMwYy41IDAgMSAuNCAxIDF2MTVjMCAuNS0uNSAxLTEgMSIvPjxnIGlkPSJMYXllcl80Ij48cGF0aCBkPSJNNCAyNWgzMnYyLjdINHptOS0xaC0yLjJhMSAxIDAgMCAxLTEtMXYtOS43YzAtLjYuNC0xIDEtMUgxM2MuNiAwIDEgLjQgMSAxVjIzYzAgLjYtLjUgMS0xIDEiIGNsYXNzPSJzdDIiLz48cGF0aCBkPSJNNi4xIDE5LjN2LTIuMmMwLS41LjQtMSAxLTFoOS43Yy41IDAgMSAuNSAxIDF2Mi4yYzAgLjUtLjUgMS0xIDFINy4xYTEgMSAwIDAgMS0xLTEiIGNsYXNzPSJzdDIiLz48Y2lyY2xlIGN4PSIyMi44IiBjeT0iMTguMiIgcj0iMy40IiBjbGFzcz0ic3QyIi8+PGNpcmNsZSBjeD0iMzAuNiIgY3k9IjE4LjIiIHI9IjMuNCIgY2xhc3M9InN0MiIvPjxwYXRoIGQ9Ik00LjIgMjdoMzEuOXYuN0g0LjJ6IiBjbGFzcz0ic3QyIi8+PC9nPjxnIGlkPSJMYXllcl81Ij48Y2lyY2xlIGN4PSIyMi44IiBjeT0iMTguMiIgcj0iMi4zIiBjbGFzcz0ic3QzIi8+PGNpcmNsZSBjeD0iMzAuNiIgY3k9IjE4LjIiIHI9IjIuMyIgY2xhc3M9InN0MyIvPjxwYXRoIGQ9Ik0xMi41IDIyLjloLTEuMmMtLjMgMC0uNS0uMi0uNS0uNVYxNGMwLS4zLjItLjUuNS0uNWgxLjJjLjMgMCAuNS4yLjUuNXY4LjRjMCAuMy0uMi41LS41LjUiIGNsYXNzPSJzdDMiLz48cGF0aCBkPSJNNy4yIDE4Ljd2LTEuMmMwLS4zLjItLjUuNS0uNWg4LjRjLjMgMCAuNS4yLjUuNXYxLjJjMCAuMy0uMi41LS41LjVINy43Yy0uMyAwLS41LS4yLS41LS41TTQgMjZoMzJ2Mkg0eiIgY2xhc3M9InN0MyIvPjwvZz48ZyBpZD0iTGF5ZXJfMyI+PHBhdGggZD0iTTM1LjIgMjcuOUg0LjhhMSAxIDAgMCAxLTEtMVYxMi4xYzAtLjYuNS0xIDEtMWgzMC41Yy41IDAgMSAuNCAxIDFWMjdhMSAxIDAgMCAxLTEuMS45eiIgY2xhc3M9InN0NCIvPjxwYXRoIGQ9Ik0zNS4yIDI3LjlINC44YTEgMSAwIDAgMS0xLTFWMTIuMWMwLS42LjUtMSAxLTFoMzAuNWMuNSAwIDEgLjQgMSAxVjI3YTEgMSAwIDAgMS0xLjEuOXoiIGNsYXNzPSJzdDQiLz48L2c+PC9zdmc+'; /** * Length of the buffer to store key presses for the "when keys pressed in order" hat diff --git a/src/extensions/scratch3_microbit/index.js b/src/extensions/scratch3_microbit/index.js index fbc7a903f30..1d1ddc3925b 100644 --- a/src/extensions/scratch3_microbit/index.js +++ b/src/extensions/scratch3_microbit/index.js @@ -11,7 +11,7 @@ const Base64Util = require('../../util/base64-util'); * @type {string} */ // eslint-disable-next-line max-len -const blockIconURI = 'data:image/png;base64,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'; +const blockIconURI = 'data:image/png;base64,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'; /** * Enum for micro:bit BLE command protocol. diff --git a/src/extensions/scratch3_music/index.js b/src/extensions/scratch3_music/index.js index 7aea640d8b7..5a4b226f4c5 100644 --- a/src/extensions/scratch3_music/index.js +++ b/src/extensions/scratch3_music/index.js @@ -22,14 +22,14 @@ try { * @type {string} */ // eslint-disable-next-line max-len -const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PHRpdGxlPm11c2ljLWJsb2NrLWljb248L3RpdGxlPjxkZWZzPjxwYXRoIGQ9Ik0zMi4xOCAyNS44NzRDMzIuNjM2IDI4LjE1NyAzMC41MTIgMzAgMjcuNDMzIDMwYy0zLjA3IDAtNS45MjMtMS44NDMtNi4zNzItNC4xMjYtLjQ1OC0yLjI4NSAxLjY2NS00LjEzNiA0Ljc0My00LjEzNi42NDcgMCAxLjI4My4wODQgMS44OS4yMzQuMzM4LjA4Ni42MzcuMTguOTM4LjMwMi44Ny0uMDItLjEwNC0yLjI5NC0xLjgzNS0xMi4yMy0yLjEzNC0xMi4zMDIgMy4wNi0xLjg3IDguNzY4LTIuNzUyIDUuNzA4LS44ODUuMDc2IDQuODItMy42NSAzLjg0NC0zLjcyNC0uOTg3LTQuNjUtNy4xNTMuMjYzIDE0LjczOHptLTE2Ljk5OCA1Ljk5QzE1LjYzIDM0LjE0OCAxMy41MDcgMzYgMTAuNDQgMzZjLTMuMDcgMC01LjkyMi0xLjg1Mi02LjM4LTQuMTM2LS40NDgtMi4yODQgMS42NzQtNC4xMzUgNC43NS00LjEzNSAxLjAwMyAwIDEuOTc1LjE5NiAyLjg1NS41NDMuODIyLS4wNTUtLjE1LTIuMzc3LTEuODYyLTEyLjIyOC0yLjEzMy0xMi4zMDMgMy4wNi0xLjg3IDguNzY0LTIuNzUzIDUuNzA2LS44OTQuMDc2IDQuODItMy42NDggMy44MzQtMy43MjQtLjk4Ny00LjY1LTcuMTUyLjI2MiAxNC43Mzh6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjx1c2UgZmlsbD0iI0ZGRiIgeGxpbms6aHJlZj0iI2EiLz48cGF0aCBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZT0iIzAwMCIgZD0iTTI4LjQ1NiAyMS42NzVjLS4wMS0uMzEyLS4wODctLjgyNS0uMjU2LTEuNzAyLS4wOTYtLjQ5NS0uNjEyLTMuMDIyLS43NTMtMy43My0uMzk1LTEuOTgtLjc2LTMuOTItMS4xNDItNi4xMTMtLjczMi00LjIyMy0uNjkzLTYuMDUuMzQ0LTYuNTI3LjUtLjIzIDEuMDYtLjA4IDEuODQuMzUuNDE0LjIyNyAyLjE4MiAxLjM2NSAyLjA3IDEuMjk2IDEuOTk0IDEuMjQyIDMuNDY0IDEuNzc0IDQuOTMgMS41NDggMS41MjYtLjIzNyAyLjUwNC0uMDYgMi44NzYuNjE4LjM0OC42MzUuMDE1IDEuNDE2LS43MyAyLjE4LTEuNDcyIDEuNTE2LTMuOTc1IDIuNTE0LTUuODQ4IDIuMDIzLS44MjItLjIyLTEuMjM4LS40NjUtMi4zOC0xLjI2N2wtLjA5NS0uMDY2Yy4wNDcuNTkzLjI2NCAxLjc0LjcxNyAzLjgwMy4yOTQgMS4zMzYgMi4wOCA5LjE4NyAyLjYzNyAxMS42NzRsLjAwMi4wMTJjLjUyOCAyLjYzNy0xLjg3MyA0LjcyNC01LjIzNiA0LjcyNC0zLjI5IDAtNi4zNjMtMS45ODgtNi44NjItNC41MjgtLjUzLTIuNjQgMS44NzMtNC43MzQgNS4yMzMtNC43MzQuNjcyIDAgMS4zNDcuMDg1IDIuMDE0LjI1LjIyNy4wNTcuNDM2LjExOC42MzYuMTg3em0tMTYuOTk2IDUuOTljLS4wMS0uMzE4LS4wOS0uODM4LS4yNjYtMS43MzctLjA5LS40Ni0uNTk1LTIuOTM3LS43NTMtMy43MjctLjM5LTEuOTYtLjc1LTMuODktMS4xMy02LjA3LS43MzItNC4yMjMtLjY5Mi02LjA1LjM0NC02LjUyNi41MDItLjIzIDEuMDYtLjA4MiAxLjg0LjM1LjQxNS4yMjcgMi4xODIgMS4zNjQgMi4wNyAxLjI5NSAxLjk5MyAxLjI0MiAzLjQ2MiAxLjc3NCA0LjkyNiAxLjU0OCAxLjUyNS0uMjQgMi41MDQtLjA2NCAyLjg3Ni42MTQuMzQ4LjYzNS4wMTUgMS40MTUtLjcyOCAyLjE4LTEuNDc0IDEuNTE3LTMuOTc3IDIuNTEzLTUuODQ3IDIuMDE3LS44Mi0uMjItMS4yMzYtLjQ2NC0yLjM3OC0xLjI2N2wtLjA5NS0uMDY1Yy4wNDcuNTkzLjI2NCAxLjc0LjcxNyAzLjgwMi4yOTQgMS4zMzcgMi4wNzggOS4xOSAyLjYzNiAxMS42NzVsLjAwMy4wMTNjLjUxNyAyLjYzOC0xLjg4NCA0LjczMi01LjIzNCA0LjczMi0zLjI4NyAwLTYuMzYtMS45OTMtNi44Ny00LjU0LS41Mi0yLjY0IDEuODg0LTQuNzMgNS4yNC00LjczLjkwNSAwIDEuODAzLjE1IDIuNjUuNDM2eiIvPjwvZz48L3N2Zz4='; +const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHRpdGxlPm11c2ljLWJsb2NrLWljb248L3RpdGxlPjxkZWZzPjxwYXRoIGlkPSJhIiBkPSJNMzIuMTggMjUuODc0QzMyLjYzNiAyOC4xNTcgMzAuNTEyIDMwIDI3LjQzMyAzMGMtMy4wNyAwLTUuOTIzLTEuODQzLTYuMzcyLTQuMTI2LS40NTgtMi4yODUgMS42NjUtNC4xMzYgNC43NDMtNC4xMzZhOCA4IDAgMCAxIDEuODkuMjM0Yy4zMzguMDg2LjYzNy4xOC45MzguMzAyLjg3LS4wMi0uMTA0LTIuMjk0LTEuODM1LTEyLjIzLTIuMTM0LTEyLjMwMiAzLjA2LTEuODcgOC43NjgtMi43NTIgNS43MDgtLjg4NS4wNzYgNC44Mi0zLjY1IDMuODQ0LTMuNzI0LS45ODctNC42NS03LjE1My4yNjMgMTQuNzM4em0tMTYuOTk4IDUuOTlDMTUuNjMgMzQuMTQ4IDEzLjUwNyAzNiAxMC40NCAzNmMtMy4wNyAwLTUuOTIyLTEuODUyLTYuMzgtNC4xMzYtLjQ0OC0yLjI4NCAxLjY3NC00LjEzNSA0Ljc1LTQuMTM1IDEuMDAzIDAgMS45NzUuMTk2IDIuODU1LjU0My44MjItLjA1NS0uMTUtMi4zNzctMS44NjItMTIuMjI4LTIuMTMzLTEyLjMwMyAzLjA2LTEuODcgOC43NjQtMi43NTMgNS43MDYtLjg5NC4wNzYgNC44Mi0zLjY0OCAzLjgzNHMtNC42NS03LjE1Mi4yNjIgMTQuNzM4eiIvPjwvZGVmcz48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjx1c2UgeGxpbms6aHJlZj0iI2EiIGZpbGw9IiNmZmYiLz48cGF0aCBzdHJva2U9IiMwMDAiIHN0cm9rZS1vcGFjaXR5PSIuMSIgZD0iTTI4LjQ1NiAyMS42NzVjLS4wMS0uMzEyLS4wODctLjgyNS0uMjU2LTEuNzAyLS4wOTYtLjQ5NS0uNjEyLTMuMDIyLS43NTMtMy43My0uMzk1LTEuOTgtLjc2LTMuOTItMS4xNDItNi4xMTMtLjczMi00LjIyMy0uNjkzLTYuMDUuMzQ0LTYuNTI3LjUtLjIzIDEuMDYtLjA4IDEuODQuMzUuNDE0LjIyNyAyLjE4MiAxLjM2NSAyLjA3IDEuMjk2IDEuOTk0IDEuMjQyIDMuNDY0IDEuNzc0IDQuOTMgMS41NDggMS41MjYtLjIzNyAyLjUwNC0uMDYgMi44NzYuNjE4LjM0OC42MzUuMDE1IDEuNDE2LS43MyAyLjE4LTEuNDcyIDEuNTE2LTMuOTc1IDIuNTE0LTUuODQ4IDIuMDIzLS44MjItLjIyLTEuMjM4LS40NjUtMi4zOC0xLjI2N2wtLjA5NS0uMDY2Yy4wNDcuNTkzLjI2NCAxLjc0LjcxNyAzLjgwMy4yOTQgMS4zMzYgMi4wOCA5LjE4NyAyLjYzNyAxMS42NzRsLjAwMi4wMTJjLjUyOCAyLjYzNy0xLjg3MyA0LjcyNC01LjIzNiA0LjcyNC0zLjI5IDAtNi4zNjMtMS45ODgtNi44NjItNC41MjgtLjUzLTIuNjQgMS44NzMtNC43MzQgNS4yMzMtNC43MzRhOC40IDguNCAwIDAgMSAyLjY1LjQzN3ptLTE2Ljk5NiA1Ljk5Yy0uMDEtLjMxOC0uMDktLjgzOC0uMjY2LTEuNzM3LS4wOS0uNDYtLjU5NS0yLjkzNy0uNzUzLTMuNzI3LS4zOS0xLjk2LS43NS0zLjg5LTEuMTMtNi4wNy0uNzMyLTQuMjIzLS42OTItNi4wNS4zNDQtNi41MjYuNTAyLS4yMyAxLjA2LS4wODIgMS44NC4zNS40MTUuMjI3IDIuMTgyIDEuMzY0IDIuMDcgMS4yOTUgMS45OTMgMS4yNDIgMy40NjIgMS43NzQgNC45MjYgMS41NDggMS41MjUtLjI0IDIuNTA0LS4wNjQgMi44NzYuNjE0LjM0OC42MzUuMDE1IDEuNDE1LS43MjggMi4xOC0xLjQ3NCAxLjUxNy0zLjk3NyAyLjUxMy01Ljg0NyAyLjAxNy0uODItLjIyLTEuMjM2LS40NjQtMi4zNzgtMS4yNjdsLS4wOTUtLjA2NWMuMDQ3LjU5My4yNjQgMS43NC43MTcgMy44MDIuMjk0IDEuMzM3IDIuMDc4IDkuMTkgMi42MzYgMTEuNjc1bC4wMDMuMDEzYy41MTcgMi42MzgtMS44ODQgNC43MzItNS4yMzQgNC43MzItMy4yODcgMC02LjM2LTEuOTkzLTYuODctNC41NC0uNTItMi42NCAxLjg4NC00LjczIDUuMjQtNC43My45MDUgMCAxLjgwMy4xNSAyLjY1LjQzNnoiLz48L2c+PC9zdmc+'; /** * Icon svg to be displayed in the category menu, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len -const menuIconURI = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE2LjA5IDEyLjkzN2MuMjI4IDEuMTQxLS44MzMgMi4wNjMtMi4zNzMgMi4wNjMtMS41MzUgMC0yLjk2Mi0uOTIyLTMuMTg2LTIuMDYzLS4yMy0xLjE0Mi44MzMtMi4wNjggMi4zNzItMi4wNjguMzIzIDAgLjY0MS4wNDIuOTQ1LjExN2EzLjUgMy41IDAgMCAxIC40NjguMTUxYy40MzUtLjAxLS4wNTItMS4xNDctLjkxNy02LjExNC0xLjA2Ny02LjE1MiAxLjUzLS45MzUgNC4zODQtMS4zNzcgMi44NTQtLjQ0Mi4wMzggMi40MS0xLjgyNSAxLjkyMi0xLjg2Mi0uNDkzLTIuMzI1LTMuNTc3LjEzMiA3LjM3ek03LjQ2IDguNTYzYy0xLjg2Mi0uNDkzLTIuMzI1LTMuNTc2LjEzIDcuMzdDNy44MTYgMTcuMDczIDYuNzU0IDE4IDUuMjIgMThjLTEuNTM1IDAtMi45NjEtLjkyNi0zLjE5LTIuMDY4LS4yMjQtMS4xNDIuODM3LTIuMDY3IDIuMzc1LTIuMDY3LjUwMSAwIC45ODcuMDk4IDEuNDI3LjI3Mi40MTItLjAyOC0uMDc0LTEuMTg5LS45My02LjExNEMzLjgzNCAxLjg3IDYuNDMgNy4wODcgOS4yODIgNi42NDZjMi44NTQtLjQ0Ny4wMzggMi40MS0xLjgyMyAxLjkxN3oiIGZpbGw9IiM1NzVFNzUiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg=='; +const menuIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCI+PHBhdGggZmlsbD0iIzU3NWU3NSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTYuMDkgMTIuOTM3Yy4yMjggMS4xNDEtLjgzMyAyLjA2My0yLjM3MyAyLjA2My0xLjUzNSAwLTIuOTYyLS45MjItMy4xODYtMi4wNjMtLjIzLTEuMTQyLjgzMy0yLjA2OCAyLjM3Mi0yLjA2OC4zMjMgMCAuNjQxLjA0Mi45NDUuMTE3YTMuNSAzLjUgMCAwIDEgLjQ2OC4xNTFjLjQzNS0uMDEtLjA1Mi0xLjE0Ny0uOTE3LTYuMTE0LTEuMDY3LTYuMTUyIDEuNTMtLjkzNSA0LjM4NC0xLjM3N3MuMDM4IDIuNDEtMS44MjUgMS45MjJjLTEuODYyLS40OTMtMi4zMjUtMy41NzcuMTMyIDcuMzd6TTcuNDYgOC41NjNjLTEuODYyLS40OTMtMi4zMjUtMy41NzYuMTMgNy4zN0M3LjgxNiAxNy4wNzMgNi43NTQgMTggNS4yMiAxOHMtMi45NjEtLjkyNi0zLjE5LTIuMDY4Yy0uMjI0LTEuMTQyLjgzNy0yLjA2NyAyLjM3NS0yLjA2Ny41MDEgMCAuOTg3LjA5OCAxLjQyNy4yNzIuNDEyLS4wMjgtLjA3NC0xLjE4OS0uOTMtNi4xMTQtMS4wNjgtNi4xNTMgMS41MjgtLjkzNiA0LjM4LTEuMzc3IDIuODU0LS40NDcuMDM4IDIuNDEtMS44MjMgMS45MTd6Ii8+PC9zdmc+'; /** * Class for the music-related blocks in Scratch 3.0 diff --git a/src/extensions/scratch3_pen/index.js b/src/extensions/scratch3_pen/index.js index 99ebfa99acb..496c7a5b2ac 100644 --- a/src/extensions/scratch3_pen/index.js +++ b/src/extensions/scratch3_pen/index.js @@ -14,7 +14,7 @@ const StageLayering = require('../../engine/stage-layering'); * @type {string} */ // eslint-disable-next-line max-len -const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+cGVuLWljb248L3RpdGxlPjxnIHN0cm9rZT0iIzU3NUU3NSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik04Ljc1MyAzNC42MDJsLTQuMjUgMS43OCAxLjc4My00LjIzN2MxLjIxOC0yLjg5MiAyLjkwNy01LjQyMyA1LjAzLTcuNTM4TDMxLjA2NiA0LjkzYy44NDYtLjg0MiAyLjY1LS40MSA0LjAzMi45NjcgMS4zOCAxLjM3NSAxLjgxNiAzLjE3My45NyA0LjAxNUwxNi4zMTggMjkuNTljLTIuMTIzIDIuMTE2LTQuNjY0IDMuOC03LjU2NSA1LjAxMiIgZmlsbD0iI0ZGRiIvPjxwYXRoIGQ9Ik0yOS40MSA2LjExcy00LjQ1LTIuMzc4LTguMjAyIDUuNzcyYy0xLjczNCAzLjc2Ni00LjM1IDEuNTQ2LTQuMzUgMS41NDYiLz48cGF0aCBkPSJNMzYuNDIgOC44MjVjMCAuNDYzLS4xNC44NzMtLjQzMiAxLjE2NGwtOS4zMzUgOS4zYy4yODItLjI5LjQxLS42NjguNDEtMS4xMiAwLS44NzQtLjUwNy0xLjk2My0xLjQwNi0yLjg2OC0xLjM2Mi0xLjM1OC0zLjE0Ny0xLjgtNC4wMDItLjk5TDMwLjk5IDUuMDFjLjg0NC0uODQgMi42NS0uNDEgNC4wMzUuOTYuODk4LjkwNCAxLjM5NiAxLjk4MiAxLjM5NiAyLjg1NU0xMC41MTUgMzMuNzc0Yy0uNTczLjMwMi0xLjE1Ny41Ny0xLjc2NC44M0w0LjUgMzYuMzgybDEuNzg2LTQuMjM1Yy4yNTgtLjYwNC41My0xLjE4Ni44MzMtMS43NTcuNjkuMTgzIDEuNDQ4LjYyNSAyLjEwOCAxLjI4Mi42Ni42NTggMS4xMDIgMS40MTIgMS4yODcgMi4xMDIiIGZpbGw9IiM0Qzk3RkYiLz48cGF0aCBkPSJNMzYuNDk4IDguNzQ4YzAgLjQ2NC0uMTQuODc0LS40MzMgMS4xNjVsLTE5Ljc0MiAxOS42OGMtMi4xMyAyLjExLTQuNjczIDMuNzkzLTcuNTcyIDUuMDFMNC41IDM2LjM4bC45NzQtMi4zMTYgMS45MjUtLjgwOGMyLjg5OC0xLjIxOCA1LjQ0LTIuOSA3LjU3LTUuMDFsMTkuNzQzLTE5LjY4Yy4yOTItLjI5Mi40MzItLjcwMi40MzItMS4xNjUgMC0uNjQ2LS4yNy0xLjQtLjc4LTIuMTIyLjI1LjE3Mi41LjM3Ny43MzcuNjE0Ljg5OC45MDUgMS4zOTYgMS45ODMgMS4zOTYgMi44NTYiIGZpbGw9IiM1NzVFNzUiIG9wYWNpdHk9Ii4xNSIvPjxwYXRoIGQ9Ik0xOC40NSAxMi44M2MwIC41LS40MDQuOTA1LS45MDQuOTA1cy0uOTA1LS40MDUtLjkwNS0uOTA0YzAtLjUuNDA3LS45MDMuOTA2LS45MDMuNSAwIC45MDQuNDA0LjkwNC45MDR6IiBmaWxsPSIjNTc1RTc1Ii8+PC9nPjwvc3ZnPg=='; +const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIj48dGl0bGU+cGVuLWljb248L3RpdGxlPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjNTc1ZTc1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Im04Ljc1MyAzNC42MDItNC4yNSAxLjc4IDEuNzgzLTQuMjM3YzEuMjE4LTIuODkyIDIuOTA3LTUuNDIzIDUuMDMtNy41MzhMMzEuMDY2IDQuOTNjLjg0Ni0uODQyIDIuNjUtLjQxIDQuMDMyLjk2NyAxLjM4IDEuMzc1IDEuODE2IDMuMTczLjk3IDQuMDE1TDE2LjMxOCAyOS41OWMtMi4xMjMgMi4xMTYtNC42NjQgMy44LTcuNTY1IDUuMDEyIi8+PHBhdGggZD0iTTI5LjQxIDYuMTFzLTQuNDUtMi4zNzgtOC4yMDIgNS43NzJjLTEuNzM0IDMuNzY2LTQuMzUgMS41NDYtNC4zNSAxLjU0NiIvPjxwYXRoIGZpbGw9IiM0Yzk3ZmYiIGQ9Ik0zNi40MiA4LjgyNWMwIC40NjMtLjE0Ljg3My0uNDMyIDEuMTY0bC05LjMzNSA5LjNjLjI4Mi0uMjkuNDEtLjY2OC40MS0xLjEyIDAtLjg3NC0uNTA3LTEuOTYzLTEuNDA2LTIuODY4LTEuMzYyLTEuMzU4LTMuMTQ3LTEuOC00LjAwMi0uOTlMMzAuOTkgNS4wMWMuODQ0LS44NCAyLjY1LS40MSA0LjAzNS45Ni44OTguOTA0IDEuMzk2IDEuOTgyIDEuMzk2IDIuODU1TTEwLjUxNSAzMy43NzRhMjQgMjQgMCAwIDEtMS43NjQuODNMNC41IDM2LjM4MmwxLjc4Ni00LjIzNWMuMjU4LS42MDQuNTMtMS4xODYuODMzLTEuNzU3LjY5LjE4MyAxLjQ0OC42MjUgMi4xMDggMS4yODIuNjYuNjU4IDEuMTAyIDEuNDEyIDEuMjg3IDIuMTAyIi8+PHBhdGggZmlsbD0iIzU3NWU3NSIgZD0iTTM2LjQ5OCA4Ljc0OGMwIC40NjQtLjE0Ljg3NC0uNDMzIDEuMTY1bC0xOS43NDIgMTkuNjhjLTIuMTMgMi4xMS00LjY3MyAzLjc5My03LjU3MiA1LjAxTDQuNSAzNi4zOGwuOTc0LTIuMzE2IDEuOTI1LS44MDhjMi44OTgtMS4yMTggNS40NC0yLjkgNy41Ny01LjAxbDE5Ljc0My0xOS42OGMuMjkyLS4yOTIuNDMyLS43MDIuNDMyLTEuMTY1IDAtLjY0Ni0uMjctMS40LS43OC0yLjEyMi4yNS4xNzIuNS4zNzcuNzM3LjYxNC44OTguOTA1IDEuMzk2IDEuOTgzIDEuMzk2IDIuODU2IiBvcGFjaXR5PSIuMTUiLz48cGF0aCBmaWxsPSIjNTc1ZTc1IiBkPSJNMTguNDUgMTIuODNhLjkwNC45MDQgMCAxIDEtLjkwMy0uOTAyYy41IDAgLjkwNC40MDQuOTA0LjkwNHoiLz48L2c+PC9zdmc+'; /** * Enum for pen color parameter values. diff --git a/src/extensions/scratch3_speech2text/index.js b/src/extensions/scratch3_speech2text/index.js index b42e7f8c1fa..79b5ac1e012 100644 --- a/src/extensions/scratch3_speech2text/index.js +++ b/src/extensions/scratch3_speech2text/index.js @@ -11,7 +11,7 @@ const DiffMatchPatch = require('diff-match-patch'); * @type {string} */ // eslint-disable-next-line max-len -const iconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSIjRkZGRkZGIj48cGF0aCBkPSJNMTIgMTRjMS42NiAwIDIuOTktMS4zNCAyLjk5LTNMMTUgNWMwLTEuNjYtMS4zNC0zLTMtM1M5IDMuMzQgOSA1djZjMCAxLjY2IDEuMzQgMyAzIDN6bTUuMy0zYzAgMy0yLjU0IDUuMS01LjMgNS4xUzYuNyAxNCA2LjcgMTFINWMwIDMuNDEgMi43MiA2LjIzIDYgNi43MlYyMWgydi0zLjI4YzMuMjgtLjQ4IDYtMy4zIDYtNi43MmgtMS43eiIvPjxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz48L3N2Zz4K'; +const iconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0iI2ZmZiIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTIgMTRjMS42NiAwIDIuOTktMS4zNCAyLjk5LTNMMTUgNWMwLTEuNjYtMS4zNC0zLTMtM1M5IDMuMzQgOSA1djZjMCAxLjY2IDEuMzQgMyAzIDNtNS4zLTNjMCAzLTIuNTQgNS4xLTUuMyA1LjFTNi43IDE0IDYuNyAxMUg1YzAgMy40MSAyLjcyIDYuMjMgNiA2LjcyVjIxaDJ2LTMuMjhjMy4yOC0uNDggNi0zLjMgNi02LjcyeiIvPjxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0wIDBoMjR2MjRIMHoiLz48L3N2Zz4='; /** @@ -19,7 +19,7 @@ const iconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vc * @type {string} */ // eslint-disable-next-line max-len -const menuIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzc1NzU3NSI+CiAgICA8cGF0aCBkPSJNMTIgMTRjMS42NiAwIDIuOTktMS4zNCAyLjk5LTNMMTUgNWMwLTEuNjYtMS4zNC0zLTMtM1M5IDMuMzQgOSA1djZjMCAxLjY2IDEuMzQgMyAzIDN6bTUuMy0zYzAgMy0yLjU0IDUuMS01LjMgNS4xUzYuNyAxNCA2LjcgMTFINWMwIDMuNDEgMi43MiA2LjIzIDYgNi43MlYyMWgydi0zLjI4YzMuMjgtLjQ4IDYtMy4zIDYtNi43MmgtMS43eiIvPgogICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPgo8L3N2Zz4K'; +const menuIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0iIzc1NzU3NSIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTIgMTRjMS42NiAwIDIuOTktMS4zNCAyLjk5LTNMMTUgNWMwLTEuNjYtMS4zNC0zLTMtM1M5IDMuMzQgOSA1djZjMCAxLjY2IDEuMzQgMyAzIDNtNS4zLTNjMCAzLTIuNTQgNS4xLTUuMyA1LjFTNi43IDE0IDYuNyAxMUg1YzAgMy40MSAyLjcyIDYuMjMgNiA2LjcyVjIxaDJ2LTMuMjhjMy4yOC0uNDggNi0zLjMgNi02LjcyeiIvPjxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0wIDBoMjR2MjRIMHoiLz48L3N2Zz4='; /** diff --git a/src/extensions/scratch3_text2speech/index.js b/src/extensions/scratch3_text2speech/index.js index b48cf0dbb2c..57bce01085b 100644 --- a/src/extensions/scratch3_text2speech/index.js +++ b/src/extensions/scratch3_text2speech/index.js @@ -14,14 +14,14 @@ const {fetchWithTimeout} = require('../../util/fetch-with-timeout'); * @type {string} */ // eslint-disable-next-line max-len -const menuIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjBweCIgaGVpZ2h0PSIyMHB4IiB2aWV3Qm94PSIwIDAgMjAgMjAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjIgKDY3MTQ1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5FeHRlbnNpb25zL1NvZnR3YXJlL1RleHQtdG8tU3BlZWNoLU1lbnU8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZyBpZD0iRXh0ZW5zaW9ucy9Tb2Z0d2FyZS9UZXh0LXRvLVNwZWVjaC1NZW51IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0idGV4dDJzcGVlY2giIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIuMDAwMDAwLCAyLjAwMDAwMCkiIGZpbGwtcnVsZT0ibm9uemVybyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik01Ljc1LDguODM0NjcxNzMgQzUuNzUsOC4zMjY5NjM0NCA1LjAwMzAwNzI3LDguMDQyMjEzNzEgNC41NTYyODAxMiw4LjQ0NDE0OTk5IEwzLjIwNjI4MDEyLDkuNTI1MzU3MDIgQzIuNjk2NzMzNzgsOS45MzM0NDk2OCAyLjAzNzQ4Njc1LDEwLjE2NTg3ODggMS4zNSwxMC4xNjU4Nzg4IEwxLjE1LDEwLjE2NTg3ODggQzAuNjMyNTk2MTY1LDEwLjE2NTg3ODggMC4yNSwxMC41MTA2MDAyIDAuMjUsMTAuOTUyMDM1NSBMMC4yNSwxMy4wNjkzOTkzIEMwLjI1LDEzLjUxMDgzNDYgMC42MzI1OTYxNjUsMTMuODU1NTU2IDEuMTUsMTMuODU1NTU2IEwxLjM1LDEzLjg1NTU1NiBDMi4wNzg3Nzg0MSwxMy44NTU1NTYgMi43MjY4NjE2MSwxNC4wNjY3NjM2IDMuMjU5ODYwNDksMTQuNDk5IEw0LjU1OTIwMTQ3LDE1LjU3OTY2MDggQzUuMDEzMDkyNzYsMTUuOTU0NTM5NiA1Ljc1LDE1LjY3MzYzNDQgNS43NSwxNS4xNDE3MTI4IEw1Ljc1LDguODM0NjcxNzMgWiIgaWQ9InNwZWFrZXIiIHN0cm9rZS1vcGFjaXR5PSIwLjE1IiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iMC41IiBmaWxsPSIjNEQ0RDREIj48L3BhdGg+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMC43MDQ4MzEzLDggQzkuNzkwNjc0NjgsOS4xMzExNDg0NyA4LjMwNjYxODQsOS43MTQyODU3MSA3LjgzMzMzMzMzLDkuNzE0Mjg1NzEgQzcuODMzMzMzMzMsOS43MTQyODU3MSA3LjUsOS43MTQyODU3MSA3LjUsOS4zODA5NTIzOCBDNy41LDkuMDg1MjI2ODQgOC4wNjIyMDE2OCw4LjkwMTk0MTY0IDguMTg5MDYwNjcsNy41Njc1NDA1OCBDNi44ODk5Njk5MSw2LjkwNjc5MDA1IDYsNS41NTczMjY4MyA2LDQgQzYsMS43OTA4NjEgNy43OTA4NjEsNC4wNTgxMjI1MWUtMTYgMTAsMCBMMTIsMCBDMTQuMjA5MTM5LC00LjA1ODEyMjUxZS0xNiAxNiwxLjc5MDg2MSAxNiw0IEMxNiw2LjIwOTEzOSAxNC4yMDkxMzksOCAxMiw4IEwxMC43MDQ4MzEzLDggWiIgaWQ9InNwZWVjaCIgZmlsbD0iIzBFQkQ4QyI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+'; +const menuIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48dGl0bGU+RXh0ZW5zaW9ucy9Tb2Z0d2FyZS9UZXh0LXRvLVNwZWVjaC1NZW51PC90aXRsZT48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9Im5vbnplcm8iPjxwYXRoIGZpbGw9IiM0ZDRkNGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLW9wYWNpdHk9Ii4xNSIgc3Ryb2tlLXdpZHRoPSIuNSIgZD0iTTcuNzUgMTAuODM1YzAtLjUwOC0uNzQ3LS43OTMtMS4xOTQtLjM5bC0xLjM1IDEuMDhjLS41MS40MDgtMS4xNjkuNjQtMS44NTYuNjRoLS4yYy0uNTE3IDAtLjkuMzQ2LS45Ljc4N3YyLjExN2MwIC40NDIuMzgzLjc4Ny45Ljc4N2guMmMuNzI5IDAgMS4zNzcuMjEgMS45MS42NDNsMS4zIDEuMDhjLjQ1My4zNzYgMS4xOS4wOTUgMS4xOS0uNDM3eiIvPjxwYXRoIGZpbGw9IiMwZWJkOGMiIGQ9Ik0xMi43MDUgMTBjLS45MTQgMS4xMzEtMi4zOTggMS43MTQtMi44NzIgMS43MTQgMCAwLS4zMzMgMC0uMzMzLS4zMzMgMC0uMjk2LjU2Mi0uNDguNjktMS44MTNBNCA0IDAgMCAxIDEyIDJoMmE0IDQgMCAxIDEgMCA4eiIvPjwvZz48L3N2Zz4='; /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len -const blockIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNDBweCIgaGVpZ2h0PSI0MHB4IiB2aWV3Qm94PSIwIDAgNDAgNDAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjIgKDY3MTQ1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5FeHRlbnNpb25zL1NvZnR3YXJlL1RleHQtdG8tU3BlZWNoLUJsb2NrPC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGcgaWQ9IkV4dGVuc2lvbnMvU29mdHdhcmUvVGV4dC10by1TcGVlY2gtQmxvY2siIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZS1vcGFjaXR5PSIwLjE1Ij4KICAgICAgICA8ZyBpZD0idGV4dDJzcGVlY2giIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQuMDAwMDAwLCA0LjAwMDAwMCkiIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSIjMDAwMDAwIj4KICAgICAgICAgICAgPHBhdGggZD0iTTExLjUsMTcuNjY5MzQzNSBDMTEuNSwxNi42NTM5MjY5IDEwLjAwNjAxNDUsMTYuMDg0NDI3NCA5LjExMjU2MDI0LDE2Ljg4ODMgTDYuNDEyNTYwMjQsMTkuMDUwNzE0IEM1LjM5MzQ2NzU1LDE5Ljg2Njg5OTQgNC4wNzQ5NzM1MSwyMC4zMzE3NTc1IDIuNywyMC4zMzE3NTc1IEwyLjMsMjAuMzMxNzU3NSBDMS4yNjUxOTIzMywyMC4zMzE3NTc1IDAuNSwyMS4wMjEyMDAzIDAuNSwyMS45MDQwNzEgTDAuNSwyNi4xMzg3OTg2IEMwLjUsMjcuMDIxNjY5MyAxLjI2NTE5MjMzLDI3LjcxMTExMiAyLjMsMjcuNzExMTEyIEwyLjcsMjcuNzExMTEyIEM0LjE1NzU1NjgyLDI3LjcxMTExMiA1LjQ1MzcyMzIyLDI4LjEzMzUyNzEgNi41MTk3MjA5OCwyOC45OTggTDkuMTE4NDAyOTMsMzEuMTU5MzIxNiBDMTAuMDI2MTg1NSwzMS45MDkwNzkzIDExLjUsMzEuMzQ3MjY4OSAxMS41LDMwLjI4MzQyNTUgTDExLjUsMTcuNjY5MzQzNSBaIiBpZD0ic3BlYWtlciIgZmlsbD0iIzRENEQ0RCI+PC9wYXRoPgogICAgICAgICAgICA8cGF0aCBkPSJNMjEuNjQzNjA2NiwxNi41IEMxOS45NzcwMDk5LDE4LjQzNzAyMzQgMTcuMTA1MDI3NSwxOS45Mjg1NzE0IDE1LjY2NjY2NjcsMTkuOTI4NTcxNCBDMTUuNTEyNjM5NywxOS45Mjg1NzE0IDE1LjMxNjYyOTIsMTkuODk1OTAzIDE1LjEwOTcyNjUsMTkuNzkyNDUxNyBDMTQuNzM3NjAzOSwxOS42MDYzOTA0IDE0LjUsMTkuMjQ5OTg0NiAxNC41LDE4Ljc2MTkwNDggQzE0LjUsMTguNjU2ODA0MSAxNC41MTcwNTU1LDE4LjU1NDUwNzYgMTQuNTQ5NDQ2NywxOC40NTQwODQ0IEMxNC42MjU3NTQ1LDE4LjIxNzUwNjMgMTUuMTczNTcyMSwxNy40Njc1MzEgMTUuMjc3MjA3MSwxNy4yODA5ODgxIEMxNS41NDYzNTI2LDE2Ljc5NjUyNjEgMTUuNzM5MDI1LDE2LjIwNjM1NjEgMTUuODQzMjg5MSwxNS40MTYwMDM0IEMxMy4xODk3MDA1LDEzLjkyNjgzNjkgMTEuNSwxMS4xMTM5NjY4IDExLjUsOCBDMTEuNSwzLjMwNTU3OTYzIDE1LjMwNTU3OTYsLTAuNSAyMCwtMC41IEwyNCwtMC41IEMyOC42OTQ0MjA0LC0wLjUgMzIuNSwzLjMwNTU3OTYzIDMyLjUsOCBDMzIuNSwxMi42OTQ0MjA0IDI4LjY5NDQyMDQsMTYuNSAyNCwxNi41IEwyMS42NDM2MDY2LDE2LjUgWiIgaWQ9InNwZWVjaCIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+'; +const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIj48dGl0bGU+RXh0ZW5zaW9ucy9Tb2Z0d2FyZS9UZXh0LXRvLVNwZWVjaC1CbG9jazwvdGl0bGU+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJub256ZXJvIiBzdHJva2U9IiMwMDAiIHN0cm9rZS1vcGFjaXR5PSIuMTUiPjxwYXRoIGZpbGw9IiM0ZDRkNGQiIGQ9Ik0xNS41IDIxLjY3YzAtMS4wMTYtMS40OTQtMS41ODYtMi4zODctLjc4MmwtMi43IDIuMTYzQTUuOTYgNS45NiAwIDAgMSA2LjcgMjQuMzNoLS40Yy0xLjAzNSAwLTEuOC42OS0xLjggMS41NzN2NC4yMzVjMCAuODgzLjc2NSAxLjU3MiAxLjggMS41NzJoLjRjMS40NTggMCAyLjc1NC40MjMgMy44MiAxLjI4N2wyLjU5OCAyLjE2MWMuOTA4Ljc1IDIuMzgyLjE4OCAyLjM4Mi0uODc2eiIvPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0yNS42NDQgMjAuNWMtMS42NjcgMS45MzctNC41MzkgMy40MjktNS45NzcgMy40MjlhMS4yNSAxLjI1IDAgMCAxLS41NTctLjEzN2MtLjM3Mi0uMTg2LS42MS0uNTQyLS42MS0xLjAzcTAtLjE1Ny4wNS0uMzA4Yy4wNzYtLjIzNi42MjQtLjk4Ni43MjctMS4xNzMuMjctLjQ4NC40NjItMS4wNzUuNTY2LTEuODY1QTguNSA4LjUgMCAwIDEgMjQgMy41aDRhOC41IDguNSAwIDEgMSAwIDE3eiIvPjwvZz48L3N2Zz4='; /** * The url of the synthesis server. diff --git a/src/extensions/scratch3_translate/index.js b/src/extensions/scratch3_translate/index.js index f81f5890b94..3fe4e022a0c 100644 --- a/src/extensions/scratch3_translate/index.js +++ b/src/extensions/scratch3_translate/index.js @@ -11,14 +11,14 @@ const formatMessage = require('format-message'); * @type {string} */ // eslint-disable-next-line max-len -const menuIconURI = 'data:image/png;base64,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'; +const menuIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAACXBIWXMAABYlAAAWJQFJUiTwAAABXFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAOvYwAAACOjo6EhIQOvYx4eHicnJwOvYytra0OvYykpKSfn5/BwcEOvYy0tLSvr6+pqakOvYy1tbXExMQOvYy+vr66urrCwsIOvYzLy8vFxcXAwMC9vb3GxsYOvYzKysrHx8cOvYy9vb20tLTLy8sOvYzR0dHPz88OvYzU1NTS0tIOvYza2trX19fV1dUOvYze3t7c3Nz////9/f36+vr4+Pj0+P/19fXx8fHp8v/u7u7s7Ozq6+7d6//n5+fl5eXS5f/i4uLf4eXg4ODb29vH3v/Z2dnV19y82P/R0dG10/+x0f/KzNSgx/+bxP+rv9uVwf+Rv/+1uMKPvv+huNmIt/h/tP+gpLFsqf9rqf9lpf+Wmqhho/9fov9coP9an/9Znv9Ynf9VnP9Smv9Rmf9Nl/+BhpdJkPMOvYx2fI5rcoZhZ31XXnVRayw6AAAAOXRSTlMAAgUHCgwOEBMbHSAgMTBBQENFTlBSU1ZgZHBwcnOBgI6QkpOgoK2usLS3vMDJydDX1+Dk5OXw8vIZ3wVeAAACCklEQVR42tXU7XPSMBzA8SAoDjYEFcUxrIN1PoHMbaJpC7UFbOfDUKdOUFHLfM6MmP//zoQuCWm90ze+8PsCcsnnfnc0APhvWlipKa0s0M06xljPKa6wbRtwLsPeLgCgNzGtBGSZLc4k3crQgyyjWQkrNj/vtfnKrgBaehNjXcKaGPjtrRhZY67MRmp5ASGtvT8ajdAX+rI/G8tgGYcpcIBEAw5zoasrEHpP0QfP+4gGHuQQlJhrpiUM+4o8D32GUEAmpZPwGTr4hJ5IyMprwkkIJwi9gwLy4rB3gNCkZzh9n3btfFhxMRGBvTeUTdD3F77Tmcvx144r8CFC6Dlsv35lw0j25eQRrJps4PuXd+nbPRfGcs/xL08fih6YcWhWj+CxdQfyHvFF9/CwG3sCydU77myS4z7mh0NChhKKTjYMutG/eOYqP/xByPQ38IILoelXEuKZ7pDplOzEYdUy3capBBBwTIZjMo7DxetrxdT8LU1JEJCff77OPTJrLwbT2lkFBmS8uxuQIArTTYxL85CQLvtAREDpqJQ/NDVDwDqelaPLZTsO7WUOcZhGl6kNK+qsjRSHeY2yzTJgZRpuJ8xiyui4jQyQ6Ri30uEyVbgUdpNJ89ZpOk+WbWHczAKlzA2HSn8JKJVamNIryl5y1e9AK3otWZ3SOlBKLK3fvl8Ef1XqROJf/Xv/Ao6e1+rnxxl1AAAAAElFTkSuQmCC'; /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len -const blockIconURI = 'data:image/png;base64,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'; +const blockIconURI = 'data:image/png;base64,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'; /** * The url of the translate server. diff --git a/src/extensions/scratch3_video_sensing/index.js b/src/extensions/scratch3_video_sensing/index.js index 5f8380fe424..360b893ca3e 100644 --- a/src/extensions/scratch3_video_sensing/index.js +++ b/src/extensions/scratch3_video_sensing/index.js @@ -14,14 +14,14 @@ const VideoMotion = require('./library'); * @type {string} */ // eslint-disable-next-line max-len -const menuIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjBweCIgaGVpZ2h0PSIyMHB4IiB2aWV3Qm94PSIwIDAgMjAgMjAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjIgKDY3MTQ1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5FeHRlbnNpb25zL1NvZnR3YXJlL1ZpZGVvLVNlbnNpbmctTWVudTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJFeHRlbnNpb25zL1NvZnR3YXJlL1ZpZGVvLVNlbnNpbmctTWVudSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9InZpZGVvLW1vdGlvbiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDUuMDAwMDAwKSIgZmlsbC1ydWxlPSJub256ZXJvIj4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjMEVCRDhDIiBvcGFjaXR5PSIwLjI1IiBjeD0iMTYiIGN5PSI4IiByPSIyIj48L2NpcmNsZT4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjMEVCRDhDIiBvcGFjaXR5PSIwLjUiIGN4PSIxNiIgY3k9IjYiIHI9IjIiPjwvY2lyY2xlPgogICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsLUNvcHkiIGZpbGw9IiMwRUJEOEMiIG9wYWNpdHk9IjAuNzUiIGN4PSIxNiIgY3k9IjQiIHI9IjIiPjwvY2lyY2xlPgogICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsIiBmaWxsPSIjMEVCRDhDIiBjeD0iMTYiIGN5PSIyIiByPSIyIj48L2NpcmNsZT4KICAgICAgICAgICAgPHBhdGggZD0iTTExLjMzNTk3MzksMi4yMDk3ODgyNSBMOC4yNSw0LjIwOTk1NjQ5IEw4LjI1LDMuMDUgQzguMjUsMi4wNDQ4ODIyNyA3LjQ2ODU5MDMxLDEuMjUgNi41LDEuMjUgTDIuMDUsMS4yNSBDMS4wMzgwNzExOSwxLjI1IDAuMjUsMi4wMzgwNzExOSAwLjI1LDMuMDUgTDAuMjUsNyBDMC4yNSw3Ljk2MzY5OTM3IDEuMDQyMjQ5MTksOC43NTU5NDg1NiAyLjA1LDguOCBMNi41LDguOCBDNy40NTA4MzAwOSw4LjggOC4yNSw3Ljk3MzI3MjUgOC4yNSw3IEw4LjI1LDUuODU4NDUyNDEgTDguNjI4NjIzOTQsNi4wODU2MjY3NyBMMTEuNDI2Nzc2Nyw3Ljc3MzIyMzMgQzExLjQzNjg5NDMsNy43ODMzNDA5MSAxMS40NzU3NjU1LDcuOCAxMS41LDcuOCBDMTEuNjMzNDkzMiw3LjggMTEuNzUsNy42OTEyNjAzNCAxMS43NSw3LjU1IEwxMS43NSwyLjQgQzExLjc1LDIuNDE4MzgyNjkgMTEuNzIxOTAyOSwyLjM1MjgyMjgyIDExLjY4NTYyNjgsMi4yNzg2MjM5NCBDMTEuNjEyOTUyOCwyLjE1NzUwMDY5IDExLjQ3MDc5NjgsMi4xMjkwNjk1IDExLjMzNTk3MzksMi4yMDk3ODgyNSBaIiBpZD0idmlkZW9fMzdfIiBzdHJva2Utb3BhY2l0eT0iMC4xNSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjAuNSIgZmlsbD0iIzRENEQ0RCI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+'; +const menuIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48dGl0bGU+RXh0ZW5zaW9ucy9Tb2Z0d2FyZS9WaWRlby1TZW5zaW5nLU1lbnU8L3RpdGxlPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0ibm9uemVybyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCA1KSI+PGNpcmNsZSBjeD0iMTYiIGN5PSI4IiByPSIyIiBmaWxsPSIjMGViZDhjIiBvcGFjaXR5PSIuMjUiLz48Y2lyY2xlIGN4PSIxNiIgY3k9IjYiIHI9IjIiIGZpbGw9IiMwZWJkOGMiIG9wYWNpdHk9Ii41Ii8+PGNpcmNsZSBjeD0iMTYiIGN5PSI0IiByPSIyIiBmaWxsPSIjMGViZDhjIiBvcGFjaXR5PSIuNzUiLz48Y2lyY2xlIGN4PSIxNiIgY3k9IjIiIHI9IjIiIGZpbGw9IiMwZWJkOGMiLz48cGF0aCBmaWxsPSIjNGQ0ZDRkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS1vcGFjaXR5PSIuMTUiIHN0cm9rZS13aWR0aD0iLjUiIGQ9Im0xMS4zMzYgMi4yMS0zLjA4NiAyVjMuMDVjMC0xLjAwNS0uNzgxLTEuOC0xLjc1LTEuOEgyLjA1Yy0xLjAxMiAwLTEuOC43ODgtMS44IDEuOFY3YzAgLjk2NC43OTIgMS43NTYgMS44IDEuOEg2LjVjLjk1IDAgMS43NS0uODI3IDEuNzUtMS44VjUuODU4bC4zNzkuMjI4IDIuNzk4IDEuNjg3Yy4wMS4wMS4wNDkuMDI3LjA3My4wMjdhLjI1LjI1IDAgMCAwIC4yNS0uMjVWMi40YzAgLjAxOC0uMDI4LS4wNDctLjA2NC0uMTIxLS4wNzMtLjEyMS0uMjE1LS4xNS0uMzUtLjA3WiIvPjwvZz48L3N2Zz4='; /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len -const blockIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNDBweCIgaGVpZ2h0PSI0MHB4IiB2aWV3Qm94PSIwIDAgNDAgNDAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjIgKDY3MTQ1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5FeHRlbnNpb25zL1NvZnR3YXJlL1ZpZGVvLVNlbnNpbmctQmxvY2s8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZyBpZD0iRXh0ZW5zaW9ucy9Tb2Z0d2FyZS9WaWRlby1TZW5zaW5nLUJsb2NrIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2Utb3BhY2l0eT0iMC4xNSI+CiAgICAgICAgPGcgaWQ9InZpZGVvLW1vdGlvbiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDEwLjAwMDAwMCkiIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSIjMDAwMDAwIj4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjRkZGRkZGIiBvcGFjaXR5PSIwLjI1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGN4PSIzMiIgY3k9IjE2IiByPSI0LjUiPjwvY2lyY2xlPgogICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsLUNvcHkiIGZpbGw9IiNGRkZGRkYiIG9wYWNpdHk9IjAuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBjeD0iMzIiIGN5PSIxMiIgcj0iNC41Ij48L2NpcmNsZT4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjRkZGRkZGIiBvcGFjaXR5PSIwLjc1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGN4PSIzMiIgY3k9IjgiIHI9IjQuNSI+PC9jaXJjbGU+CiAgICAgICAgICAgIDxjaXJjbGUgaWQ9Ik92YWwiIGZpbGw9IiNGRkZGRkYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY3g9IjMyIiBjeT0iNCIgcj0iNC41Ij48L2NpcmNsZT4KICAgICAgICAgICAgPHBhdGggZD0iTTIyLjY3MTk0NzcsNC40MTk1NzY0OSBMMTYuNSw4LjQxOTkxMjk4IEwxNi41LDYuMSBDMTYuNSw0LjA4OTc2NDU0IDE0LjkzNzE4MDYsMi41IDEzLDIuNSBMNC4xLDIuNSBDMi4wNzYxNDIzNywyLjUgMC41LDQuMDc2MTQyMzcgMC41LDYuMSBMMC41LDE0IEMwLjUsMTUuOTI3Mzk4NyAyLjA4NDQ5ODM5LDE3LjUxMTg5NzEgNC4xLDE3LjYgTDEzLDE3LjYgQzE0LjkwMTY2MDIsMTcuNiAxNi41LDE1Ljk0NjU0NSAxNi41LDE0IEwxNi41LDExLjcxNjkwNDggTDIyLjc1NzI0NzksMTUuNDcxMjUzNSBMMjIuODUzNTUzNCwxNS41NDY0NDY2IEMyMi44NzM3ODg2LDE1LjU2NjY4MTggMjIuOTUxNTMxLDE1LjYgMjMsMTUuNiBDMjMuMjY2OTg2NSwxNS42IDIzLjUsMTUuMzgyNTIwNyAyMy41LDE1LjEgTDIzLjUsNC44IEMyMy41LDQuODM2NzY1MzggMjMuNDQzODA1OCw0LjcwNTY0NTYzIDIzLjM3MTI1MzUsNC41NTcyNDc4OCBDMjMuMjI1OTA1Niw0LjMxNTAwMTM5IDIyLjk0MTU5MzcsNC4yNTgxMzg5OSAyMi42NzE5NDc3LDQuNDE5NTc2NDkgWiIgaWQ9InZpZGVvXzM3XyIgZmlsbD0iIzRENEQ0RCI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+'; +const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIj48dGl0bGU+RXh0ZW5zaW9ucy9Tb2Z0d2FyZS9WaWRlby1TZW5zaW5nLUJsb2NrPC90aXRsZT48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLW9wYWNpdHk9Ii4xNSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxMCkiPjxjaXJjbGUgY3g9IjMyIiBjeT0iMTYiIHI9IjQuNSIgZmlsbD0iI2ZmZiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBvcGFjaXR5PSIuMjUiLz48Y2lyY2xlIGN4PSIzMiIgY3k9IjEyIiByPSI0LjUiIGZpbGw9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgb3BhY2l0eT0iLjUiLz48Y2lyY2xlIGN4PSIzMiIgY3k9IjgiIHI9IjQuNSIgZmlsbD0iI2ZmZiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBvcGFjaXR5PSIuNzUiLz48Y2lyY2xlIGN4PSIzMiIgY3k9IjQiIHI9IjQuNSIgZmlsbD0iI2ZmZiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZmlsbD0iIzRkNGQ0ZCIgZD0ibTIyLjY3MiA0LjQyLTYuMTcyIDRWNi4xYzAtMi4wMS0xLjU2My0zLjYtMy41LTMuNkg0LjFDMi4wNzYgMi41LjUgNC4wNzYuNSA2LjFWMTRjMCAxLjkyNyAxLjU4NCAzLjUxMiAzLjYgMy42SDEzYzEuOTAyIDAgMy41LTEuNjUzIDMuNS0zLjZ2LTIuMjgzbDYuMjU3IDMuNzU0LjA5Ny4wNzVjLjAyLjAyLjA5OC4wNTQuMTQ2LjA1NC4yNjcgMCAuNS0uMjE3LjUtLjVWNC44YzAgLjAzNy0uMDU2LS4wOTQtLjEyOS0uMjQzLS4xNDUtLjI0Mi0uNDMtLjI5OS0uNy0uMTM3WiIvPjwvZz48L3N2Zz4='; /** * Sensor attribute video sensor block should report. diff --git a/src/extensions/scratch3_wedo2/index.js b/src/extensions/scratch3_wedo2/index.js index 64a6ee46171..9dc7b584963 100644 --- a/src/extensions/scratch3_wedo2/index.js +++ b/src/extensions/scratch3_wedo2/index.js @@ -14,7 +14,7 @@ const log = require('../../util/log'); * @type {string} */ // eslint-disable-next-line max-len -const iconURI = 'data:image/png;base64,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'; +const iconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAACXBIWXMAABYlAAAWJQFJUiTwAAABQVBMVEX///98h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V8h6V9h6V8h6V8h6V8h6VwhKxyhat8h6V8h6VwhKxwhKx8h6U9ecw+e88/fdJAf9VBgNlDhN9EhuJGgM9GjOxHgM9Hju9Ij/JKk/lLlfxMl/9fkNVtmtlwhKx4hqd5o9x6h6Z8h6V9iKV9iKZ+iKZ+iaaAi6iBjKmCjamEjqqGkKyIkq6Jkq6MlrCOmLKQmbGUnbaVnraWn7WWn7aYobmZormao7qcpbudpbqevOWjq76lrcGqxOmttMevtsi1u8y2zey3vcu6v9C9w9K+w8/FytfLz9fO0t3O3fLS1dvS1uDX2d/a5vXe4ejf4eTm5+jm6O7v8PTz9/z39/n///+zX1z3AAAAInRSTlMAEDBAUFdgcICHkJygr7DAwc/Q3ODv8PD19vf7+/v8/f7+PDte4QAAAe9JREFUeNrt11tvEkEYxvGB1oqIjFVaDxWU0VqpJ2zVxx5kVayKumKp9ihai7vA+/0/gDOZNNbkzdJM9qJJ53cBhGf2n73YmxWe53med3plijIvxLiUWSHyspARWSknhMjJYsZsOSEmzJYp6GNmGxcjFAGMCWgiByAnpgFkxwBIIQ+3abvZY0nOTU6Vgac3Zha1mZvm89bic6BSAVAtVwFcktBkCUDJ/pQynxGsM9fhqCA456sItomeqNkHdWNe1doDordAuE9JugB7f1Ws67Wt7j6uG49U7YCI3mNV55KFbPCK7mn3b+uecU91iGgP6JNT8CwC0n6qubp1Rw2I6A2+kVvwMrZJ66j5uqUWSMMSOQavgYy2eng0uIfXrkGs8sGmczA4QcFPCcFNNWsfm7njB+OVhOCgpg5tHjM4fIeEIB08W7A69H+wF5uLe30i6veG5sZ6dtjAK/BBxr9gCGxQ3ETQpW6AZkzfgXBoj3x2CUKjHQChaWOHoPWIYgRxyAVXwFrCSF1ig2i0GGuwfzfAr029rPNBtCLGD3yIjBb4dTf6heX9VIPRFl5+TDUYfUEj3eCfBlIM2q8XKQbt6hBkuQe3WrzfLsFEPngE1lIOLuOra3AXXLAEuJsUjItlRqV6dWq0C/5NwvM8zzuV/gL7cbih1u2EKwAAAABJRU5ErkJggg=='; /** * A list of WeDo 2.0 BLE service UUIDs. From 464a9c68dd0be96bbbedd96c25bc83d542c32b0b Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Tue, 13 Jan 2026 19:09:45 -0600 Subject: [PATCH 088/106] Support JS Map in externalDeltaToJS for extension compatibility Nothing in Scratch uses this --- src/engine/monitor-record.js | 8 ++++++-- test/unit/tw_monitor_record.js | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/engine/monitor-record.js b/src/engine/monitor-record.js index 694bcd8464e..f19e7be10ec 100644 --- a/src/engine/monitor-record.js +++ b/src/engine/monitor-record.js @@ -29,7 +29,7 @@ const defined = obj => typeof obj !== 'undefined' && obj !== null; */ /** - * @typedef {JSDelta|ImmutableJSDelta} ExternalDelta Delta object that might be JS or immutable.js. + * @typedef {JSDelta|ImmutableJSDelta|Map} ExternalDelta Delta object that might be JS object, immutable.js, or JS Map */ /** @@ -184,7 +184,7 @@ class MonitorRecord { } /** - * For compatibility, converts an immutable.js delta received from consumer to a plain JS delta for internal use. + * For compatibility, converts delta received from consumer to a plain JS delta for internal use. * @param {ExternalDelta} obj * @returns {JSDelta} */ @@ -192,6 +192,10 @@ MonitorRecord.externalDeltaToJS = obj => { if (typeof obj.toJS === 'function') { return obj.toJS(); } + // Nothing in Scratch would pass a JS map into this, but some weird extensions do. + if (obj instanceof Map) { + return Object.fromEntries(Array.from(obj.entries())); + } return obj; }; diff --git a/test/unit/tw_monitor_record.js b/test/unit/tw_monitor_record.js index 59cd3a13417..614d16c84aa 100644 --- a/test/unit/tw_monitor_record.js +++ b/test/unit/tw_monitor_record.js @@ -52,5 +52,9 @@ test('externalDeltaToJS', t => { toJS: () => ({whatever: 'a'}) }), {whatever: 'a'}); + t.same(MonitorRecord.externalDeltaToJS( + new Map([['whatever', 'a']]) + ), {whatever: 'a'}); + t.end(); }); From d825b5017f58916a396fe61f54f1ee87e602fd15 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 24 Jan 2026 14:01:42 -0600 Subject: [PATCH 089/106] add sensing_online --- src/blocks/scratch3_sensing.js | 15 ++++++++++++++- test/unit/tw_block_sensing.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 test/unit/tw_block_sensing.js diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js index 15c071cb7f5..d9ef1e8ed6b 100644 --- a/src/blocks/scratch3_sensing.js +++ b/src/blocks/scratch3_sensing.js @@ -72,7 +72,8 @@ class Scratch3SensingBlocks { sensing_askandwait: this.askAndWait, sensing_answer: this.getAnswer, sensing_username: this.getUsername, - sensing_userid: () => {} // legacy no-op block + sensing_userid: () => {}, // legacy no-op block + sensing_online: this.isOnline }; } @@ -104,6 +105,9 @@ class Scratch3SensingBlocks { // importing multiple monitors from the same opcode from sb2 files, // something that is not currently supported in scratch 3. getId: (_, fields) => getMonitorIdForBlockWithArgs('current', fields) // _${param}` + }, + sensing_online: { + getId: () => 'online' } }; } @@ -343,6 +347,15 @@ class Scratch3SensingBlocks { getUsername (args, util) { return util.ioQuery('userData', 'getUsername'); } + + isOnline () { + // Modern Node.js has a navigator object but does .onLine === undefined + if (typeof navigator === 'object' && typeof navigator.onLine === 'boolean') { + return navigator.onLine; + } + // We're running in some non-browser environment. We probably have internet. + return true; + } } module.exports = Scratch3SensingBlocks; diff --git a/test/unit/tw_block_sensing.js b/test/unit/tw_block_sensing.js new file mode 100644 index 00000000000..779c8a14119 --- /dev/null +++ b/test/unit/tw_block_sensing.js @@ -0,0 +1,28 @@ +const {test} = require('tap'); +const Scratch3SensingBlocks = require('../../src/blocks/scratch3_sensing'); +const Runtime = require('../../src/engine/runtime'); + +test('isOnline', t => { + const rt = new Runtime(); + const sensing = new Scratch3SensingBlocks(rt); + + if (!global.navigator) { + global.navigator = {}; + } + + Object.defineProperty(global.navigator, 'onLine', { + get: () => false, + configurable: true, + enumerable: true + }); + t.equal(sensing.isOnline(), false); + + Object.defineProperty(global.navigator, 'onLine', { + get: () => true, + configurable: true, + enumerable: true + }); + t.equal(sensing.isOnline(), true); + + t.end(); +}); From 722014ee66d323831e30c199c7eaca809aceea65 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 24 Jan 2026 14:02:44 -0600 Subject: [PATCH 090/106] add sensing_online to compiler compat blocks --- src/compiler/compat-blocks.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/compat-blocks.js b/src/compiler/compat-blocks.js index 2174a58c4a7..86f03f26078 100644 --- a/src/compiler/compat-blocks.js +++ b/src/compiler/compat-blocks.js @@ -38,6 +38,7 @@ const inputs = [ 'motion_yscroll', 'sensing_loud', 'sensing_loudness', + 'sensing_online', 'sensing_userid', 'sound_volume' ]; From 1ea395fe97cc9742c2a822dc294c3912ec288720 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sun, 8 Feb 2026 11:22:19 -0600 Subject: [PATCH 091/106] Don't allow reading video motion when external communication is possible (#331) --- src/engine/runtime.js | 10 ++++++++-- src/extensions/scratch3_video_sensing/index.js | 8 ++++++++ test/integration/tw_privacy.js | 14 ++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/engine/runtime.js b/src/engine/runtime.js index e1802a7bc31..ce6a0801eef 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -505,6 +505,12 @@ class Runtime extends EventEmitter { */ this.enforcePrivacy = true; + /** + * If true, an external communication method exists and enforcePrivacy is enabled. + * Do not update this directly. Must be changed via public functions that call Runtime.updatePrivacy(). + */ + this.privacyRestrictionsActive = false; + /** * Internal map of opaque identifiers to the callback to run that function. * @type {Map} @@ -3420,12 +3426,12 @@ class Runtime extends EventEmitter { } updatePrivacy () { - const enforceRestrictions = ( + this.privacyRestrictionsActive = ( this.enforcePrivacy && Object.values(this.externalCommunicationMethods).some(i => i) ); if (this.renderer && this.renderer.setPrivateSkinAccess) { - this.renderer.setPrivateSkinAccess(!enforceRestrictions); + this.renderer.setPrivateSkinAccess(!this.privacyRestrictionsActive); } } diff --git a/src/extensions/scratch3_video_sensing/index.js b/src/extensions/scratch3_video_sensing/index.js index 360b893ca3e..3940043c06c 100644 --- a/src/extensions/scratch3_video_sensing/index.js +++ b/src/extensions/scratch3_video_sensing/index.js @@ -531,6 +531,10 @@ class Scratch3VideoSensingBlocks { * @returns {number} the motion amount or direction of the stage or sprite */ videoOn (args, util) { + if (this.runtime.privacyRestrictionsActive) { + return -1; + } + this.detect.analyzeFrame(); let state = this.detect; @@ -554,6 +558,10 @@ class Scratch3VideoSensingBlocks { * reference */ whenMotionGreaterThan (args, util) { + if (this.runtime.privacyRestrictionsActive) { + return false; + } + this.detect.analyzeFrame(); const state = this._analyzeLocalMotion(util.target); return state.motionAmount > Number(args.REFERENCE); diff --git a/test/integration/tw_privacy.js b/test/integration/tw_privacy.js index fda382f7114..0f2b1d760b7 100644 --- a/test/integration/tw_privacy.js +++ b/test/integration/tw_privacy.js @@ -114,3 +114,17 @@ test('custom extensions', async t => { t.equal(vm.renderer.privateSkinAccess, false); t.end(); }); + +test('hasExternalCommunicationMethod', t => { + const vm = new VM(); + t.equal(vm.runtime.privacyRestrictionsActive, false); + vm.runtime.setExternalCommunicationMethod('cloudVariables', true); + t.equal(vm.runtime.privacyRestrictionsActive, true); + vm.runtime.setExternalCommunicationMethod('customExtensions', true); + t.equal(vm.runtime.privacyRestrictionsActive, true); + vm.runtime.setExternalCommunicationMethod('cloudVariables', false); + t.equal(vm.runtime.privacyRestrictionsActive, true); + vm.runtime.setExternalCommunicationMethod('customExtensions', false); + t.equal(vm.runtime.privacyRestrictionsActive, false); + t.end(); +}); From 9f2106a290297cd07c75bcde0e2b7163f40053af Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 2 Mar 2026 22:43:29 -0600 Subject: [PATCH 092/106] Remove variable value safe stringification I thought this may have been part of fixing a sb2 -> sb3 corruption issue. But from commit log, it seems this was added to prevent extensions from making mistakes. With the scratch-parser change, those mistakes are now considered features. Seems safe to just do remove these checks all the time. Closes https://github.com/TurboWarp/scratch-vm/pull/332 --- src/serialization/sb3.js | 36 ++------------------------------- test/unit/virtual-machine_tw.js | 10 ++++----- 2 files changed, 7 insertions(+), 39 deletions(-) diff --git a/src/serialization/sb3.js b/src/serialization/sb3.js index 33c822205d2..0f4475807f8 100644 --- a/src/serialization/sb3.js +++ b/src/serialization/sb3.js @@ -481,38 +481,6 @@ const serializeSound = function (sound) { return obj; }; -// Using some bugs, it can be possible to get values like undefined, null, or complex objects into -// variables or lists. This will cause make the project unusable after exporting without JSON editing -// as it will fail validation in scratch-parser. -// To avoid this, we'll convert those objects to strings before saving them. -const isVariableValueSafeForJSON = value => ( - typeof value === 'number' || - typeof value === 'string' || - typeof value === 'boolean' -); -const makeSafeForJSON = value => { - if (Array.isArray(value)) { - let copy = null; - for (let i = 0; i < value.length; i++) { - if (!isVariableValueSafeForJSON(value[i])) { - if (!copy) { - // Only copy the list when needed - copy = value.slice(); - } - copy[i] = `${copy[i]}`; - } - } - if (copy) { - return copy; - } - return value; - } - if (isVariableValueSafeForJSON(value)) { - return value; - } - return `${value}`; -}; - /** * Serialize the given variables object. * @param {object} variables The variables to be serialized. @@ -534,12 +502,12 @@ const serializeVariables = function (variables) { continue; } if (v.type === Variable.LIST_TYPE) { - obj.lists[varId] = [v.name, makeSafeForJSON(v.value)]; + obj.lists[varId] = [v.name, v.value]; continue; } // otherwise should be a scalar type - obj.variables[varId] = [v.name, makeSafeForJSON(v.value)]; + obj.variables[varId] = [v.name, v.value]; // only scalar vars have the potential to be cloud vars if (v.isCloud) obj.variables[varId].push(true); } diff --git a/test/unit/virtual-machine_tw.js b/test/unit/virtual-machine_tw.js index b0d2f52c075..d41acde7daf 100644 --- a/test/unit/virtual-machine_tw.js +++ b/test/unit/virtual-machine_tw.js @@ -24,7 +24,7 @@ test('emitTargetsUpdate targetList is lazy', t => { t.end(); }); -test('non-primitive values in lists and variables converted to strings', t => { +test('values in lists and variables are serialized as-is', t => { const vm = new VirtualMachine(); const sprite = new Sprite(); const target = new RenderedTarget(sprite, vm.runtime); @@ -54,14 +54,14 @@ test('non-primitive values in lists and variables converted to strings', t => { const json = JSON.parse(vm.toJSON()); - t.deepEqual(json.targets[0].variables.var1[1], 'null'); - t.deepEqual(json.targets[0].variables.var2[1], 'undefined'); - t.deepEqual(json.targets[0].variables.var3[1], '[object Object]'); + t.deepEqual(json.targets[0].variables.var1[1], null); + t.deepEqual(json.targets[0].variables.var2[1], null); // undefined becomes null due to JSON limitations + t.deepEqual(json.targets[0].variables.var3[1], {}); t.deepEqual(json.targets[0].variables.var4[1], 1); t.deepEqual(json.targets[0].variables.var5[1], 'abc'); t.deepEqual(json.targets[0].variables.var6[1], false); - t.deepEqual(json.targets[0].lists.list[1], ['abc', false, 1, 'null', 'undefined', '[object Object]']); + t.deepEqual(json.targets[0].lists.list[1], ['abc', false, 1, null, null, {}]); t.end(); }); From 94276b1ee9f3dbfbd602cde8ff9f66b5c1dcdf0b Mon Sep 17 00:00:00 2001 From: Classfied3D <82328013+Classfied3D@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:08:06 +0100 Subject: [PATCH 093/106] fix indefinite calls to analyzeScript when a large amount of procedures interlink (#334) --- src/compiler/irgen.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index befab712049..08d1701fbb3 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -1459,7 +1459,7 @@ class IRGenerator { /** @type {Object.} */ this.procedures = {}; - this.analyzedProcedures = []; + this.analyzedProcedures = new Set(); } addProcedureDependencies (dependencies) { @@ -1500,12 +1500,11 @@ class IRGenerator { const procedureData = this.procedures[procedureCode]; // Analyze newly found procedures. - if (!this.analyzedProcedures.includes(procedureCode)) { - this.analyzedProcedures.push(procedureCode); + if (!this.analyzedProcedures.has(procedureCode)) { + this.analyzedProcedures.add(procedureCode); if (this.analyzeScript(procedureData)) { madeChanges = true; } - this.analyzedProcedures.pop(); } // If a procedure used by a script may yield, the script itself may yield. @@ -1548,7 +1547,10 @@ class IRGenerator { } // Analyze scripts until no changes are made. - while (this.analyzeScript(entry)); + while (this.analyzeScript(entry)) { + // Reset so all procedures get re-examined each pass. + this.analyzedProcedures = new Set(); + } return new IntermediateRepresentation(entry, this.procedures); } From 7b521ff000780d61b18ac47bfb65625451caceb5 Mon Sep 17 00:00:00 2001 From: LilyMakesThings <127533508+LilyMakesThings@users.noreply.github.com> Date: Sun, 19 Apr 2026 04:18:21 +0100 Subject: [PATCH 094/106] Force shadow property for procedure blocks during deserialization (#335) Co-authored-by: Cubester <78769806+CubesterYT@users.noreply.github.com> Co-authored-by: Thomas Weber --- src/serialization/sb3.js | 27 ++++++++++++++++ .../tw-spork-custom-block-definition.sb3 | Bin 0 -> 2020 bytes test/integration/tw_spork_compat.js | 30 ++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 test/fixtures/tw-spork-custom-block-definition.sb3 create mode 100644 test/integration/tw_spork_compat.js diff --git a/src/serialization/sb3.js b/src/serialization/sb3.js index 0f4475807f8..66854a09826 100644 --- a/src/serialization/sb3.js +++ b/src/serialization/sb3.js @@ -1114,6 +1114,31 @@ const parseScratchAssets = function (object, runtime, zip) { return assets; }; +/** + * Fix various backwards-incompatible changes that Scratch made in the spork migration. + * @param {object} blocks Blocks, mutated in-place. + */ +const fixSporkCompatibility = function (blocks) { + for (const blockId in blocks) { + if (!Object.prototype.hasOwnProperty.call(blocks, blockId)) continue; + const block = blocks[blockId]; + + // Custom block definition prototype blocks used to be marked as shadow: true, but spork marks as shadow: true. + // Our scratch-blocks relies on it being shadow: true to prevent moving, so we'll force it to be that way. + if (block.opcode === 'procedures_prototype') { + block.shadow = true; + } else if ( + block.opcode === 'argument_reporter_string_number' || + block.opcode === 'argument_reporter_boolean' + ) { + const parent = blocks[block.parent]; + if (parent && parent.opcode === 'procedures_prototype') { + block.shadow = true; + } + } + } +}; + /** * Parse a single "Scratch object" and create all its in-memory VM objects. * @param {!object} object From-JSON "Scratch object:" sprite, stage, watcher. @@ -1154,6 +1179,8 @@ const parseScratchObject = function (object, runtime, extensions, zip, assets) { extensions.extensionIDs.add(extensionID); } } + // Take a third pass to fix various things that spork broke. + fixSporkCompatibility(object.blocks); } // Costumes from JSON. const {costumePromises} = assets; diff --git a/test/fixtures/tw-spork-custom-block-definition.sb3 b/test/fixtures/tw-spork-custom-block-definition.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..f9d5f9f733de9a67e3fa638d1d18a56cd39c4ec6 GIT binary patch literal 2020 zcma)7c`)1Q8~;j_)YWX`SXbGSy4sKg35~jGf;#Fb)e<6ARM0qE4OX>P(x0Og?a!j_ zyVM$+)z-C0i!@7A>MV7Pn^5Z5?C+o5?aXgx-)EkA=6&b+JTvbzpU-?8Y`}sd002OM zX~_)F#~X{0F<=1j7X|<^{%c4WCBV;@iU_z#2`+Xa-WZ zvrCGX?mf3%K2Gn=vh^e}ReFTXdMGOdlSkCHV)S;;$l&f0caR^$IdvVyr9>tpII9X2Wn~gv^$YBhbuVa z4$;|t_bcPc z$rLt-PYv!W(M~4#<*@4|o`*v(8_4|bgDrXM)MB6ydgE$9J;e?h;JquF8CU-LnWae? z@E10>x&0#u!9>5Be|)GTK~2&s(JwgFo7qCoB|5gz*M1rdu;)fTqCGq--8gOLh|D68 zI!T_+(YBrE;5f}nMfl{Z(87A+5B zp^D=)>fgu1sk`U0E8g$k43BfKEgdB@I^V)C z$qlON5V)5y43k_bRFS!Tyv-d)r`(ScA;|K#4~s1e8)g*#3r0-G)S0NCQEd$KopmOj zLE<+&E}ESAE!=azX~sM1OzEen5yA6C+(&x|Uoi}q9;kRVdhCH-cXB}RyY{|j*wage zbjHMRsQl37T-#`NWC5X{SJhxUklCL{ma%F(=I{@V=C9qY(E|a14nI}-8pWcC1{f@c zr0eUWPe%J-^wB6ET@s1x=R?NmqV+L|NMeM54yb?M32$Yk&Ih@fx>}NNP?e#4umC^4 z(*l5#t^fc6pa6+TB?|I;1_3bmSK%=66{(AgIF&rrDdkG(n?f#YUL)QesSVf5)5~V+ ztvgL8H$Y3LSk?q$EJY-Rt09UUgrgQYETmZQ-?K zrGdKRnyW7Uf)-ftG`F>7u}q?z#Yh=t2;mTMHj?gYPFD=7UMEr7aEe19e-) zCt{4d9eW)EjboK&ci2Pmtx8QUtyO~zp62%nXr5`J$!TpdnA>{(U_(3a6_xq)Qw%6Z z`GJ0t@q4VHYP(SStbAY6E68i9e#iMh$Q`({A;k10HcREAkoKHwzh>J)n+NO20$w=t zBu8%mx2Q)@@i=O|EI%B{6lao$C=2zVbXl}!lum^fPH_`L+IThD%-I^M8i%gD6VQNp zDwV06SE_{7f}J)(KDUf>C(!e6w^W6=uyqB3QlebXvD*UE>w2@|lSz{?bJsQtK&PQz za!{od#jDarqSS-g_1=Z7*~IyYm7OoYgCL>=X!>^_Brr#1LD65IZDnna@;Ez6hjhVg zh>S=w#6^&J@K4&^?}G|t@EOy~&p&DBOF|*_kh&xtJv5R`B9nbkD3p$_pN^leo*xOT zOGMm^xOT(NM&d_h$&a^^IX??`)abSq;_U}ujf6z!&exR#T#iS!9T}NJk>?1w!U{JU z%zEHvVMgwEr4sal>l)dEIn*`xA2R9+66~04to7Y2|Lck8HP)z~&xsXkGM$3jt)KT4 z<>enHyr>DR|D{YcZmZ*a&y6W?&WRJ0=J3f2&yEOLV-5t*8BCSXj(Xe5EN$D+00$cZ zkRE_ literal 0 HcmV?d00001 diff --git a/test/integration/tw_spork_compat.js b/test/integration/tw_spork_compat.js new file mode 100644 index 00000000000..55cc87c439b --- /dev/null +++ b/test/integration/tw_spork_compat.js @@ -0,0 +1,30 @@ +const {test} = require('tap'); +const fs = require('fs'); +const path = require('path'); +const VM = require('../../src/virtual-machine'); + +test('spork compat: procedure prototype and argument reporters load as shadows', t => { + const vm = new VM(); + const fixture = fs.readFileSync(path.join(__dirname, '../fixtures/tw-spork-custom-block-definition.sb3')); + vm.loadProject(fixture).then(() => { + let prototypeCount = 0; + let argumentReporterCount = 0; + + for (const target of vm.runtime.targets) { + for (const block of Object.values(target.blocks._blocks)) { + if (block.opcode === 'procedures_prototype') { + prototypeCount++; + t.equal(block.shadow, true); + } else if (block.opcode.startsWith('argument_reporter_')) { + argumentReporterCount++; + t.equal(block.shadow, true); + } + } + } + + t.equal(prototypeCount, 1); + t.equal(argumentReporterCount, 2); + + t.end(); + }); +}); From 52f4369e63a69accc9b2acd614dea63fa594a37f Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sun, 3 May 2026 10:27:14 -0500 Subject: [PATCH 095/106] Fix spork compatibility issue with mutation-less control_stop Our editor relies on the mutation for control_stop to know if there is a connection below. Spork does not export that mutation anymore. Instead, we will just generate the mutation to fix errors on loading. --- src/serialization/sb3.js | 35 ++++++++++++++--- test/fixtures/tw-spork-stop-other-scripts.sb3 | Bin 0 -> 4107 bytes test/integration/tw_spork_compat.js | 37 ++++++++++++++++++ 3 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/tw-spork-stop-other-scripts.sb3 diff --git a/src/serialization/sb3.js b/src/serialization/sb3.js index 66854a09826..84280a584c0 100644 --- a/src/serialization/sb3.js +++ b/src/serialization/sb3.js @@ -1121,20 +1121,43 @@ const parseScratchAssets = function (object, runtime, zip) { const fixSporkCompatibility = function (blocks) { for (const blockId in blocks) { if (!Object.prototype.hasOwnProperty.call(blocks, blockId)) continue; + const block = blocks[blockId]; + const opcode = block.opcode; - // Custom block definition prototype blocks used to be marked as shadow: true, but spork marks as shadow: true. + switch (opcode) { + // Custom block definition prototype blocks used to be marked as shadow: true, but spork marks as shadow: false. // Our scratch-blocks relies on it being shadow: true to prevent moving, so we'll force it to be that way. - if (block.opcode === 'procedures_prototype') { + case 'procedures_prototype': block.shadow = true; - } else if ( - block.opcode === 'argument_reporter_string_number' || - block.opcode === 'argument_reporter_boolean' - ) { + break; + + // For completeness with the above, set the argument reporter generators to be shadow: true as well. + case 'argument_reporter_string_number': + case 'argument_reporter_boolean': { const parent = blocks[block.parent]; if (parent && parent.opcode === 'procedures_prototype') { block.shadow = true; } + break; + } + + // control_stop used to define a mutation for whether it has a connection below, which is what old + // scratch-blocks relies on to determine if there is another conneciton below or not. Spork does not define + // this mutation and relies only on the STOP_OPTION field. We will generate the mutation if it's missing so + // that a "stop other scripts in sprite" block doesn't cause the workspace to fail to load. + case 'control_stop': { + if (!block.mutation) { + const stopOption = block.fields?.STOP_OPTION?.value; + const hasNext = stopOption === 'other scripts in sprite' || stopOption === 'other scripts in stage'; + block.mutation = { + tagName: 'mutation', + hasnext: hasNext ? 'true' : 'false', + children: [] + }; + } + break; + } } } }; diff --git a/test/fixtures/tw-spork-stop-other-scripts.sb3 b/test/fixtures/tw-spork-stop-other-scripts.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..994e66ac49e6b12c4d21496b3ae5a83073521215 GIT binary patch literal 4107 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 { + const vm = new VM(); + const fixture = fs.readFileSync(path.join(__dirname, '../fixtures/tw-spork-stop-other-scripts.sb3')); + vm.loadProject(fixture).then(() => { + let otherScriptsInSprite = 0; + let all = 0; + let thisScript = 0; + + for (const target of vm.runtime.targets) { + for (const block of Object.values(target.blocks._blocks)) { + if (block.opcode !== 'control_stop') { + continue; + } + const stopOption = block.fields.STOP_OPTION.value; + if (stopOption === 'other scripts in sprite') { + otherScriptsInSprite++; + t.same(block.mutation, {tagName: 'mutation', hasnext: 'true', children: []}); + } else if (stopOption === 'all') { + all++; + t.same(block.mutation, {tagName: 'mutation', hasnext: 'false', children: []}); + } else if (stopOption === 'this script') { + thisScript++; + t.same(block.mutation, {tagName: 'mutation', hasnext: 'false', children: []}); + } else { + t.fail(`unexpected STOP_OPTION value: ${stopOption}`); + } + } + } + + t.equal(otherScriptsInSprite, 2); + t.equal(all, 1); + t.equal(thisScript, 1); + + t.end(); + }); +}); From 925f1134001ada36572eeb35f9d83ba01c98081a Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 13 May 2026 17:58:31 -0500 Subject: [PATCH 096/106] Don't start monitors if there are no targets Fixes https://github.com/TurboWarp/sb3fix/issues/125 in the safest way that hopefully has no unforseen breakages on weird behaviors --- src/engine/runtime.js | 4 +++ test/unit/engine_runtime_tw.js | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/engine/runtime.js b/src/engine/runtime.js index ce6a0801eef..1df8dff1bba 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -2612,6 +2612,10 @@ class Runtime extends EventEmitter { * Queue monitor blocks to sequencer to be run. */ _pushMonitors () { + if (this.targets.length === 0) { + // Project is not loaded yet, but monitors might be. Don't try to start anything. + return; + } this.monitorBlocks.runAllMonitored(this); } diff --git a/test/unit/engine_runtime_tw.js b/test/unit/engine_runtime_tw.js index e69e736a6fe..84644178710 100644 --- a/test/unit/engine_runtime_tw.js +++ b/test/unit/engine_runtime_tw.js @@ -272,3 +272,51 @@ test('visual report -0', t => { t.end(); }); + +const makeMonitorBlock = () => ({ + id: 'fakeMonitor', + opcode: 'data_variable', + fields: { + VARIABLE: { + name: 'VARIABLE', + value: 'x', + id: 'fakeMonitor' + } + }, + inputs: {}, + topLevel: true, + next: null, + parent: null, + shadow: false, + x: 0, + y: 0, + isMonitored: true, + targetId: null +}); + +test('_pushMonitors does nothing when no targets are installed', t => { + const rt = new Runtime(); + rt.monitorBlocks.createBlock(makeMonitorBlock()); + + t.equal(rt.targets.length, 0); + rt._pushMonitors(); + t.equal(rt.threads.length, 0); + + t.end(); +}); + +test('_pushMonitors queues threads once targets are installed', t => { + const rt = new Runtime(); + rt.monitorBlocks.createBlock(makeMonitorBlock()); + + const stage = new Target(rt); + rt.targets.push(stage); + rt.setEditingTarget(stage); + + rt._pushMonitors(); + t.equal(rt.threads.length, 1); + t.equal(rt.threads[0].target, stage); + t.equal(rt.threads[0].updateMonitor, true); + + t.end(); +}); From adaa47dec2dd13739930abcdb095900064998938 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 23 May 2026 00:43:59 -0500 Subject: [PATCH 097/106] Update scratch-parser --- package-lock.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index d6759c7ad58..ada339cd7db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2133,9 +2133,9 @@ "integrity": "sha512-9nWywp+0SH7ROVzQPQQO9gMWBikahsqyMWp1Ku8VV0q+q6bnx6dS0aNPTjqTtF2GHAY55hcREsqKzaoUdWBSwg==" }, "node_modules/@turbowarp/jszip": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/@turbowarp/jszip/-/jszip-3.11.1.tgz", - "integrity": "sha512-1tWXTxAac1T/g0VHC9lIY0Ij7Qyt7sORIaAT4L0/Y+pjU1ZtXD9ti/+RnXzTVHXp6AM8fM2O3mF22/aSEVPXiQ==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@turbowarp/jszip/-/jszip-3.12.0.tgz", + "integrity": "sha512-nTKFFc1rUToxTdxUKPIou3YKUsSelgEoyx4TAPzK/0BkGPntkenp9zoJOSnxnGWNchVXYVZv01+3aZwlS1K8hw==", "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", @@ -2186,12 +2186,12 @@ "integrity": "sha512-texcM9oxfEsADVlVDR5UhLkYclPKsV9mytJh+9pHHonNcUrxRVGF6FkJTzWO/Hl5NafU1crSdw737nqKE3atSA==" }, "node_modules/@turbowarp/sb3fix": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@turbowarp/sb3fix/-/sb3fix-0.3.6.tgz", - "integrity": "sha512-pKRyJbZYGHFAQNacwJEoz5sh8SnSDRFFle1BcEoyZHRuDE/9TZoBFNfYzoyjKCeOyOBStcS8kmGhak45YabaDg==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@turbowarp/sb3fix/-/sb3fix-0.5.0.tgz", + "integrity": "sha512-X5EOo+2nO3jIjEAzDY/Fmyn0wj6uAqOYXrRB9HAwTX4xWrmwvhuN/l8trVg/p+718/ySB9vQ7BGP2P0wklBCzw==", "license": "MPL-2.0", "dependencies": { - "@turbowarp/jszip": "^3.11.1" + "@turbowarp/jszip": "^3.12.0" } }, "node_modules/@turbowarp/scratch-svg-renderer": { @@ -13559,12 +13559,12 @@ }, "node_modules/scratch-parser": { "version": "0.0.0-development", - "resolved": "git+ssh://git@github.com/TurboWarp/scratch-parser.git#083d6425bc0c43d17f393be2f41f00b6488ba940", + "resolved": "git+ssh://git@github.com/TurboWarp/scratch-parser.git#fb65ba09d78ab6a0d19ce908d64b72d1a122312f", "license": "MPL-2.0", "dependencies": { "@turbowarp/json": "^0.1.1", "@turbowarp/jszip": "^3.11.0", - "@turbowarp/sb3fix": "^0.3.0", + "@turbowarp/sb3fix": "^0.5.0", "ajv": "6.3.0", "pify": "4.0.1" }, From 8da02dcab31cbacb8fe279b03fd68a16deb96187 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 23 May 2026 01:07:33 -0500 Subject: [PATCH 098/106] Bump @turbowarp/scratch-svg-renderer peer dep --- package-lock.json | 62 +++++++++++++++++------------------------------ package.json | 2 +- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/package-lock.json b/package-lock.json index ada339cd7db..afda7ac24a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,7 +64,7 @@ "webpack-dev-server": "3.11.2" }, "peerDependencies": { - "@turbowarp/scratch-svg-renderer": "^1.0.0-202312300007-62fe825" + "@turbowarp/scratch-svg-renderer": "^1.1.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2195,18 +2195,16 @@ } }, "node_modules/@turbowarp/scratch-svg-renderer": { - "version": "1.0.202409161736", - "resolved": "https://registry.npmjs.org/@turbowarp/scratch-svg-renderer/-/scratch-svg-renderer-1.0.202409161736.tgz", - "integrity": "sha512-Lztj24zQqT8Ddw7gz1zCbRFZXi/h3r9boEzlQs5omtHeImGZe6I8mLkoHyeP/jJGOUpp5LKZgTKGOStBLtRSiw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@turbowarp/scratch-svg-renderer/-/scratch-svg-renderer-1.1.0.tgz", + "integrity": "sha512-UPSUNKfR9f73ZNgjYdxsz5yheZYO/EiKE3Wji31thRVDGzOJOROQXcFicl/1oDWkMII4FvSLylGAw6/MPpoXqg==", "license": "MPL-2.0", "peer": true, "dependencies": { "@turbowarp/nanolog": "^0.2.0", "base64-js": "1.2.1", "base64-loader": "1.0.0", - "css-tree": "1.1.3", - "dompurify": "^2.5.6", - "fastestsmallesttextencoderdecoder": "^1.0.22", + "dompurify": "^3.4.5", "transformation-matrix": "1.15.0" }, "peerDependencies": { @@ -2214,11 +2212,14 @@ } }, "node_modules/@turbowarp/scratch-svg-renderer/node_modules/dompurify": { - "version": "2.5.8", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz", - "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.5.tgz", + "integrity": "sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA==", "license": "(MPL-2.0 OR Apache-2.0)", - "peer": true + "peer": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -2292,6 +2293,14 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -4667,28 +4676,6 @@ "node": "*" } }, - "node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "peer": true, - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-tree/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cyclist": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz", @@ -6940,7 +6927,8 @@ "node_modules/fastestsmallesttextencoderdecoder": { "version": "1.0.22", "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz", - "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==" + "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==", + "dev": true }, "node_modules/fastq": { "version": "1.16.0", @@ -10786,12 +10774,6 @@ "safe-buffer": "^5.1.2" } }, - "node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "peer": true - }, "node_modules/mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", diff --git a/package.json b/package.json index a22e531a254..3155445d494 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "worker-loader": "^1.1.1" }, "peerDependencies": { - "@turbowarp/scratch-svg-renderer": "^1.0.0-202312300007-62fe825" + "@turbowarp/scratch-svg-renderer": "^1.1.0" }, "devDependencies": { "@babel/core": "7.13.10", From 43f13efd1883eeef8f82616faf69380ff75ab068 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 23 May 2026 16:27:10 -0500 Subject: [PATCH 099/106] Add default URL for video sprites --- src/extension-support/tw-default-extension-urls.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/extension-support/tw-default-extension-urls.js b/src/extension-support/tw-default-extension-urls.js index de3c3ec77d0..05411afc69b 100644 --- a/src/extension-support/tw-default-extension-urls.js +++ b/src/extension-support/tw-default-extension-urls.js @@ -11,8 +11,11 @@ const defaults = { // Turboloader's AudioStream audiostr: 'https://extensions.turbowarp.org/turboloader/audiostream.js', - // https://scratch.mit.edu/discuss/topic/842592/ - faceSensing: 'https://extensions.turbowarp.org/lab/face-sensing.js' + // Face Sensing - https://lab.scratch.mit.edu/face/ - https://scratch.mit.edu/discuss/topic/842592/ + faceSensing: 'https://extensions.turbowarp.org/lab/face-sensing.js', + + // Video Sprites - https://lab.scratch.mit.edu/videosprites/ + videoSprites: 'https://extensions.turbowarp.org/lab/video-sprites.js' }; module.exports = defaults; From ccfd5f4006254d38d64fdff1925102943cf276cd Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 4 Jul 2026 17:42:31 -0500 Subject: [PATCH 100/106] Run no-op rAF workaround on Chrome Android closes https://github.com/TurboWarp/scratch-vm/issues/343 --- src/engine/tw-frame-loop.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/engine/tw-frame-loop.js b/src/engine/tw-frame-loop.js index bf2554b452e..30632ec08bb 100644 --- a/src/engine/tw-frame-loop.js +++ b/src/engine/tw-frame-loop.js @@ -24,18 +24,28 @@ const animationFrameWrapper = callback => { /** * We've found that having an empty requestAnimationFrame loop running in the background improves frame - * pacing in many situations. See https://github.com/TurboWarp/scratch-vm/issues/257. + * pacing in many situations. * * Having an extra loop running increases CPU usage and battery usage even if it's not doing anything. * So, we only do this when the intended framerate is high enough that the user clearly wants smooth * motion, and only if the user is on a platform where we have evidence that this helps: - * - Chrome, Edge, and other Chromium on Windows + * + * Chrome on Windows: We think this is related to timer precision, where using rAF might be making Chrome + * give us a more precise timer. + * See https://github.com/TurboWarp/scratch-vm/issues/257. + * + * Chrome on Android. Chrome throttles frame production when it does not believe there is an animation + * happening. setInterval does not count as an animation, but rAF does. + * See https://github.com/TurboWarp/scratch-vm/issues/343. * * @param {number} framerate Intended framerate * @returns {boolean} true if no-op animation frame loop should be used */ const shouldUseNoopAnimationFrame = framerate => - framerate >= 30 && navigator.userAgent.includes('Chrome') && navigator.userAgent.includes('Windows'); + framerate >= 30 && navigator.userAgent.includes('Chrome') && ( + navigator.userAgent.includes('Windows') || + navigator.userAgent.includes('Android') + ); class FrameLoop { constructor (runtime) { From c4823421cb7c17d8d8a89878851ce1668c26a21f Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 11 Jul 2026 23:29:37 -0500 Subject: [PATCH 101/106] Fix toggleScript confusion when block ID is reused across targets (#347) --- src/engine/runtime.js | 6 ++- test/unit/engine_runtime_tw.js | 84 ++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 1df8dff1bba..e017bcb30c4 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -2111,7 +2111,11 @@ class Runtime extends EventEmitter { // Remove any existing thread. for (let i = 0; i < this.threads.length; i++) { // Toggling a script that's already running turns it off - if (this.threads[i].topBlock === topBlockId && this.threads[i].status !== Thread.STATUS_DONE) { + if ( + this.threads[i].target === opts.target && + this.threads[i].topBlock === topBlockId && + this.threads[i].status !== Thread.STATUS_DONE + ) { const blockContainer = opts.target.blocks; const opcode = blockContainer.getOpcode(blockContainer.getBlock(topBlockId)); diff --git a/test/unit/engine_runtime_tw.js b/test/unit/engine_runtime_tw.js index 84644178710..476b251aa35 100644 --- a/test/unit/engine_runtime_tw.js +++ b/test/unit/engine_runtime_tw.js @@ -320,3 +320,87 @@ test('_pushMonitors queues threads once targets are installed', t => { t.end(); }); + +const makeCommandBlock = id => ({ + id, + opcode: 'motion_movesteps', + fields: {}, + inputs: {}, + topLevel: true, + next: null, + parent: null, + shadow: false, + x: 0, + y: 0 +}); + +test('toggleScript is scoped to its target when block IDs collide', t => { + const rt = new Runtime(); + // Avoid compiling the fake single-block scripts. + rt.setCompilerOptions({enabled: false}); + + // Two sprites whose scripts share a top block ID. This happens when a block + // is copied between sprites without its ID being regenerated. + const spriteA = new Target(rt); + const spriteB = new Target(rt); + spriteA.blocks.createBlock(makeCommandBlock('dup')); + spriteB.blocks.createBlock(makeCommandBlock('dup')); + + // Start the script on sprite A. + rt.toggleScript('dup', {target: spriteA, stackClick: true}); + t.equal(rt.threads.length, 1, 'sprite A script started'); + t.equal(rt.threads[0].target, spriteA); + + // Clicking the same-ID script on sprite B must start B, not stop A. + rt.toggleScript('dup', {target: spriteB, stackClick: true}); + t.equal(rt.threads.length, 2, 'sprite B script started as a second thread'); + t.notOk(rt.threads[0].isKilled, 'sprite A thread was not stopped'); + t.equal(rt.threads[1].target, spriteB); + + // Toggling B again stops only B, leaving A running. + rt.toggleScript('dup', {target: spriteB, stackClick: true}); + t.notOk(rt.threads[0].isKilled, 'sprite A thread still running'); + t.ok(rt.threads[1].isKilled, 'sprite B thread stopped'); + + t.end(); +}); + +test('toggleScript scopes colliding block IDs using the editing target', t => { + const rt = new Runtime(); + rt.setCompilerOptions({enabled: false}); + + const spriteA = new Target(rt); + const spriteB = new Target(rt); + spriteA.blocks.createBlock(makeCommandBlock('dup')); + spriteB.blocks.createBlock(makeCommandBlock('dup')); + + rt.setEditingTarget(spriteA); + rt.toggleScript('dup', {stackClick: true}); + t.equal(rt.threads.length, 1, 'sprite A script started'); + t.equal(rt.threads[0].target, spriteA); + + rt.setEditingTarget(spriteB); + rt.toggleScript('dup', {stackClick: true}); + t.equal(rt.threads.length, 2, 'sprite B script started as a second thread'); + t.notOk(rt.threads[0].isKilled, 'sprite A thread was not stopped'); + t.equal(rt.threads[1].target, spriteB); + + t.end(); +}); + +test('toggleScript still toggles a running script off on the same target', t => { + const rt = new Runtime(); + rt.setCompilerOptions({enabled: false}); + + const sprite = new Target(rt); + sprite.blocks.createBlock(makeCommandBlock('top')); + + rt.toggleScript('top', {target: sprite, stackClick: true}); + t.equal(rt.threads.length, 1, 'script started'); + t.notOk(rt.threads[0].isKilled); + + rt.toggleScript('top', {target: sprite, stackClick: true}); + t.ok(rt.threads[0].isKilled, 'clicking again stopped the script'); + + t.end(); +}); From 9b72967e894c95c779fd15b0e1c60130c8923c78 Mon Sep 17 00:00:00 2001 From: Mist Date: Tue, 14 Jul 2026 15:53:51 +0100 Subject: [PATCH 102/106] Fix Origin icon renderer raw patches --- src/compiler/irgen.js | 30 ++++----- test/unit/tw_mistwarp_compiler_blocks.js | 77 ++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 5108c8993ba..2e0b8b4a8c5 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -249,16 +249,16 @@ class ScriptTreeGenerator { * @returns {IntermediateInput} Compiled input node for this input. */ descendInput (block, preserveStrings = false) { - const compilerExtension = this.runtime.compilerExtensions.get(block.opcode); - if (compilerExtension && compilerExtension.type !== 'command') { - return this.descendCompilerExtensionInput(block, compilerExtension); - } - const rawSourceType = RAW_SOURCE_REPORTERS.get(block.opcode); if (rawSourceType) { return this.descendRawSourceInput(block, rawSourceType); } + const compilerExtension = this.runtime.compilerExtensions.get(block.opcode); + if (compilerExtension && compilerExtension.type !== 'command') { + return this.descendCompilerExtensionInput(block, compilerExtension); + } + if (this.oldCompilerStub) { const oldCompilerResult = this.oldCompilerStub.descendInputFromNewCompiler(block); if (oldCompilerResult) { @@ -685,16 +685,6 @@ class ScriptTreeGenerator { * @returns {IntermediateStackBlock} Compiled node for this block. */ descendStackedBlock (block) { - const compilerExtension = this.runtime.compilerExtensions.get(block.opcode); - if (compilerExtension) { - if (compilerExtension.type === 'command') { - return this.descendCompilerExtensionStack(block, compilerExtension); - } - return new IntermediateStackBlock(StackOpcode.VISUAL_REPORT, { - input: this.descendCompilerExtensionInput(block, compilerExtension) - }); - } - if (RAW_SOURCE_COMMANDS.has(block.opcode)) { return new IntermediateStackBlock(StackOpcode.RAW_SOURCE, { fragments: this.descendRawSourceFragments(block) @@ -707,6 +697,16 @@ class ScriptTreeGenerator { }); } + const compilerExtension = this.runtime.compilerExtensions.get(block.opcode); + if (compilerExtension) { + if (compilerExtension.type === 'command') { + return this.descendCompilerExtensionStack(block, compilerExtension); + } + return new IntermediateStackBlock(StackOpcode.VISUAL_REPORT, { + input: this.descendCompilerExtensionInput(block, compilerExtension) + }); + } + if (this.oldCompilerStub) { const oldCompilerResult = this.oldCompilerStub.descendStackedBlockFromNewCompiler(block); if (oldCompilerResult) { diff --git a/test/unit/tw_mistwarp_compiler_blocks.js b/test/unit/tw_mistwarp_compiler_blocks.js index 99e7153a384..17dfdf868e9 100644 --- a/test/unit/tw_mistwarp_compiler_blocks.js +++ b/test/unit/tw_mistwarp_compiler_blocks.js @@ -181,3 +181,80 @@ test("legacy Mist's Utils patch blocks splice raw JavaScript", async t => { t.notMatch(source, /"globalThis\.__originPatch/, 'raw source is not emitted as a quoted statement'); t.notMatch(source, /executeInCompatibilityLayer/, 'patching does not use the runtime compatibility bridge'); }); + +test("Mist's Utils compiler API cannot alter raw patch syntax", async t => { + const vm = new VirtualMachine(); + vm.extensionManager.addBuiltinExtension('mistsutils', class { + getInfo () { + return { + id: 'mistsutils', + name: "Mist's Utils", + blocks: [{ + opcode: 'patchcommand', + blockType: 'command', + text: '[A]', + arguments: {A: {type: 'string'}} + }] + }; + } + patchcommand () {} + }); + const command = vm.exports.compiler.types.COMMAND; + vm.exports.compiler.register('mistsutils', { + patchcommand: { + type: command, + compile: ({input}) => input.raw('A') + } + }); + await vm.loadProject({ + targets: [{ + isStage: true, + name: 'Stage', + variables: {}, + lists: {}, + broadcasts: {}, + blocks: { + hat: {opcode: 'event_whenflagclicked', next: 'if', parent: null, inputs: {}, fields: {}, topLevel: true, x: 0, y: 0}, + if: { + opcode: 'mistsutils_patchcommand', + next: 'else', + parent: 'hat', + inputs: {A: [1, [10, 'if (true) globalThis.__originIcon = 1;']]}, + fields: {}, + topLevel: false + }, + else: { + opcode: 'mistsutils_patchcommand', + next: null, + parent: 'if', + inputs: {A: [1, [10, 'else globalThis.__originIcon = 2;']]}, + fields: {}, + topLevel: false + } + }, + comments: {}, + currentCostume: 0, + costumes: [], + sounds: [], + volume: 100, + layerOrder: 0, + tempo: 60, + videoTransparency: 50, + videoState: 'on', + textToSpeechLanguage: null + }], + monitors: [], + extensions: [], + meta: {semver: '3.0.0', vm: '3.0.0', agent: ''} + }); + + let source = ''; + JSGenerator.testingApparatus = {report: (generator, generated) => { + source += generated; + }}; + vm.runtime.precompile(); + JSGenerator.testingApparatus = null; + + t.match(source, /if \(true\) globalThis\.__originIcon = 1;\s*else globalThis\.__originIcon = 2;/); + t.notMatch(source, /;;\s*else/, 'raw commands are not terminated twice'); +}); From 04bbd4e931481477631bf8a41947be6b44b66f44 Mon Sep 17 00:00:00 2001 From: Mist Date: Tue, 14 Jul 2026 16:28:12 +0100 Subject: [PATCH 103/106] Compile Mist utils and add native patching --- src/blocks/scratch3_operators.js | 21 +++ src/blocks/scratch3_sensing.js | 2 + src/compiler/irgen.js | 19 ++- src/compiler/jsgen.js | 1 + src/compiler/mists-utils.js | 69 +++++++++ src/engine/runtime.js | 7 + src/extension-support/extension-manager.js | 1 + src/extensions/mistwarp_patching/index.js | 42 ++++++ test/unit/blocks_operators.js | 7 + test/unit/tw_block_sensing.js | 8 + test/unit/tw_compiler_extension_api.js | 40 ++++- test/unit/tw_mistwarp_compiler_blocks.js | 166 +++++++++++++++++++-- 12 files changed, 362 insertions(+), 21 deletions(-) create mode 100644 src/compiler/mists-utils.js create mode 100644 src/extensions/mistwarp_patching/index.js diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js index e0fb9bf2f12..a6f4aa1459e 100644 --- a/src/blocks/scratch3_operators.js +++ b/src/blocks/scratch3_operators.js @@ -46,6 +46,9 @@ class Scratch3OperatorsBlocks { operator_repeat: this.repeat, operator_change_case: this.changeCase, operator_trim: this.trim, + operator_clamp: this.clamp, + operator_min: this.min, + operator_max: this.max, operator_mod: this.mod, operator_pi: this.pi, operator_newline: this.newline, @@ -90,6 +93,24 @@ class Scratch3OperatorsBlocks { return result; } + clamp (args) { + return Math.min(Math.max(Cast.toNumber(args.NUM), Cast.toNumber(args.MIN)), Cast.toNumber(args.MAX)); + } + + min (args) { + const count = operandCount(args); + let result = Infinity; + for (let i = 1; i <= count; i++) result = Math.min(result, Cast.toNumber(args[`NUM${i}`])); + return result; + } + + max (args) { + const count = operandCount(args); + let result = -Infinity; + for (let i = 1; i <= count; i++) result = Math.max(result, Cast.toNumber(args[`NUM${i}`])); + return result; + } + lt (args) { return Cast.compare(args.OPERAND1, args.OPERAND2) < 0; } diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js index 26f2247da6b..287de120dfb 100644 --- a/src/blocks/scratch3_sensing.js +++ b/src/blocks/scratch3_sensing.js @@ -73,6 +73,8 @@ class Scratch3SensingBlocks { sensing_answer: this.getAnswer, sensing_username: this.getUsername, sensing_userid: () => {}, // legacy no-op block + sensing_stagewidth: () => this.runtime.stageWidth, + sensing_stageheight: () => this.runtime.stageHeight, sensing_online: this.isOnline }; } diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 2e0b8b4a8c5..7229ee77d73 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -34,13 +34,20 @@ const COMPILER_INPUT_TYPES = { const RAW_SOURCE_COMMANDS = new Set([ 'mistsutils_patchcommand', 'mistsutils_patchcommand2', - 'mistsutils_patchcommand3' + 'mistsutils_patchcommand3', + 'patching_jscommand', + 'patching_jscommand2', + 'patching_jscommand3' ]); const RAW_SOURCE_REPORTERS = new Map([ ['mistsutils_patchreporter', InputType.ANY], ['mistsutils_patchreporter2', InputType.ANY], ['mistsutils_patchreporter3', InputType.ANY], - ['mistsutils_patchboolean', InputType.BOOLEAN] + ['mistsutils_patchboolean', InputType.BOOLEAN], + ['patching_jsreporter', InputType.ANY], + ['patching_jsreporter2', InputType.ANY], + ['patching_jsreporter3', InputType.ANY], + ['patching_jsboolean', InputType.BOOLEAN] ]); /** @@ -1434,7 +1441,10 @@ class ScriptTreeGenerator { * @returns {IntermediateInput[]} */ descendRawSourceFragments (block) { - return ['A', 'B', 'C'] + const variadic = Object.keys(block.inputs) + .filter(name => /^ARG\d+$/.test(name)) + .sort((a, b) => Number(a.substring(3)) - Number(b.substring(3))); + return (variadic.length ? variadic : ['A', 'B', 'C']) .filter(name => block.inputs[name]) .map(name => this.descendInputOfBlock(block, name, true)); } @@ -1462,7 +1472,8 @@ class ScriptTreeGenerator { return new IntermediateInput(InputOpcode.EXTENSION, COMPILER_INPUT_TYPES[compiler.type], { compiler, inputs, - fields + fields, + mutation: block.mutation || {} }); } diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index 630b435daab..f99c0b93ab8 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -1187,6 +1187,7 @@ class JSGenerator { const source = node.compiler.compile({ input, field: name => JSON.stringify(node.fields[name] ?? ''), + mutation: node.mutation, runtime: 'runtime', target: 'target', stage: 'stage' diff --git a/src/compiler/mists-utils.js b/src/compiler/mists-utils.js new file mode 100644 index 00000000000..8b4b1a8b5cd --- /dev/null +++ b/src/compiler/mists-utils.js @@ -0,0 +1,69 @@ +const c = (type, compile) => Object.freeze({type, compile}); + +const mistsUtils = Object.freeze({ + notequals: c('boolean', ({input: i}) => `(${i.string('A')} !== ${i.string('B')})`), + equals: c('boolean', ({input: i}) => `(${i.string('A')} === ${i.string('B')})`), + greaterorequal: c('boolean', ({input: i}) => `(${i.number('A')} >= ${i.number('B')})`), + lessthanorequal: c('boolean', ({input: i}) => `(${i.number('A')} <= ${i.number('B')})`), + compare: c('boolean', ({input: i}) => `(${i.number('A')} ${i.raw('C')} ${i.number('B')})`), + power: c('number', ({input: i}) => `Math.pow(${i.number('A')}, ${i.number('B')})`), + round: c('number', ({input: i}) => `(Math.round(${i.number('A')} / ${i.number('B')}) * ${i.number('B')})`), + clamp: c('number', ({input: i}) => `Math.min(Math.max(${i.number('A')}, ${i.number('B')}), ${i.number('C')})`), + min: c('number', ({input: i}) => `Math.min(${i.number('A')}, ${i.number('B')})`), + max: c('number', ({input: i}) => `Math.max(${i.number('A')}, ${i.number('B')})`), + interpolate: c('number', ({input: i}) => + `(${i.number('B')} + ((${i.number('C')} - ${i.number('B')}) / ${i.number('A')}))`), + ifthen: c('string', ({input: i}) => `(${i.boolean('A')} ? ${i.string('B')} : ${i.string('C')})`), + letters: c('string', ({input: i}) => + `${i.string('C')}.substring(Math.max(0, ${i.number('A')} - 1), ` + + `Math.min(${i.number('B')}, ${i.string('C')}.length))`), + starts: c('boolean', ({input: i}) => `${i.string('A')}.startsWith(${i.string('B')})`), + ends: c('boolean', ({input: i}) => `${i.string('A')}.endsWith(${i.string('B')})`), + toUnicode: c('number', ({input: i}) => `${i.string('A')}.charCodeAt(0)`), + replace: c('string', ({input: i}) => `${i.string('A')}.replace(${i.string('C')}, ${i.string('B')})`), + replaceall: c('string', ({input: i}) => `${i.string('A')}.replaceAll(${i.string('C')}, ${i.string('B')})`), + alltextAfterString: c('string', ({input: i}) => + `${i.string('A')}.substring(${i.string('A')}.indexOf(${i.string('B')}) + 1)`), + alltextBeforeString: c('string', ({input: i}) => `${i.string('A')}.split(${i.string('B')}, 1)[0]`), + split: c('string', ({input: i}) => `JSON.stringify(${i.string('A')}.split(${i.string('B')}))`), + splitarray: c('any', ({input: i}) => `${i.string('A')}.split(${i.string('B')})`), + length: c('number', ({input: i}) => `${i('A')}.length`), + item: c('string', ({input: i}) => `${i('A')}.split(${i.string('B')})[${i.number('C')}]`), + squarebrackets: c('any', ({input: i}) => `${i('A')}[${i.string('B')}]`), + jsonparse: c('any', ({input: i}) => `JSON.parse(${i.string('A')})`), + jsonstringify: c('string', ({input: i}) => `JSON.stringify(${i('A')})`), + isnumber: c('boolean', ({input: i}) => `(Number(${i.string('A')}) == ${i.string('A')})`), + isstring: c('boolean', ({input: i}) => `(String(${i.string('A')}) == ${i.string('A')})`), + isboolean: c('boolean', ({input: i}) => `(${i.string('A')} == "true" || ${i.string('A')} == "false")`), + tostring: c('string', ({input: i}) => i.string('A')), + tonumber: c('number', ({input: i}) => `(isNaN(Number(${i.string('A')})) ? 0 : Number(${i.string('A')}))`), + toboolean: c('boolean', ({input: i}) => + `(${i.string('A')} == "true" || ${i.string('A')} == "1" || ${i.string('A')} == "yes")`), + true: c('boolean', () => 'true'), + false: c('boolean', () => 'false'), + isPackaged: c('boolean', () => `(typeof window.scaffolding === 'object')`), + performancenow: c('number', () => 'performance.now()'), + stagewidth: c('number', ({runtime}) => `${runtime}.stageWidth`), + stageheight: c('number', ({runtime}) => `${runtime}.stageHeight`), + newline: c('string', () => '"\\n"'), + pi: c('number', () => 'Math.PI'), + e: c('number', () => 'Math.E'), + infinity: c('number', () => 'Infinity'), + MaxInt: c('number', () => 'Number.MAX_SAFE_INTEGER') +}); + +const variadic = (name, input, mutation) => { + const count = Math.max(2, parseInt(mutation.itemcount, 10) || 2); + return `Math.${name}(${Array.from({length: count}, (_, index) => input.number(`NUM${index + 1}`)).join(',')})`; +}; + +const core = Object.freeze({ + sensing_stagewidth: c('number', ({runtime}) => `${runtime}.stageWidth`), + sensing_stageheight: c('number', ({runtime}) => `${runtime}.stageHeight`), + operator_clamp: c('number', ({input: i}) => + `Math.min(Math.max(${i.number('NUM')}, ${i.number('MIN')}), ${i.number('MAX')})`), + operator_min: c('number', ({input, mutation}) => variadic('min', input, mutation)), + operator_max: c('number', ({input, mutation}) => variadic('max', input, mutation)) +}); + +module.exports = {mistsUtils, core}; diff --git a/src/engine/runtime.js b/src/engine/runtime.js index aa30442edc6..065ca31edf3 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -10,6 +10,7 @@ const Profiler = require('./profiler'); const Sequencer = require('./sequencer'); const execute = require('./execute.js'); const compilerExecute = require('../compiler/jsexecute'); +const {mistsUtils: mistsUtilsCompiler, core: mistWarpCompiler} = require('../compiler/mists-utils'); const ScratchBlocksConstants = require('./scratch-blocks-constants'); const TargetType = require('../extension-support/target-type'); const Thread = require('./thread'); @@ -472,6 +473,12 @@ class Runtime extends EventEmitter { // Compiler implementations registered by unsandboxed extensions. this.compilerExtensions = new Map(); + for (const [opcode, compiler] of Object.entries(mistsUtilsCompiler)) { + this.compilerExtensions.set(`mistsutils_${opcode}`, compiler); + } + for (const [opcode, compiler] of Object.entries(mistWarpCompiler)) { + this.compilerExtensions.set(opcode, compiler); + } this.debug = false; diff --git a/src/extension-support/extension-manager.js b/src/extension-support/extension-manager.js index e5f8759c9af..46d2ee7cea8 100644 --- a/src/extension-support/extension-manager.js +++ b/src/extension-support/extension-manager.js @@ -25,6 +25,7 @@ const defaultBuiltinExtensions = { makeymakey: () => require('../extensions/scratch3_makeymakey'), boost: () => require('../extensions/scratch3_boost'), gdxfor: () => require('../extensions/scratch3_gdx_for'), + patching: () => require('../extensions/mistwarp_patching'), // tw: core extension tw: () => require('../extensions/tw') }; diff --git a/src/extensions/mistwarp_patching/index.js b/src/extensions/mistwarp_patching/index.js new file mode 100644 index 00000000000..ab29d42d9c8 --- /dev/null +++ b/src/extensions/mistwarp_patching/index.js @@ -0,0 +1,42 @@ +const ArgumentType = require('../../extension-support/argument-type'); +const BlockType = require('../../extension-support/block-type'); + +const input = defaultValue => ({ + type: ArgumentType.STRING, + defaultValue +}); + +const block = (opcode, blockType, text, defaults) => ({ + opcode, + blockType, + text, + arguments: Object.fromEntries(defaults.map((value, index) => { + const name = `ARG${index + 1}`; + return [name, input(value)]; + })), + allowDropAnywhere: blockType === BlockType.REPORTER, + func: 'unsupported' +}); + +class PatchingBlocks { + getInfo () { + return { + id: 'patching', + name: 'Patching', + color1: '#9966ff', + color2: '#855cd6', + color3: '#774dcb', + blocks: [ + block('jsreporter', BlockType.REPORTER, 'js [ARG1]', ['1 * 3']), + block('jsboolean', BlockType.BOOLEAN, 'js [ARG1]', ['1 === 1']), + block('jscommand', BlockType.COMMAND, 'js [ARG1]', ['console.log("hello")']) + ] + }; + } + + unsupported () { + throw new Error('Patching blocks require the compiler'); + } +} + +module.exports = PatchingBlocks; diff --git a/test/unit/blocks_operators.js b/test/unit/blocks_operators.js index b670e11d350..e5bb3d78d85 100644 --- a/test/unit/blocks_operators.js +++ b/test/unit/blocks_operators.js @@ -32,6 +32,13 @@ test('divide', t => { t.end(); }); +test('MistWarp numeric helpers', t => { + t.strictEqual(blocks.clamp({NUM: 12, MIN: 0, MAX: 10}), 10); + t.strictEqual(blocks.min({NUM1: 8, NUM2: 3, NUM3: 5, mutation: {itemcount: 3}}), 3); + t.strictEqual(blocks.max({NUM1: 8, NUM2: 3, NUM3: 12, mutation: {itemcount: 3}}), 12); + t.end(); +}); + test('lt', t => { t.strictEqual(blocks.lt({OPERAND1: '1', OPERAND2: '2'}), true); t.strictEqual(blocks.lt({OPERAND1: '2', OPERAND2: '1'}), false); diff --git a/test/unit/tw_block_sensing.js b/test/unit/tw_block_sensing.js index 779c8a14119..4a46e396adc 100644 --- a/test/unit/tw_block_sensing.js +++ b/test/unit/tw_block_sensing.js @@ -26,3 +26,11 @@ test('isOnline', t => { t.end(); }); + +test('stage dimensions', t => { + const rt = new Runtime(); + const primitives = new Scratch3SensingBlocks(rt).getPrimitives(); + t.equal(primitives.sensing_stagewidth(), rt.stageWidth); + t.equal(primitives.sensing_stageheight(), rt.stageHeight); + t.end(); +}); diff --git a/test/unit/tw_compiler_extension_api.js b/test/unit/tw_compiler_extension_api.js index c408f537468..bf170d64174 100644 --- a/test/unit/tw_compiler_extension_api.js +++ b/test/unit/tw_compiler_extension_api.js @@ -8,7 +8,7 @@ test('compiler extension API emits native code', async t => { compiler.register('compilerTest', { double: { type: compiler.types.NUMBER, - compile: ({input}) => `(${input.number('VALUE')} * 2)` + compile: ({input, mutation}) => `(${input.number('VALUE')} * ${mutation.factor})` } }); vm.extensionManager.addBuiltinExtension('compilerTest', class { @@ -37,9 +37,33 @@ test('compiler extension API emits native code', async t => { lists: {}, broadcasts: {}, blocks: { - hat: {opcode: 'event_whenflagclicked', next: 'say', parent: null, inputs: {}, fields: {}, topLevel: true, x: 0, y: 0}, - say: {opcode: 'looks_say', next: null, parent: 'hat', inputs: {MESSAGE: [2, 'double']}, fields: {}, topLevel: false}, - double: {opcode: 'compilerTest_double', next: null, parent: 'say', inputs: {VALUE: [1, [4, '3']]}, fields: {}, topLevel: false} + hat: { + opcode: 'event_whenflagclicked', + next: 'say', + parent: null, + inputs: {}, + fields: {}, + topLevel: true, + x: 0, + y: 0 + }, + say: { + opcode: 'looks_say', + next: null, + parent: 'hat', + inputs: {MESSAGE: [2, 'double']}, + fields: {}, + topLevel: false + }, + double: { + opcode: 'compilerTest_double', + next: null, + parent: 'say', + inputs: {VALUE: [1, [4, '3']]}, + fields: {}, + mutation: {factor: '2'}, + topLevel: false + } }, comments: {}, currentCostume: 0, @@ -66,4 +90,12 @@ test('compiler extension API emits native code', async t => { t.match(source, /3 \* 2/, 'custom reporter was compiled directly'); t.notMatch(source, /compilerTest_double/, 'compatibility bridge was not used'); + + const input = name => name; + input.number = name => name; + t.equal( + vm.runtime.compilerExtensions.get('operator_min').compile({input, mutation: {itemcount: '3'}}), + 'Math.min(NUM1,NUM2,NUM3)', + 'extendable compiler inputs follow their mutation' + ); }); diff --git a/test/unit/tw_mistwarp_compiler_blocks.js b/test/unit/tw_mistwarp_compiler_blocks.js index 17dfdf868e9..621d624f2fb 100644 --- a/test/unit/tw_mistwarp_compiler_blocks.js +++ b/test/unit/tw_mistwarp_compiler_blocks.js @@ -13,12 +13,23 @@ test('MistWarp text and coordinate blocks compile directly', async t => { lists: {list: ['items', []]}, broadcasts: {}, blocks: { - hat: {opcode: 'event_whenflagclicked', next: 'point', parent: null, inputs: {}, fields: {}, topLevel: true, x: 0, y: 0}, + hat: { + opcode: 'event_whenflagclicked', + next: 'point', + parent: null, + inputs: {}, + fields: {}, + topLevel: true, + x: 0, + y: 0 + }, point: { opcode: 'motion_pointtowards_xyfrom', next: 'print', parent: 'hat', - inputs: {X: [1, [4, '10']], Y: [1, [4, '10']], FROMX: [1, [4, '0']], FROMY: [1, [4, '0']]}, + inputs: { + X: [1, [4, '10']], Y: [1, [4, '10']], FROMX: [1, [4, '0']], FROMY: [1, [4, '0']] + }, fields: {}, topLevel: false }, @@ -38,8 +49,17 @@ test('MistWarp text and coordinate blocks compile directly', async t => { fields: {}, topLevel: false }, - say: {opcode: 'looks_say', next: 'setList', parent: 'print', inputs: {MESSAGE: [2, 'costumes']}, fields: {}, topLevel: false}, - costumes: {opcode: 'looks_costumes', next: null, parent: 'say', inputs: {}, fields: {}, topLevel: false}, + say: { + opcode: 'looks_say', + next: 'setList', + parent: 'print', + inputs: {MESSAGE: [2, 'costumes']}, + fields: {}, + topLevel: false + }, + costumes: { + opcode: 'looks_costumes', next: null, parent: 'say', inputs: {}, fields: {}, topLevel: false + }, setList: { opcode: 'data_set_list_to_array', next: 'sayList', @@ -48,7 +68,14 @@ test('MistWarp text and coordinate blocks compile directly', async t => { fields: {LIST: ['items', 'list']}, topLevel: false }, - sayList: {opcode: 'looks_say', next: null, parent: 'setList', inputs: {MESSAGE: [2, 'listAs']}, fields: {}, topLevel: false}, + sayList: { + opcode: 'looks_say', + next: null, + parent: 'setList', + inputs: {MESSAGE: [2, 'listAs']}, + fields: {}, + topLevel: false + }, listAs: { opcode: 'data_get_list_as', next: null, @@ -75,7 +102,7 @@ test('MistWarp text and coordinate blocks compile directly', async t => { }); let source = ''; - JSGenerator.testingApparatus = {report: (generator, generated) => { + JSGenerator.testingApparatus = {report: (_generator, generated) => { source += generated; }}; vm.runtime.precompile(); @@ -92,7 +119,9 @@ test('MistWarp text and coordinate blocks compile directly', async t => { test('compiled list helpers preserve case-sensitive mode', t => { const globalState = {thread: {target: {runtime: {runtimeOptions: {caseSensitiveLists: true}}}}}; - const makeHelper = source => new Function('globalState', `${source}; return ${source.match(/const (\w+)/)[1]};`)(globalState); + const makeHelper = source => new Function( + 'globalState', `${source}; return ${source.match(/const (\w+)/)[1]};` + )(globalState); const contains = makeHelper(runtimeFunctions.listContains); const indexOf = makeHelper(runtimeFunctions.listIndexOf); const list = {value: ['jump', 'Jump']}; @@ -127,10 +156,19 @@ test("legacy Mist's Utils patch blocks splice raw JavaScript", async t => { lists: {}, broadcasts: {}, blocks: { - hat: {opcode: 'event_whenflagclicked', next: 'patch', parent: null, inputs: {}, fields: {}, topLevel: true, x: 0, y: 0}, + hat: { + opcode: 'event_whenflagclicked', + next: 'patch', + parent: null, + inputs: {}, + fields: {}, + topLevel: true, + x: 0, + y: 0 + }, patch: { opcode: 'mistsutils_patchcommand3', - next: null, + next: 'nativePatch', parent: 'hat', inputs: { A: [1, [10, 'globalThis.__originPatch = ']], @@ -140,6 +178,19 @@ test("legacy Mist's Utils patch blocks splice raw JavaScript", async t => { fields: {}, topLevel: false }, + nativePatch: { + opcode: 'patching_jscommand', + next: null, + parent: 'patch', + inputs: { + ARG1: [1, [10, 'globalThis.__nativePatch = ']], + ARG2: [1, [10, '4']], + ARG3: [1, [10, ';']] + }, + fields: {}, + mutation: {tagName: 'mutation', children: [], itemcount: '3'}, + topLevel: false + }, sum: { opcode: 'operator_add', next: null, @@ -162,12 +213,12 @@ test("legacy Mist's Utils patch blocks splice raw JavaScript", async t => { textToSpeechLanguage: null }], monitors: [], - extensions: [], + extensions: ['patching'], meta: {semver: '3.0.0', vm: '3.0.0', agent: ''} }); let source = ''; - JSGenerator.testingApparatus = {report: (generator, generated) => { + JSGenerator.testingApparatus = {report: (_generator, generated) => { source += generated; }}; vm.runtime.precompile(); @@ -178,6 +229,7 @@ test("legacy Mist's Utils patch blocks splice raw JavaScript", async t => { /globalThis\.__originPatch = \(toNotNaN\(\(1 \+ 2\)\) \+ 3\);/, 'literal source and variadic reporters are joined' ); + t.match(source, /globalThis\.__nativePatch = 4;/, 'native Patching blocks splice JavaScript'); t.notMatch(source, /"globalThis\.__originPatch/, 'raw source is not emitted as a quoted statement'); t.notMatch(source, /executeInCompatibilityLayer/, 'patching does not use the runtime compatibility bridge'); }); @@ -214,7 +266,16 @@ test("Mist's Utils compiler API cannot alter raw patch syntax", async t => { lists: {}, broadcasts: {}, blocks: { - hat: {opcode: 'event_whenflagclicked', next: 'if', parent: null, inputs: {}, fields: {}, topLevel: true, x: 0, y: 0}, + hat: { + opcode: 'event_whenflagclicked', + next: 'if', + parent: null, + inputs: {}, + fields: {}, + topLevel: true, + x: 0, + y: 0 + }, if: { opcode: 'mistsutils_patchcommand', next: 'else', @@ -249,7 +310,7 @@ test("Mist's Utils compiler API cannot alter raw patch syntax", async t => { }); let source = ''; - JSGenerator.testingApparatus = {report: (generator, generated) => { + JSGenerator.testingApparatus = {report: (_generator, generated) => { source += generated; }}; vm.runtime.precompile(); @@ -258,3 +319,82 @@ test("Mist's Utils compiler API cannot alter raw patch syntax", async t => { t.match(source, /if \(true\) globalThis\.__originIcon = 1;\s*else globalThis\.__originIcon = 2;/); t.notMatch(source, /;;\s*else/, 'raw commands are not terminated twice'); }); + +test("Mist's Utils 5.9 blocks use native compiler cases", async t => { + const vm = new VirtualMachine(); + vm.extensionManager.addBuiltinExtension('mistsutils', class { + getInfo () { + return { + id: 'mistsutils', + name: "Mist's Utils", + blocks: [{ + opcode: 'starts', + blockType: 'Boolean', + text: '[A] starts with [B]', + arguments: {A: {type: 'string'}, B: {type: 'string'}} + }] + }; + } + starts () {} + }); + await vm.loadProject({ + targets: [{ + isStage: true, + name: 'Stage', + variables: {}, + lists: {}, + broadcasts: {}, + blocks: { + hat: { + opcode: 'event_whenflagclicked', + next: 'if', + parent: null, + inputs: {}, + fields: {}, + topLevel: true, + x: 0, + y: 0 + }, + if: { + opcode: 'control_if', + next: null, + parent: 'hat', + inputs: {CONDITION: [2, 'report'], SUBSTACK: [2, null]}, + fields: {}, + topLevel: false + }, + report: { + opcode: 'mistsutils_starts', + next: null, + parent: 'if', + inputs: {A: [1, [10, 'origin']], B: [1, [10, 'ori']]}, + fields: {}, + topLevel: false + } + }, + comments: {}, + currentCostume: 0, + costumes: [], + sounds: [], + volume: 100, + layerOrder: 0, + tempo: 60, + videoTransparency: 50, + videoState: 'on', + textToSpeechLanguage: null + }], + monitors: [], + extensions: [], + meta: {semver: '3.0.0', vm: '3.0.0', agent: ''} + }); + + let source = ''; + JSGenerator.testingApparatus = {report: (_generator, generated) => { + source += generated; + }}; + vm.runtime.precompile(); + JSGenerator.testingApparatus = null; + + t.match(source, /"origin"\.startsWith\("ori"\)/); + t.notMatch(source, /oldCompiler|executeInCompatibilityLayer/); +}); From 81e0c579932206c2ad1b829cc4c751111f0b1add Mon Sep 17 00:00:00 2001 From: Mist Date: Tue, 14 Jul 2026 16:31:05 +0100 Subject: [PATCH 104/106] Migrate legacy patch blocks to Patching --- src/serialization/sb3.js | 20 ++++++++++++++++++++ test/unit/tw_mistwarp_compiler_blocks.js | 20 +++++--------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/serialization/sb3.js b/src/serialization/sb3.js index f0913b8a903..63d3423362c 100644 --- a/src/serialization/sb3.js +++ b/src/serialization/sb3.js @@ -125,6 +125,16 @@ for (const opcode in VANILLA_CONSTANTS) { CONSTANT_OPCODE_BY_NAME[VANILLA_CONSTANTS[opcode].name] = opcode; } +const MIST_PATCHING_OPCODES = { + mistsutils_patchreporter: ['patching_jsreporter', 1], + mistsutils_patchreporter2: ['patching_jsreporter', 2], + mistsutils_patchreporter3: ['patching_jsreporter', 3], + mistsutils_patchboolean: ['patching_jsboolean', 1], + mistsutils_patchcommand: ['patching_jscommand', 1], + mistsutils_patchcommand2: ['patching_jscommand', 2], + mistsutils_patchcommand3: ['patching_jscommand', 3] +}; + const collapseConstants = function (blocks) { for (const id in blocks) { if (!hasOwnProperty.call(blocks, id)) continue; @@ -1298,6 +1308,16 @@ const deserializeBlocks = function (blocks) { deserializeInputDesc(block, null, false, blocks); continue; } + const patching = MIST_PATCHING_OPCODES[block.opcode]; + if (patching) { + block.opcode = patching[0]; + block.inputs = Object.fromEntries(Object.entries(block.inputs).map(([name, input]) => { + const newName = /^[ABC]$/.test(name) ? `ARG${name.charCodeAt(0) - 64}` : name; + if (input && !Array.isArray(input)) input.name = newName; + return [newName, input]; + })); + block.mutation = {tagName: 'mutation', children: [], itemcount: String(patching[1])}; + } block.id = blockId; // add id back to block since it wasn't serialized block.inputs = deserializeInputs(block.inputs, blockId, blocks); block.fields = deserializeFields(block.fields); diff --git a/test/unit/tw_mistwarp_compiler_blocks.js b/test/unit/tw_mistwarp_compiler_blocks.js index 621d624f2fb..a0fcfa4b113 100644 --- a/test/unit/tw_mistwarp_compiler_blocks.js +++ b/test/unit/tw_mistwarp_compiler_blocks.js @@ -133,21 +133,6 @@ test('compiled list helpers preserve case-sensitive mode', t => { test("legacy Mist's Utils patch blocks splice raw JavaScript", async t => { const vm = new VirtualMachine(); - vm.extensionManager.addBuiltinExtension('mistsutils', class { - getInfo () { - return { - id: 'mistsutils', - name: "Mist's Utils", - blocks: [{ - opcode: 'patchcommand3', - blockType: 'command', - text: '[A] [B] [C]', - arguments: {A: {type: 'string'}, B: {type: 'string'}, C: {type: 'string'}} - }] - }; - } - patchcommand3 () {} - }); await vm.loadProject({ targets: [{ isStage: true, @@ -224,6 +209,11 @@ test("legacy Mist's Utils patch blocks splice raw JavaScript", async t => { vm.runtime.precompile(); JSGenerator.testingApparatus = null; + t.ok(vm.extensionManager.isExtensionLoaded('patching'), 'legacy blocks load built-in Patching'); + t.notOk(vm.extensionManager.isExtensionLoaded('mistsutils'), "Mist's Utils is not loaded"); + const migrated = vm.runtime.getTargetForStage().blocks.getBlock('patch'); + t.equal(migrated.opcode, 'patching_jscommand', 'legacy opcode is migrated'); + t.equal(migrated.mutation.itemcount, '3', 'legacy arity is preserved'); t.match( source, /globalThis\.__originPatch = \(toNotNaN\(\(1 \+ 2\)\) \+ 3\);/, From 3688a05e78972bd4af81cc8de0cb860f0c28e019 Mon Sep 17 00:00:00 2001 From: Mist Date: Tue, 14 Jul 2026 19:01:02 +0100 Subject: [PATCH 105/106] support originOS and mist's utils patching --- src/compiler/irgen.js | 20 +- src/compiler/jsgen.js | 20 +- src/compiler/mists-utils.js | 28 +-- test/unit/tw_mistwarp_compiler_blocks.js | 241 ++++++++++++++++++++++- 4 files changed, 284 insertions(+), 25 deletions(-) diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 7229ee77d73..921f6a585f5 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -805,12 +805,12 @@ class ScriptTreeGenerator { }, this.analyzeLoop()); case 'control_switch': return new IntermediateStackBlock(StackOpcode.CONTROL_SWITCH, { - value: this.descendInputOfBlock(block, 'VALUE').toType(InputType.STRING), + value: this.descendSwitchValue(block), do: this.descendSubstack(block, 'SUBSTACK') }); case 'control_case': return new IntermediateStackBlock(StackOpcode.CONTROL_CASE, { - value: this.descendInputOfBlock(block, 'VALUE').toType(InputType.STRING), + value: this.descendSwitchValue(block), do: this.descendSubstack(block, 'SUBSTACK') }); case 'control_default': @@ -821,7 +821,7 @@ class ScriptTreeGenerator { return new IntermediateStackBlock(StackOpcode.CONTROL_BREAK); case 'control_case_fallthrough': return new IntermediateStackBlock(StackOpcode.CONTROL_CASE_FALLTHROUGH, { - value: this.descendInputOfBlock(block, 'VALUE').toType(InputType.STRING) + value: this.descendSwitchValue(block) }); case 'control_clear_counter': return new IntermediateStackBlock(StackOpcode.CONTROL_CLEAR_COUNTER); @@ -1434,6 +1434,20 @@ class ScriptTreeGenerator { }, true); } + /** + * Raw-source switch and case values stay uncoerced so spliced `case x:` + * statements and the discriminant compare with === on the original values. + * @param {*} block Switch, case, or fallthrough block. + * @returns {IntermediateInput} + */ + descendSwitchValue (block) { + const value = this.descendInputOfBlock(block, 'VALUE'); + if (value.opcode === InputOpcode.RAW_SOURCE) { + return value; + } + return value.toType(InputType.STRING); + } + /** * Preserve the source-splicing behavior used by legacy Mist's Utils projects. * Literal text is JavaScript source; reporter inputs are compiled expressions. diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index f99c0b93ab8..129282ac6e1 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -207,8 +207,12 @@ class JSGenerator { case InputOpcode.EXTENSION: return this.generateExtensionCompilerSource(node); - case InputOpcode.RAW_SOURCE: - return this.generateRawSource(node.fragments); + case InputOpcode.RAW_SOURCE: { + // Parenthesized so casts and operators cannot rebind the spliced expression. + // ("" + a + 1) would concatenate; ("" + (a + 1)) adds first, like the old compiler. + const source = this.generateRawSource(node.fragments); + return source === '' ? source : `(${source})`; + } case InputOpcode.CONSTANT: if (block.isAlwaysType(InputType.NUMBER)) { @@ -1199,15 +1203,17 @@ class JSGenerator { /** * Join raw JavaScript source fragments without quoting literal text. * Non-literal inputs remain ordinary compiled JavaScript expressions. + * Nested patch blocks splice verbatim: their source may be a partial + * fragment such as `}${`, which parentheses would turn into a syntax error. * @param {IntermediateInput[]} fragments Source fragments. * @returns {string} JavaScript source. */ generateRawSource (fragments) { - return fragments.map(fragment => ( - fragment.opcode === InputOpcode.CONSTANT ? - `${fragment.inputs.value}` : - this.descendInput(fragment) - )).join(''); + return fragments.map(fragment => { + if (fragment.opcode === InputOpcode.CONSTANT) return `${fragment.inputs.value}`; + if (fragment.opcode === InputOpcode.RAW_SOURCE) return this.generateRawSource(fragment.inputs.fragments); + return this.descendInput(fragment); + }).join(''); } getScriptFactoryName () { diff --git a/src/compiler/mists-utils.js b/src/compiler/mists-utils.js index 8b4b1a8b5cd..a4a4eeaa6a2 100644 --- a/src/compiler/mists-utils.js +++ b/src/compiler/mists-utils.js @@ -15,21 +15,21 @@ const mistsUtils = Object.freeze({ `(${i.number('B')} + ((${i.number('C')} - ${i.number('B')}) / ${i.number('A')}))`), ifthen: c('string', ({input: i}) => `(${i.boolean('A')} ? ${i.string('B')} : ${i.string('C')})`), letters: c('string', ({input: i}) => - `${i.string('C')}.substring(Math.max(0, ${i.number('A')} - 1), ` + - `Math.min(${i.number('B')}, ${i.string('C')}.length))`), - starts: c('boolean', ({input: i}) => `${i.string('A')}.startsWith(${i.string('B')})`), - ends: c('boolean', ({input: i}) => `${i.string('A')}.endsWith(${i.string('B')})`), - toUnicode: c('number', ({input: i}) => `${i.string('A')}.charCodeAt(0)`), - replace: c('string', ({input: i}) => `${i.string('A')}.replace(${i.string('C')}, ${i.string('B')})`), - replaceall: c('string', ({input: i}) => `${i.string('A')}.replaceAll(${i.string('C')}, ${i.string('B')})`), + `(${i.string('C')}).substring(Math.max(0, ${i.number('A')} - 1), ` + + `Math.min(${i.number('B')}, (${i.string('C')}).length))`), + starts: c('boolean', ({input: i}) => `(${i.string('A')}).startsWith(${i.string('B')})`), + ends: c('boolean', ({input: i}) => `(${i.string('A')}).endsWith(${i.string('B')})`), + toUnicode: c('number', ({input: i}) => `(${i.string('A')}).charCodeAt(0)`), + replace: c('string', ({input: i}) => `(${i.string('A')}).replace(${i.string('C')}, ${i.string('B')})`), + replaceall: c('string', ({input: i}) => `(${i.string('A')}).replaceAll(${i.string('C')}, ${i.string('B')})`), alltextAfterString: c('string', ({input: i}) => - `${i.string('A')}.substring(${i.string('A')}.indexOf(${i.string('B')}) + 1)`), - alltextBeforeString: c('string', ({input: i}) => `${i.string('A')}.split(${i.string('B')}, 1)[0]`), - split: c('string', ({input: i}) => `JSON.stringify(${i.string('A')}.split(${i.string('B')}))`), - splitarray: c('any', ({input: i}) => `${i.string('A')}.split(${i.string('B')})`), - length: c('number', ({input: i}) => `${i('A')}.length`), - item: c('string', ({input: i}) => `${i('A')}.split(${i.string('B')})[${i.number('C')}]`), - squarebrackets: c('any', ({input: i}) => `${i('A')}[${i.string('B')}]`), + `(${i.string('A')}).substring((${i.string('A')}).indexOf(${i.string('B')}) + 1)`), + alltextBeforeString: c('string', ({input: i}) => `(${i.string('A')}).split(${i.string('B')}, 1)[0]`), + split: c('string', ({input: i}) => `JSON.stringify((${i.string('A')}).split(${i.string('B')}))`), + splitarray: c('any', ({input: i}) => `(${i.string('A')}).split(${i.string('B')})`), + length: c('number', ({input: i}) => `(${i('A')}).length`), + item: c('string', ({input: i}) => `(${i('A')}).split(${i.string('B')})[${i.number('C')}]`), + squarebrackets: c('any', ({input: i}) => `(${i('A')})[${i.string('B')}]`), jsonparse: c('any', ({input: i}) => `JSON.parse(${i.string('A')})`), jsonstringify: c('string', ({input: i}) => `JSON.stringify(${i('A')})`), isnumber: c('boolean', ({input: i}) => `(Number(${i.string('A')}) == ${i.string('A')})`), diff --git a/test/unit/tw_mistwarp_compiler_blocks.js b/test/unit/tw_mistwarp_compiler_blocks.js index a0fcfa4b113..2a73aeb192f 100644 --- a/test/unit/tw_mistwarp_compiler_blocks.js +++ b/test/unit/tw_mistwarp_compiler_blocks.js @@ -385,6 +385,245 @@ test("Mist's Utils 5.9 blocks use native compiler cases", async t => { vm.runtime.precompile(); JSGenerator.testingApparatus = null; - t.match(source, /"origin"\.startsWith\("ori"\)/); + t.match(source, /\("origin"\)\.startsWith\("ori"\)/); t.notMatch(source, /oldCompiler|executeInCompatibilityLayer/); }); + +test('native switch keeps raw patch values uncoerced', async t => { + const vm = new VirtualMachine(); + await vm.loadProject({ + targets: [{ + isStage: true, + name: 'Stage', + variables: {}, + lists: {}, + broadcasts: {}, + blocks: { + hat: { + opcode: 'event_whenflagclicked', + next: 'setup', + parent: null, + inputs: {}, + fields: {}, + topLevel: true, + x: 0, + y: 0 + }, + setup: { + opcode: 'mistsutils_patchcommand', + next: 'switch', + parent: 'hat', + inputs: {A: [1, [10, 'const num = 17; const tkn = {cmd: 17, str: 5}; globalThis.__switchResult = "none";']]}, + fields: {}, + topLevel: false + }, + switch: { + opcode: 'control_switch', + next: null, + parent: 'setup', + inputs: {VALUE: [3, 'discriminant', [10, '']], SUBSTACK: [2, 'rawCase']}, + fields: {}, + topLevel: false + }, + discriminant: { + opcode: 'mistsutils_patchreporter', + next: null, + parent: 'switch', + inputs: {A: [1, [10, 'num']]}, + fields: {}, + topLevel: false + }, + rawCase: { + opcode: 'mistsutils_patchcommand', + next: 'case', + parent: 'switch', + inputs: {A: [1, [10, 'case tkn.cmd: globalThis.__switchResult = "cmd"; break;']]}, + fields: {}, + topLevel: false + }, + case: { + opcode: 'control_case', + next: 'default', + parent: 'rawCase', + inputs: {VALUE: [3, 'caseValue', [10, '']], SUBSTACK: [2, 'caseBody']}, + fields: {}, + topLevel: false + }, + caseValue: { + opcode: 'mistsutils_patchreporter', + next: null, + parent: 'case', + inputs: {A: [1, [10, 'tkn.str']]}, + fields: {}, + topLevel: false + }, + caseBody: { + opcode: 'mistsutils_patchcommand', + next: null, + parent: 'case', + inputs: {A: [1, [10, 'globalThis.__switchResult = "str";']]}, + fields: {}, + topLevel: false + }, + default: { + opcode: 'control_default', + next: null, + parent: 'case', + inputs: {SUBSTACK: [2, 'defaultBody']}, + fields: {}, + topLevel: false + }, + defaultBody: { + opcode: 'mistsutils_patchcommand', + next: null, + parent: 'default', + inputs: {A: [1, [10, 'globalThis.__switchResult = "default";']]}, + fields: {}, + topLevel: false + } + }, + comments: {}, + currentCostume: 0, + costumes: [], + sounds: [], + volume: 100, + layerOrder: 0, + tempo: 60, + videoTransparency: 50, + videoState: 'on', + textToSpeechLanguage: null + }], + monitors: [], + extensions: [], + meta: {semver: '3.0.0', vm: '3.0.0', agent: ''} + }); + + let source = ''; + JSGenerator.testingApparatus = {report: (_generator, generated) => { + source += generated; + }}; + vm.runtime.precompile(); + JSGenerator.testingApparatus = null; + + t.match(source, /switch \(\(num\)\) \{/, 'raw discriminant is not stringified'); + t.match(source, /case \(tkn\.str\): \{/, 'raw case value is not stringified'); + t.match(source, /case tkn\.cmd: globalThis\.__switchResult = "cmd"; break;/, 'spliced case statement is preserved'); + + vm.greenFlag(); + vm.runtime._step(); + t.equal(global.__switchResult, 'cmd', 'raw spliced case matches the raw discriminant'); + delete global.__switchResult; +}); + +test('casting a raw patch reporter keeps its operator precedence', async t => { + const vm = new VirtualMachine(); + vm.extensionManager.addBuiltinExtension('mistsutils', class { + getInfo () { + return { + id: 'mistsutils', + name: "Mist's Utils", + blocks: [{ + opcode: 'ifthen', + blockType: 'reporter', + text: 'if [A] then [B] else [C]', + arguments: {A: {type: 'Boolean'}, B: {type: 'string'}, C: {type: 'string'}} + }, { + opcode: 'false', + blockType: 'Boolean', + text: 'false' + }] + }; + } + ifthen () {} + false () {} + }); + await vm.loadProject({ + targets: [{ + isStage: true, + name: 'Stage', + variables: {}, + lists: {}, + broadcasts: {}, + blocks: { + hat: { + opcode: 'event_whenflagclicked', + next: 'setup', + parent: null, + inputs: {}, + fields: {}, + topLevel: true, + x: 0, + y: 0 + }, + setup: { + opcode: 'mistsutils_patchcommand', + next: 'store', + parent: 'hat', + inputs: {A: [1, [10, 'const labels = ["type", "name", "location", "data"];']]}, + fields: {}, + topLevel: false + }, + store: { + opcode: 'mistsutils_patchcommand2', + next: null, + parent: 'setup', + inputs: { + A: [1, [10, 'globalThis.__rawIndex = ']], + B: [3, 'ifthen', [10, '']] + }, + fields: {}, + topLevel: false + }, + ifthen: { + opcode: 'mistsutils_ifthen', + next: null, + parent: 'store', + inputs: { + A: [2, 'never'], + B: [1, [10, 'unused']], + C: [3, 'lookup', [10, '']] + }, + fields: {}, + topLevel: false + }, + never: { + opcode: 'mistsutils_false', + next: null, + parent: 'ifthen', + inputs: {}, + fields: {}, + topLevel: false + }, + lookup: { + opcode: 'mistsutils_patchreporter', + next: null, + parent: 'ifthen', + inputs: {A: [1, [10, 'labels.indexOf("data") + 1']]}, + fields: {}, + topLevel: false + } + }, + comments: {}, + currentCostume: 0, + costumes: [], + sounds: [], + volume: 100, + layerOrder: 0, + tempo: 60, + videoTransparency: 50, + videoState: 'on', + textToSpeechLanguage: null + }], + monitors: [], + extensions: [], + meta: {semver: '3.0.0', vm: '3.0.0', agent: ''} + }); + + vm.runtime.precompile(); + vm.greenFlag(); + vm.runtime._step(); + + // "" + labels.indexOf("data") + 1 would concatenate to "31" instead of adding to 4. + t.equal(`${global.__rawIndex}`, '4', 'the spliced expression is added, not concatenated'); + delete global.__rawIndex; +}); From 4871638c60755b7d7deae90d2072e78074b056a3 Mon Sep 17 00:00:00 2001 From: Mist Date: Tue, 14 Jul 2026 19:06:09 +0100 Subject: [PATCH 106/106] fix issue with stage caching --- src/engine/blocks.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/engine/blocks.js b/src/engine/blocks.js index d6f5e91a55b..aa89bdabb14 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -783,6 +783,9 @@ class Blocks { block.mutation = mutationAdapter(args.value); break; case 'checkbox': { + const stage = this.runtime.getTargetForStage(); + if (!stage) return; + // A checkbox usually has a one to one correspondence with the monitor // block but in the case of monitored reporters that have arguments, // map the old id to a new id, creating a new monitor block if necessary @@ -812,9 +815,9 @@ class Blocks { // Variable blocks may be sprite specific depending on the owner of the variable let isSpriteLocalVariable = false; if (block.opcode === 'data_variable') { - isSpriteLocalVariable = !(this.runtime.getTargetForStage().variables[block.fields.VARIABLE.id]); + isSpriteLocalVariable = !(stage.variables[block.fields.VARIABLE.id]); } else if (block.opcode === 'data_listcontents') { - isSpriteLocalVariable = !(this.runtime.getTargetForStage().variables[block.fields.LIST.id]); + isSpriteLocalVariable = !(stage.variables[block.fields.LIST.id]); } const isSpriteSpecific = isSpriteLocalVariable ||