Skip to content

Commit b029218

Browse files
committed
supported converting variables blocks from Ruby.
1 parent 6efdeaa commit b029218

File tree

3 files changed

+421
-48
lines changed

3 files changed

+421
-48
lines changed

src/lib/ruby-to-blocks-converter/index.js

Lines changed: 144 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ class RubyToBlocksConverter {
269269
});
270270
}
271271

272-
_findOrCreateVariable (name, type = Variable.SCALAR_TYPE) {
272+
_findOrCreateVariable (name, type) {
273273
let scope;
274274
let store;
275275
if (name[0] === '$') {
@@ -285,19 +285,47 @@ class RubyToBlocksConverter {
285285
store = this._context.localVariables;
286286
}
287287
if (store.hasOwnProperty(name)) {
288+
if (type) {
289+
store[name].type = type;
290+
}
288291
return store[name];
289292
}
290293

291294
const variable = {
292295
id: Blockly.utils.genUid(),
293296
name: name,
294297
scope: scope,
295-
type: type
298+
type: type ? type : Variable.SCALAR_TYPE
296299
};
297300
store[variable.name] = variable;
298301
return variable;
299302
}
300303

304+
_changeVariableBlock (block, opcode, blockType, varType) {
305+
block.opcode = opcode;
306+
this._setBlockType(block, blockType);
307+
308+
let before;
309+
let after;
310+
if (varType === Variable.SCALAR_TYPE) {
311+
before = 'LIST';
312+
after = 'VARIABLE';
313+
} else {
314+
before = 'VARIABLE';
315+
after = 'LIST';
316+
}
317+
if (block.fields[before]) {
318+
block.fields[after] = block.fields[before];
319+
block.fields[after].name = after;
320+
delete block.fields[before];
321+
322+
const varName = block.fields[after].value;
323+
const variable = this.instanceVariables[varName] || this.globalVariables[varName];
324+
variable.type = varType;
325+
}
326+
return block;
327+
}
328+
301329
_getSource (node) {
302330
const expression = node.$loc().$expression();
303331
if (expression === Opal.nil) {
@@ -352,6 +380,10 @@ class RubyToBlocksConverter {
352380
return _.isString(stringOrBlock) || this._isBlock(stringOrBlock);
353381
}
354382

383+
_isVariableBlock (block) {
384+
return this._isBlock(block) && ['data_variable', 'data_listcontents'].indexOf(block.opcode) >= 0;
385+
}
386+
355387
_matchRubyExpression (block, regexp) {
356388
if (!this._isBlock(block) || block.opcode !== 'ruby_expression') {
357389
return false;
@@ -629,7 +661,7 @@ class RubyToBlocksConverter {
629661
opcode = 'data_hidevariable';
630662
break;
631663
}
632-
const variable = this._findOrCreateVariable(args[0]);
664+
const variable = this._findOrCreateVariable(args[0], Variable.SCALAR_TYPE);
633665
if (variable.scope !== 'local') {
634666
block = this._createBlock(opcode, 'statement', {
635667
fields: {
@@ -643,12 +675,104 @@ class RubyToBlocksConverter {
643675
}
644676
}
645677
break;
678+
case 'show_list':
679+
case 'hide_list':
680+
if (args.length === 1 && _.isString(args[0])) {
681+
let opcode;
682+
switch (name) {
683+
case 'show_list':
684+
opcode = 'data_showlist';
685+
break;
686+
case 'hide_list':
687+
opcode = 'data_hidelist';
688+
break;
689+
}
690+
const variable = this._findOrCreateVariable(args[0], Variable.LIST_TYPE);
691+
if (variable.scope !== 'local') {
692+
block = this._createBlock(opcode, 'statement', {
693+
fields: {
694+
LIST: {
695+
name: 'LIST',
696+
id: variable.id,
697+
value: variable.name
698+
}
699+
}
700+
});
701+
}
702+
}
703+
break;
646704
case 'wait':
647705
if (args.length === 0) {
648706
block = this._createBlock('ruby_statement', 'statement');
649707
this._addInput(block, 'STATEMENT', this._createTextBlock('wait', block.id));
650708
}
651709
}
710+
} else if (this._isVariableBlock(receiver)) {
711+
switch (name) {
712+
case 'push':
713+
if (args.length === 1 &&
714+
this._isStringOrBlock(args[0])) {
715+
block = this._changeVariableBlock(receiver, 'data_addtolist', 'statement', Variable.LIST_TYPE);
716+
this._addInput(block, 'ITEM', this._createTextBlock(args[0], block.id));
717+
}
718+
break;
719+
case 'delete_at':
720+
if (args.length === 1 &&
721+
this._isNumberOrBlock(args[0])) {
722+
block = this._changeVariableBlock(receiver, 'data_deleteoflist', 'statement', Variable.LIST_TYPE);
723+
this._addInput(block, 'INDEX', this._createNumberBlock('math_number', args[0], block.id));
724+
}
725+
break;
726+
case 'clear':
727+
if (args.length === 0) {
728+
block = this._changeVariableBlock(receiver, 'data_deletealloflist', 'statement', Variable.LIST_TYPE);
729+
}
730+
break;
731+
case 'insert':
732+
if (args.length === 2 &&
733+
this._isNumberOrBlock(args[0]) &&
734+
this._isStringOrBlock(args[1])) {
735+
block = this._changeVariableBlock(receiver, 'data_insertatlist', 'statement', Variable.LIST_TYPE);
736+
this._addInput(block, 'INDEX', this._createNumberBlock('math_number', args[0], block.id));
737+
this._addInput(block, 'ITEM', this._createTextBlock(args[1], block.id));
738+
}
739+
break;
740+
case '[]=':
741+
if (args.length === 2 &&
742+
this._isNumberOrBlock(args[0]) &&
743+
this._isStringOrBlock(args[1])) {
744+
block = this._changeVariableBlock(receiver, 'data_replaceitemoflist', 'statement', Variable.LIST_TYPE);
745+
this._addInput(block, 'INDEX', this._createNumberBlock('math_number', args[0], block.id));
746+
this._addInput(block, 'ITEM', this._createTextBlock(args[1], block.id));
747+
}
748+
break;
749+
case '[]':
750+
if (args.length === 1 &&
751+
this._isNumberOrBlock(args[0])) {
752+
block = this._changeVariableBlock(receiver, 'data_itemoflist', 'value', Variable.LIST_TYPE);
753+
this._addInput(block, 'INDEX', this._createNumberBlock('math_number', args[0], block.id));
754+
}
755+
break;
756+
case 'index':
757+
if (args.length === 1 &&
758+
this._isStringOrBlock(args[0])) {
759+
block = this._changeVariableBlock(receiver, 'data_itemnumoflist', 'value', Variable.LIST_TYPE);
760+
this._addInput(block, 'ITEM', this._createTextBlock(args[0], block.id));
761+
}
762+
break;
763+
case 'length':
764+
if (args.length === 0) {
765+
block = this._changeVariableBlock(receiver, 'data_lengthoflist', 'value', Variable.LIST_TYPE);
766+
}
767+
break;
768+
case 'include?':
769+
if (args.length === 1 &&
770+
this._isStringOrBlock(args[0])) {
771+
block = this._changeVariableBlock(receiver, 'data_listcontainsitem', 'value', Variable.LIST_TYPE);
772+
this._addInput(block, 'ITEM', this._createTextBlock(args[0], block.id));
773+
}
774+
break;
775+
}
652776
} else {
653777
switch (name) {
654778
case '+':
@@ -722,8 +846,8 @@ class RubyToBlocksConverter {
722846
}
723847
break;
724848
case '[]':
725-
if (args.length === 1 &&
726-
this._isStringOrBlock(receiver) && this._isNumberOrBlock(args[0])) {
849+
if (this._isStringOrBlock(receiver) &&
850+
args.length === 1 && this._isNumberOrBlock(args[0])) {
727851
block = this._createBlock('operator_letter_of', 'value');
728852
this._addInput(block, 'STRING', this._createTextBlock(receiver, block.id));
729853
this._addInput(block, 'LETTER', this._createNumberBlock('math_number', args[0], block.id));
@@ -813,7 +937,7 @@ class RubyToBlocksConverter {
813937
}
814938
break;
815939
}
816-
case '**': {
940+
case '**':
817941
if (args.length === 1 && this._isNumberOrBlock(args[0])) {
818942
let operator;
819943
if (this._matchRubyExpression(receiver, /^(::)?Math::E$/)) {
@@ -838,7 +962,6 @@ class RubyToBlocksConverter {
838962
}
839963
break;
840964
}
841-
}
842965
}
843966
if (!block) {
844967
receiverAndArgsBlockIds.forEach(blockId => {
@@ -1008,7 +1131,7 @@ class RubyToBlocksConverter {
10081131
break;
10091132
}
10101133
} else if (_.isString(lh)) {
1011-
const variable = this._findOrCreateVariable(lh);
1134+
const variable = this._findOrCreateVariable(lh, Variable.SCALAR_TYPE);
10121135
if (variable.scope !== 'local') {
10131136
block = this._createBlock('data_changevariableby', 'statement', {
10141137
fields: {
@@ -1107,10 +1230,19 @@ class RubyToBlocksConverter {
11071230

11081231
const variable = this._findOrCreateVariable(node.children[0]);
11091232
if (variable.scope !== 'local') {
1110-
return this._createBlock('data_variable', 'value', {
1233+
let opcode;
1234+
let name;
1235+
if (variable.type === Variable.SCALAR_TYPE) {
1236+
opcode = 'data_variable';
1237+
name = 'VARIABLE';
1238+
} else {
1239+
opcode = 'data_listcontents';
1240+
name = 'LIST';
1241+
}
1242+
return this._createBlock(opcode, 'value', {
11111243
fields: {
1112-
VARIABLE: {
1113-
name: 'VARIABLE',
1244+
[name]: {
1245+
name: name,
11141246
id: variable.id,
11151247
value: variable.name
11161248
}
@@ -1136,7 +1268,7 @@ class RubyToBlocksConverter {
11361268
return node.children[0].toString();
11371269
}
11381270

1139-
const variable = this._findOrCreateVariable(node.children[0]);
1271+
const variable = this._findOrCreateVariable(node.children[0], Variable.SCALAR_TYPE);
11401272
if (variable.scope !== 'local') {
11411273
const rh = this._process(node.children[1]);
11421274
const block = this._createBlock('data_setvariableto', 'statement', {

0 commit comments

Comments
 (0)