mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-01-10 15:02:06 -05:00
Merge pull request #12 from cwillisf/feature/execute-blocks
Allow the Sequencer to execute a JS function for each block
This commit is contained in:
commit
b7ffe6d774
7 changed files with 684 additions and 317 deletions
|
@ -7,7 +7,8 @@
|
||||||
"linebreak-style": [2, "unix"],
|
"linebreak-style": [2, "unix"],
|
||||||
"max-len": [2, 80, 4],
|
"max-len": [2, 80, 4],
|
||||||
"semi": [2, "always"],
|
"semi": [2, "always"],
|
||||||
"strict": [2, "never"]
|
"strict": [2, "never"],
|
||||||
|
"no-console": [2, {"allow": ["log", "warn", "error"]}]
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"node": true,
|
"node": true,
|
||||||
|
|
54
src/blocks/scratch3.js
Normal file
54
src/blocks/scratch3.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
function Scratch3Blocks(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.
|
||||||
|
*/
|
||||||
|
Scratch3Blocks.prototype.getPrimitives = function() {
|
||||||
|
return {
|
||||||
|
'control_repeat': this.repeat,
|
||||||
|
'control_forever': this.forever,
|
||||||
|
'control_wait': this.wait,
|
||||||
|
'control_stop': this.stop,
|
||||||
|
'event_whenflagclicked': this.whenFlagClicked,
|
||||||
|
'event_whenbroadcastreceived': this.whenBroadcastReceived,
|
||||||
|
'event_broadcast': this.broadcast
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Scratch3Blocks.prototype.repeat = function() {
|
||||||
|
console.log('Running: control_repeat');
|
||||||
|
};
|
||||||
|
|
||||||
|
Scratch3Blocks.prototype.forever = function() {
|
||||||
|
console.log('Running: control_forever');
|
||||||
|
};
|
||||||
|
|
||||||
|
Scratch3Blocks.prototype.wait = function() {
|
||||||
|
console.log('Running: control_wait');
|
||||||
|
};
|
||||||
|
|
||||||
|
Scratch3Blocks.prototype.stop = function() {
|
||||||
|
console.log('Running: control_stop');
|
||||||
|
};
|
||||||
|
|
||||||
|
Scratch3Blocks.prototype.whenFlagClicked = function() {
|
||||||
|
console.log('Running: event_whenflagclicked');
|
||||||
|
};
|
||||||
|
|
||||||
|
Scratch3Blocks.prototype.whenBroadcastReceived = function() {
|
||||||
|
console.log('Running: event_whenbroadcastreceived');
|
||||||
|
};
|
||||||
|
|
||||||
|
Scratch3Blocks.prototype.broadcast = function() {
|
||||||
|
console.log('Running: event_broadcast');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Scratch3Blocks;
|
49
src/blocks/wedo2.js
Normal file
49
src/blocks/wedo2.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
|
||||||
|
function WeDo2Blocks(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.
|
||||||
|
*/
|
||||||
|
WeDo2Blocks.prototype.getPrimitives = function() {
|
||||||
|
return {
|
||||||
|
'wedo_motorclockwise': this.motorClockwise,
|
||||||
|
'wedo_motorcounterclockwise': this.motorCounterClockwise,
|
||||||
|
'wedo_motorspeed': this.motorSpeed,
|
||||||
|
'wedo_setcolor': this.setColor,
|
||||||
|
'wedo_whendistanceclose': this.whenDistanceClose,
|
||||||
|
'wedo_whentilt': this.whenTilt
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
WeDo2Blocks.prototype.motorClockwise = function() {
|
||||||
|
console.log('Running: wedo_motorclockwise');
|
||||||
|
};
|
||||||
|
|
||||||
|
WeDo2Blocks.prototype.motorCounterClockwise = function() {
|
||||||
|
console.log('Running: wedo_motorcounterclockwise');
|
||||||
|
};
|
||||||
|
|
||||||
|
WeDo2Blocks.prototype.motorSpeed = function() {
|
||||||
|
console.log('Running: wedo_motorspeed');
|
||||||
|
};
|
||||||
|
|
||||||
|
WeDo2Blocks.prototype.setColor = function() {
|
||||||
|
console.log('Running: wedo_setcolor');
|
||||||
|
};
|
||||||
|
|
||||||
|
WeDo2Blocks.prototype.whenDistanceClose = function() {
|
||||||
|
console.log('Running: wedo_whendistanceclose');
|
||||||
|
};
|
||||||
|
|
||||||
|
WeDo2Blocks.prototype.whenTilt = function() {
|
||||||
|
console.log('Running: wedo_whentilt');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = WeDo2Blocks;
|
|
@ -3,6 +3,11 @@ var Sequencer = require('./sequencer');
|
||||||
var Thread = require('./thread');
|
var Thread = require('./thread');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
|
||||||
|
var defaultBlockPackages = {
|
||||||
|
'scratch3': require('../blocks/scratch3'),
|
||||||
|
'wedo2': require('../blocks/wedo2')
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages blocks, stacks, and the sequencer.
|
* Manages blocks, stacks, and the sequencer.
|
||||||
*/
|
*/
|
||||||
|
@ -34,6 +39,14 @@ function Runtime () {
|
||||||
|
|
||||||
/** @type {!Sequencer} */
|
/** @type {!Sequencer} */
|
||||||
this.sequencer = new Sequencer(this);
|
this.sequencer = new Sequencer(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map to look up a block primitive's implementation function by its opcode.
|
||||||
|
* This is a two-step lookup: package name first, then primitive name.
|
||||||
|
* @type {Object.<string, Function>}
|
||||||
|
*/
|
||||||
|
this._primitives = {};
|
||||||
|
this._registerBlockPackages();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -184,6 +197,39 @@ Runtime.prototype.deleteBlock = function (e) {
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register default block packages with this runtime.
|
||||||
|
* @todo Prefix opcodes with package name.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Runtime.prototype._registerBlockPackages = function () {
|
||||||
|
for (var packageName in defaultBlockPackages) {
|
||||||
|
if (defaultBlockPackages.hasOwnProperty(packageName)) {
|
||||||
|
// @todo pass a different runtime depending on package privilege?
|
||||||
|
var packageObject = new (defaultBlockPackages[packageName])(this);
|
||||||
|
var packageContents = packageObject.getPrimitives();
|
||||||
|
for (var op in packageContents) {
|
||||||
|
if (packageContents.hasOwnProperty(op)) {
|
||||||
|
this._primitives[op] =
|
||||||
|
packageContents[op].bind(packageObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the function associated with the given opcode.
|
||||||
|
* @param {!string} opcode The opcode to look up.
|
||||||
|
* @return {Function} The function which implements the opcode.
|
||||||
|
*/
|
||||||
|
Runtime.prototype.getOpcodeFunction = function (opcode) {
|
||||||
|
return this._primitives[opcode];
|
||||||
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a thread and push it to the list of threads.
|
* Create a thread and push it to the list of threads.
|
||||||
* @param {!string} id ID of block that starts the stack
|
* @param {!string} id ID of block that starts the stack
|
||||||
|
@ -306,4 +352,14 @@ Runtime.prototype._getSubstack = function (id) {
|
||||||
return this.blocks[id].fields['SUBSTACK'];
|
return this.blocks[id].fields['SUBSTACK'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to get the opcode for a particular block
|
||||||
|
* @param {?string} id ID of block to query
|
||||||
|
* @return {?string} the opcode corresponding to that block
|
||||||
|
*/
|
||||||
|
Runtime.prototype._getOpcode = function (id) {
|
||||||
|
if (typeof this.blocks[id] === 'undefined') return null;
|
||||||
|
return this.blocks[id].opcode;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = Runtime;
|
module.exports = Runtime;
|
||||||
|
|
|
@ -58,10 +58,28 @@ Sequencer.prototype.stepThreads = function (threads) {
|
||||||
* @param {!Thread} thread Thread object to step
|
* @param {!Thread} thread Thread object to step
|
||||||
*/
|
*/
|
||||||
Sequencer.prototype.stepThread = function (thread) {
|
Sequencer.prototype.stepThread = function (thread) {
|
||||||
// @todo Actually run the blocks
|
var opcode = this.runtime._getOpcode(thread.nextBlock);
|
||||||
// Currently goes to the next block in the sequence.
|
|
||||||
var nextBlock = this.runtime._getNextBlock(thread.nextBlock);
|
if (!opcode) {
|
||||||
thread.nextBlock = nextBlock;
|
console.warn('Could not get opcode for block: ' + thread.nextBlock);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var blockFunction = this.runtime.getOpcodeFunction(opcode);
|
||||||
|
if (!blockFunction) {
|
||||||
|
console.warn('Could not get implementation for opcode: ' + opcode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
blockFunction();
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
console.error('Exception calling block function',
|
||||||
|
{opcode: opcode, exception: e});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread.nextBlock = this.runtime._getNextBlock(thread.nextBlock);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Sequencer;
|
module.exports = Sequencer;
|
||||||
|
|
10
vm.min.js
vendored
10
vm.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue