Spaces:
Runtime error
Runtime error
| const Cast = require('../util/cast'); | |
| class Scratch3ProcedureBlocks { | |
| constructor(runtime) { | |
| /** | |
| * The runtime instantiating this block package. | |
| * @type {Runtime} | |
| */ | |
| this.runtime = runtime; | |
| } | |
| /** | |
| * Retrieve the block primitives implemented by this package. | |
| * @return {object.<string, Function>} Mapping of opcode to Function. | |
| */ | |
| getPrimitives() { | |
| return { | |
| procedures_definition: this.definition, | |
| procedures_call: this.call, | |
| procedures_set: this.set, | |
| argument_reporter_string_number: this.argumentReporterStringNumber, | |
| argument_reporter_boolean: this.argumentReporterBoolean, | |
| argument_reporter_command: this.argumentReporterCommand | |
| }; | |
| } | |
| definition() { | |
| // No-op: execute the blocks. | |
| } | |
| call (args, util) { | |
| if (!util.stackFrame.executed) { | |
| const procedureCode = args.mutation.proccode; | |
| const paramNamesIdsAndDefaults = util.getProcedureParamNamesIdsAndDefaults(procedureCode); | |
| // If null, procedure could not be found, which can happen if custom | |
| // block is dragged between sprites without the definition. | |
| // Match Scratch 2.0 behavior and noop. | |
| if (paramNamesIdsAndDefaults === null) { | |
| return; | |
| } | |
| const [paramNames, paramIds, paramDefaults] = paramNamesIdsAndDefaults; | |
| // Initialize params for the current stackFrame to {}, even if the procedure does | |
| // not take any arguments. This is so that `getParam` down the line does not look | |
| // at earlier stack frames for the values of a given parameter (#1729) | |
| util.initParams(); | |
| for (let i = 0; i < paramIds.length; i++) { | |
| if (args.hasOwnProperty(paramIds[i])) { | |
| util.pushParam(paramNames[i], args[paramIds[i]]); | |
| } else { | |
| util.pushParam(paramNames[i], paramDefaults[i]); | |
| } | |
| } | |
| const addonBlock = util.runtime.getAddonBlock(procedureCode); | |
| if (addonBlock) { | |
| const result = addonBlock.callback(util.thread.getAllparams(), util); | |
| if (util.thread.status === 1 /* STATUS_PROMISE_WAIT */) { | |
| // If the addon block is using STATUS_PROMISE_WAIT to force us to sleep, | |
| // make sure to not re-run this block when we resume. | |
| util.stackFrame.executed = true; | |
| } | |
| return result; | |
| } | |
| util.stackFrame.executed = true; | |
| util.startProcedure(procedureCode); | |
| } | |
| } | |
| set(args, util) { | |
| const contain = util.thread.blockContainer; | |
| const block = contain.getBlock(util.thread.isCompiled ? util.thread.peekStack() : util.thread.peekStackFrame().op.id); | |
| if (!block) return; | |
| const thread = util.thread; | |
| const param = contain.getBlock(block.inputs.PARAM?.block); | |
| if (param) { | |
| try { | |
| const curParams = thread.stackFrames[0].params; | |
| if (curParams !== null) thread.stackFrames[0].params[param.fields.VALUE.value] = args.VALUE; | |
| else thread.stackFrames[0].params = { [param.fields.VALUE.value]: args.VALUE } | |
| } catch { /* shouldn't happen */ } | |
| } | |
| } | |
| argumentReporterStringNumber(args, util) { | |
| const value = util.getParam(args.VALUE); | |
| if (value === null) { | |
| // When the parameter is not found in the most recent procedure | |
| // call, the default is always 0. | |
| return 0; | |
| } | |
| return value; | |
| } | |
| argumentReporterBoolean(args, util) { | |
| const value = util.getParam(args.VALUE); | |
| if (value === null) { | |
| // When the parameter is not found in the most recent procedure | |
| // call, the default is always 0. | |
| return 0; | |
| } | |
| return value; | |
| } | |
| argumentReporterCommand(args, util) { | |
| const branchInfo = util.getParam(args.VALUE) || {}; | |
| if (branchInfo.entry === null) return; | |
| const [branchId, target] = util.getBranchAndTarget( | |
| branchInfo.callerId, | |
| branchInfo.entry | |
| ) || []; | |
| if (branchId) { | |
| // Push branch ID to the thread's stack. | |
| util.thread.pushStack(branchId, target); | |
| } else { | |
| util.thread.pushStack(null); | |
| } | |
| } | |
| } | |
| module.exports = Scratch3ProcedureBlocks; | |