Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/lib/ruby-generator/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default function (Generator) {

Generator.event_whenstageclicked = function (block) {
block.isStatement = true;
return `Stage.when(:stage_clicked) do\n`;
return `Stage.when(:clicked) do\n`;
};

return Generator;
Expand Down
77 changes: 76 additions & 1 deletion src/lib/ruby-to-blocks-converter/event.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* global Opal */
import _ from 'lodash';
import Variable from 'scratch-vm/src/engine/variable';

const KeyOptions = [
'space',
Expand Down Expand Up @@ -46,6 +47,11 @@ const KeyOptions = [
'9'
];

const GreaterThanMenu = [
'LOUDNESS',
'TIMER'
];

/**
* Event converter
*/
Expand All @@ -68,7 +74,11 @@ const EventConverter = {
opcode = 'event_whenflagclicked';
break;
case 'clicked':
opcode = 'event_whenthisspriteclicked';
if (this._context.target && this._context.target.isStage) {
opcode = 'event_whenstageclicked';
} else {
opcode = 'event_whenthisspriteclicked';
}
break;
}
block = this._createBlock(opcode, 'hat');
Expand All @@ -82,8 +92,73 @@ const EventConverter = {
this._setParent(rubyBlock, block);
}
break;
case 'backdrop_switches':
if (args.length === 2 && this._isString(args[1])) {
block = this._createBlock('event_whenbackdropswitchesto', 'hat');
this._addField(block, 'BACKDROP', args[1]);
this._setParent(rubyBlock, block);
}
break;
case 'greater_than':
if (args.length === 3 &&
this._isString(args[1]) && GreaterThanMenu.indexOf(args[1].toString()) >= 0 &&
this._isNumberOrBlock(args[2])) {
block = this._createBlock('event_whengreaterthan', 'hat');
this._addField(block, 'WHENGREATERTHANMENU', args[1]);
this._addNumberInput(block, 'VALUE', 'math_number', args[2], 10);
this._setParent(rubyBlock, block);
}
break;
case 'receive':
if (args.length === 2 && this._isString(args[1])) {
const broadcastMsg = this._lookupOrCreateBroadcastMsg(args[1]);
block = this._createBlock('event_whenbroadcastreceived', 'hat');
this._addField(block, 'BROADCAST_OPTION', broadcastMsg.name, {
id: broadcastMsg.id,
variableType: Variable.BROADCAST_MESSAGE_TYPE
});
this._setParent(rubyBlock, block);
}
break;
}
} else if (this._isSelf(receiver) || receiver === Opal.nil) {
switch (name) {
case 'broadcast':
case 'broadcast_and_wait':
if (args.length === 1 && this._isStringOrBlock(args[0]) && !rubyBlock) {
let opcode;
if (name === 'broadcast') {
opcode = 'event_broadcast';
} else {
opcode = 'event_broadcastandwait';
}
const menuBlock = this._createBlock('event_broadcast_menu', 'value', {
shadow: true
});
let broadcastMsg;
let inputBlock;
let shadowBlock;
if (this._isString(args[0])) {
broadcastMsg = this._lookupOrCreateBroadcastMsg(args[0]);
inputBlock = menuBlock;
shadowBlock = menuBlock;
} else {
broadcastMsg = this._defaultBroadcastMsg();
inputBlock = args[0];
shadowBlock = menuBlock;
}
this._addField(menuBlock, 'BROADCAST_OPTION', broadcastMsg.name, {
id: broadcastMsg.id,
variableType: Variable.BROADCAST_MESSAGE_TYPE
});

block = this._createBlock(opcode, 'statement');
this._addInput(block, 'BROADCAST_INPUT', inputBlock, shadowBlock);
}
break;
}
}

return block;
}
};
Expand Down
69 changes: 58 additions & 11 deletions src/lib/ruby-to-blocks-converter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class RubyToBlocksConverter {
return this._context.lists;
}

get broadcastMsgs () {
return this._context.broadcastMsgs;
}

reset () {
this._context = {
currentNode: null,
Expand All @@ -64,6 +68,7 @@ class RubyToBlocksConverter {
localVariables: {},
variables: {},
lists: {},
broadcastMsgs: {},
procedures: {}
};
if (this.vm && this.vm.runtime && this.vm.runtime.getTargetForStage) {
Expand All @@ -73,6 +78,7 @@ class RubyToBlocksConverter {

targetCodeToBlocks (target, code) {
this.reset();
this._setTarget(target);
this._loadVariables(target);
try {
const root = RubyParser.$parse(code);
Expand Down Expand Up @@ -139,6 +145,13 @@ class RubyToBlocksConverter {
});
});

Object.keys(this._context.broadcastMsgs).forEach(name => {
const broadcastMsg = this._context.broadcastMsgs[name];
if (!stage.variables.hasOwnProperty(broadcastMsg.id)) {
stage.createVariable(broadcastMsg.id, broadcastMsg.name, Variable.BROADCAST_MESSAGE_TYPE);
}
});

Object.keys(target.blocks._blocks).forEach(blockId => {
target.blocks.deleteBlock(blockId);
});
Expand Down Expand Up @@ -169,6 +182,7 @@ class RubyToBlocksConverter {
'localVariables',
'variables',
'lists',
'broadcastMsgs',
'procedures'
];

Expand Down Expand Up @@ -202,6 +216,10 @@ class RubyToBlocksConverter {
});
}

_setTarget (target) {
this._context.target = target;
}

_loadVariables (target) {
if (!target || !target.variables) {
return;
Expand All @@ -217,6 +235,8 @@ class RubyToBlocksConverter {
let storeName;
if (variable.type === Variable.SCALAR_TYPE) {
storeName = 'variables';
} else if (variable.type === Variable.BROADCAST_MESSAGE_TYPE) {
storeName = 'broadcastMsgs';
} else {
storeName = 'lists';
}
Expand Down Expand Up @@ -394,14 +414,14 @@ class RubyToBlocksConverter {
return block;
}

_addField (block, name, value) {
_addField (block, name, value, attributes = {}) {
if (!this._isBlock(block)) {
return;
}
block.fields[name] = {
block.fields[name] = Object.assign({
name: name,
value: value.toString()
};
}, attributes);
}

_addInput (block, name, inputBlock, shadowBlock) {
Expand Down Expand Up @@ -456,7 +476,7 @@ class RubyToBlocksConverter {
};
}

_findOrCreateVariableOrList (name, type) {
_lookupOrCreateVariableOrList (name, type) {
name = name.toString();
let scope;
let varName;
Expand Down Expand Up @@ -493,15 +513,42 @@ class RubyToBlocksConverter {
return variable;
}

_findOrCreateVariable (name) {
return this._findOrCreateVariableOrList(name, Variable.SCALAR_TYPE);
_lookupOrCreateVariable (name) {
return this._lookupOrCreateVariableOrList(name, Variable.SCALAR_TYPE);
}

_findOrCreateList (name) {
return this._findOrCreateVariableOrList(name, Variable.LIST_TYPE);
_lookupOrCreateList (name) {
return this._lookupOrCreateVariableOrList(name, Variable.LIST_TYPE);
}

_lookupOrCreateBroadcastMsg (name) {
name = name.toString();
const key = name.toLowerCase();
let broadcastMsg = this._context.broadcastMsgs[key];
if (!broadcastMsg) {
broadcastMsg = {
id: Blockly.utils.genUid(),
name: name,
scope: 'global'
};
this._context.broadcastMsgs[key] = broadcastMsg;
}
return broadcastMsg;
}

_defaultBroadcastMsg () {
const defaultName = 'message1';
const keys = Object.keys(this._context.broadcastMsgs);
if (keys.length === 0) {
return this._lookupOrCreateBroadcastMsg(defaultName);
}
if (this._context.broadcastMsgs.hasOwnProperty(defaultName)) {
return this._context.broadcastMsgs[defaultName];
}
return this._context.broadcastMsgs[keys[0]];
}

_findProcedure (name) {
_lookupProcedure (name) {
name = name.toString();
return this._context.procedures[name];
}
Expand Down Expand Up @@ -931,7 +978,7 @@ class RubyToBlocksConverter {
_onVar (node, scope) {
this._checkNumChildren(node, 1);

const variable = this._findOrCreateVariable(node.children[0]);
const variable = this._lookupOrCreateVariable(node.children[0]);
const block = this._callConvertersHandler('onVar', scope, variable);
if (block) {
return block;
Expand Down Expand Up @@ -972,7 +1019,7 @@ class RubyToBlocksConverter {

const saved = this._saveContext();

const variable = this._findOrCreateVariable(node.children[0]);
const variable = this._lookupOrCreateVariable(node.children[0]);
const rh = this._process(node.children[1]);
let block = this._callConvertersHandler('onVasgn', scope, variable, rh);
if (!block) {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/ruby-to-blocks-converter/my-blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const MyBlocksConverter = {
onSend: function (receiver, name, args, rubyBlockArgs, rubyBlock) {
let block;
if (this._isSelf(receiver) || receiver === Opal.nil) {
const procedure = this._findProcedure(name);
const procedure = this._lookupProcedure(name);
if (procedure) {
if (procedure.argumentIds.length === args.length) {
block = this._createBlock('procedures_call', 'statement', {
Expand Down Expand Up @@ -109,7 +109,7 @@ const MyBlocksConverter = {
this._process(node.children[2]).forEach(n => {
n = n.toString();
procedure.argumentNames.push(n);
procedure.argumentVariables.push(this._findOrCreateVariable(n));
procedure.argumentVariables.push(this._lookupOrCreateVariable(n));
procedure.procCode.push('%s');
procedure.argumentDefaults.push('');
const inputId = Blockly.utils.genUid();
Expand Down
6 changes: 3 additions & 3 deletions src/lib/ruby-to-blocks-converter/variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const VariablesConverter = {
opcode = 'data_hidevariable';
break;
}
const variable = this._findOrCreateVariable(args[0]);
const variable = this._lookupOrCreateVariable(args[0]);
if (variable.scope !== 'local') {
block = this._createBlock(opcode, 'statement', {
fields: {
Expand Down Expand Up @@ -57,7 +57,7 @@ const VariablesConverter = {
blockType = 'statement';
break;
}
const variable = this._findOrCreateList(args[0]);
const variable = this._lookupOrCreateList(args[0]);
if (variable.scope !== 'local') {
block = this._createBlock(opcode, blockType, {
fields: {
Expand Down Expand Up @@ -147,7 +147,7 @@ const VariablesConverter = {
onOpAsgn: function (lh, operator, rh) {
let block;
if (operator === '+' && this._isString(lh) && this._isNumberOrBlock(rh)) {
const variable = this._findOrCreateVariable(lh);
const variable = this._lookupOrCreateVariable(lh);
if (variable.scope !== 'local') {
block = this._createBlock('data_changevariableby', 'statement', {
fields: {
Expand Down
30 changes: 24 additions & 6 deletions test/helpers/expect-to-equal-blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ const expectToEqualFields = function (context, actualFields, expectedFieldsInfo)
expectedType = Variable.LIST_TYPE;
}
expect(field).toHaveProperty('variableType', expectedType);
expect(field).toHaveProperty('id', variable.id);
} else if (expectedField.hasOwnProperty('broadcastMsg')) {
expect(context.broadcastMsgs).toHaveProperty(expectedField.broadcastMsg);
const broadcastMsg = context.broadcastMsgs[expectedField.broadcastMsg];
expect(broadcastMsg.name).toEqual(expectedField.broadcastMsg);
expect(field).toHaveProperty('id', broadcastMsg.id);
expect(field).toHaveProperty('variableType', 'broadcast_msg');
} else {
expect(field.id).toEqual(void 0);
expect(field.value).toEqual(expectedField.value);
Expand Down Expand Up @@ -205,7 +212,8 @@ const expectToEqualBlocks = function (converter, expectedBlocksInfo) {
converter: converter,
blocks: blocks,
variables: converter.variables,
lists: converter.lists
lists: converter.lists,
broadcastMsgs: converter.broadcastMsgs
};

const scripts = blocks.getScripts();
Expand Down Expand Up @@ -261,14 +269,23 @@ const fieldsToExpected = function (context, fields) {
return Object.keys(fields).map(name => {
const field = fields[name];
if (field.id) {
const varName = field.value;
let varName = field.value;
let storeName;
if (field.variableType === Variable.SCALAR_TYPE) {
storeName = 'variables';
} else if (field.variableType === Variable.BROADCAST_MESSAGE_TYPE) {
storeName = 'broadcastMsgs';
varName = varName.toLowerCase();
} else {
storeName = 'lists';
}
const variable = context[storeName][varName];
if (field.variableType === Variable.BROADCAST_MESSAGE_TYPE) {
return {
name: field.name,
broadcastMsg: field.value
};
}
let scope;
if (variable.scope === 'global') {
scope = '$';
Expand All @@ -277,14 +294,14 @@ const fieldsToExpected = function (context, fields) {
} else {
scope = '';
}
if (variable.type === Variable.SCALAR_TYPE) {
if (field.variableType === Variable.SCALAR_TYPE) {
return {
name: 'VARIABLE',
name: field.name,
variable: `${scope}${varName}`
};
}
return {
name: 'LIST',
name: field.name,
list: `${scope}${varName}`
};
}
Expand Down Expand Up @@ -375,7 +392,8 @@ const rubyToExpected = function (converter, target, code) {
converter: converter,
blocks: blocks,
variables: converter.variables,
lists: converter.lists
lists: converter.lists,
broadcastMsgs: converter.broadcastMsgs
};

const scripts = blocks.getScripts();
Expand Down
Loading