Spaces:
Build error
Build error
File size: 4,560 Bytes
30c32c8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
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;
|