diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index 45f37351..9d47740e 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -1291,33 +1291,43 @@ class ScriptTreeGenerator { const procedureCode = block.mutation.proccode; const paramNamesIdsAndDefaults = this.blocks.getProcedureParamNamesIdsAndDefaults(procedureCode); if (paramNamesIdsAndDefaults === null) { + // Still need to evaluate arguments in case of side effects + const argumentList = []; + for (const inputName of Object.keys(block.inputs)) { + argumentList.push(this.descendInputOfBlock(block, inputName)); + } return { - kind: 'noop' + kind: 'procedures.discard', + values: argumentList }; } const [paramNames, paramIds, paramDefaults] = paramNamesIdsAndDefaults; + const argumentList = []; + 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] + }; + } + argumentList.push(value); + } 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; + const argumentNameMap = {}; + for (let i = 0; i < argumentList.length; i++) { + argumentNameMap[paramNames[i]] = argumentList[i]; } return { kind: 'addons.call', code: procedureCode, - arguments: args, + arguments: argumentNameMap, blockId: block.id }; } @@ -1326,7 +1336,8 @@ class ScriptTreeGenerator { const definitionBlock = this.blocks.getBlock(definitionId); if (!definitionBlock) { return { - kind: 'noop' + kind: 'procedures.discard', + values: argumentList }; } const innerDefinition = this.blocks.getBlock(definitionBlock.inputs.custom_block.block); @@ -1350,31 +1361,15 @@ class ScriptTreeGenerator { } // Non-warp direct recursion yields. - if (!this.script.isWarp) { - if (procedureCode === this.script.procedureCode) { - 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.push(value); + if (!this.script.isWarp && procedureCode === this.script.procedureCode) { + this.script.yields = true; } return { kind: 'procedures.call', code: procedureCode, variant, - arguments: args + arguments: argumentList }; } diff --git a/src/compiler/jsgen.js b/src/compiler/jsgen.js index f20b460c..c56b4ca2 100644 --- a/src/compiler/jsgen.js +++ b/src/compiler/jsgen.js @@ -653,6 +653,17 @@ class JSGenerator { } return new TypedInput(`${procedureReference}(${joinedArgs})`, TYPE_UNKNOWN); } + case 'procedures.discard': { + const args = []; + for (const value of node.values) { + args.push(this.descendInput(value).asUnknown()); + } + if (args.length > 0) { + // We can use the comma operator to discard the values. + return new TypedInput(`(${args.join(',')},"")`, TYPE_STRING); + } + return new TypedInput('""', TYPE_STRING); + } case 'sensing.answer': return new TypedInput(`runtime.ext_scratch3_sensing._answer`, TYPE_STRING); @@ -1068,6 +1079,14 @@ class JSGenerator { this.resetVariableInputs(); break; } + case 'procedures.discard': { + for (const value of node.values) { + const input = this.descendInput(value).asUnknown(); + // Don't need to use void, but it makes it explicit that we do not care about the result. + this.source += `void ${input};\n`; + } + break; + } case 'procedures.return': this.stopScriptAndReturn(this.descendInput(node.value).asSafe()); break;