Skip to content

Commit 9e0ed55

Browse files
authored
Merge pull request #145 from smalruby/issues/134_variables2
supported converting variables blocks from Ruby. refs #134
2 parents 6efdeaa + 2d5b3e2 commit 9e0ed55

File tree

3 files changed

+439
-48
lines changed

3 files changed

+439
-48
lines changed

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

Lines changed: 162 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,122 @@ 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(
716+
receiver, 'data_addtolist', 'statement', Variable.LIST_TYPE
717+
);
718+
this._addInput(block, 'ITEM', this._createTextBlock(args[0], block.id));
719+
}
720+
break;
721+
case 'delete_at':
722+
if (args.length === 1 &&
723+
this._isNumberOrBlock(args[0])) {
724+
block = this._changeVariableBlock(
725+
receiver, 'data_deleteoflist', 'statement', Variable.LIST_TYPE
726+
);
727+
this._addInput(block, 'INDEX', this._createNumberBlock('math_number', args[0], block.id));
728+
}
729+
break;
730+
case 'clear':
731+
if (args.length === 0) {
732+
block = this._changeVariableBlock(
733+
receiver, 'data_deletealloflist', 'statement', Variable.LIST_TYPE
734+
);
735+
}
736+
break;
737+
case 'insert':
738+
if (args.length === 2 &&
739+
this._isNumberOrBlock(args[0]) &&
740+
this._isStringOrBlock(args[1])) {
741+
block = this._changeVariableBlock(
742+
receiver, 'data_insertatlist', 'statement', Variable.LIST_TYPE
743+
);
744+
this._addInput(block, 'INDEX', this._createNumberBlock('math_number', args[0], block.id));
745+
this._addInput(block, 'ITEM', this._createTextBlock(args[1], block.id));
746+
}
747+
break;
748+
case '[]=':
749+
if (args.length === 2 &&
750+
this._isNumberOrBlock(args[0]) &&
751+
this._isStringOrBlock(args[1])) {
752+
block = this._changeVariableBlock(
753+
receiver, 'data_replaceitemoflist', 'statement', Variable.LIST_TYPE
754+
);
755+
this._addInput(block, 'INDEX', this._createNumberBlock('math_number', args[0], block.id));
756+
this._addInput(block, 'ITEM', this._createTextBlock(args[1], block.id));
757+
}
758+
break;
759+
case '[]':
760+
if (args.length === 1 &&
761+
this._isNumberOrBlock(args[0])) {
762+
block = this._changeVariableBlock(
763+
receiver, 'data_itemoflist', 'value', Variable.LIST_TYPE
764+
);
765+
this._addInput(block, 'INDEX', this._createNumberBlock('math_number', args[0], block.id));
766+
}
767+
break;
768+
case 'index':
769+
if (args.length === 1 &&
770+
this._isStringOrBlock(args[0])) {
771+
block = this._changeVariableBlock(
772+
receiver, 'data_itemnumoflist', 'value', Variable.LIST_TYPE
773+
);
774+
this._addInput(block, 'ITEM', this._createTextBlock(args[0], block.id));
775+
}
776+
break;
777+
case 'length':
778+
if (args.length === 0) {
779+
block = this._changeVariableBlock(
780+
receiver, 'data_lengthoflist', 'value', Variable.LIST_TYPE
781+
);
782+
}
783+
break;
784+
case 'include?':
785+
if (args.length === 1 &&
786+
this._isStringOrBlock(args[0])) {
787+
block = this._changeVariableBlock(
788+
receiver, 'data_listcontainsitem', 'value', Variable.LIST_TYPE
789+
);
790+
this._addInput(block, 'ITEM', this._createTextBlock(args[0], block.id));
791+
}
792+
break;
793+
}
652794
} else {
653795
switch (name) {
654796
case '+':
@@ -722,8 +864,8 @@ class RubyToBlocksConverter {
722864
}
723865
break;
724866
case '[]':
725-
if (args.length === 1 &&
726-
this._isStringOrBlock(receiver) && this._isNumberOrBlock(args[0])) {
867+
if (this._isStringOrBlock(receiver) &&
868+
args.length === 1 && this._isNumberOrBlock(args[0])) {
727869
block = this._createBlock('operator_letter_of', 'value');
728870
this._addInput(block, 'STRING', this._createTextBlock(receiver, block.id));
729871
this._addInput(block, 'LETTER', this._createNumberBlock('math_number', args[0], block.id));
@@ -813,7 +955,7 @@ class RubyToBlocksConverter {
813955
}
814956
break;
815957
}
816-
case '**': {
958+
case '**':
817959
if (args.length === 1 && this._isNumberOrBlock(args[0])) {
818960
let operator;
819961
if (this._matchRubyExpression(receiver, /^(::)?Math::E$/)) {
@@ -838,7 +980,6 @@ class RubyToBlocksConverter {
838980
}
839981
break;
840982
}
841-
}
842983
}
843984
if (!block) {
844985
receiverAndArgsBlockIds.forEach(blockId => {
@@ -1008,7 +1149,7 @@ class RubyToBlocksConverter {
10081149
break;
10091150
}
10101151
} else if (_.isString(lh)) {
1011-
const variable = this._findOrCreateVariable(lh);
1152+
const variable = this._findOrCreateVariable(lh, Variable.SCALAR_TYPE);
10121153
if (variable.scope !== 'local') {
10131154
block = this._createBlock('data_changevariableby', 'statement', {
10141155
fields: {
@@ -1107,10 +1248,19 @@ class RubyToBlocksConverter {
11071248

11081249
const variable = this._findOrCreateVariable(node.children[0]);
11091250
if (variable.scope !== 'local') {
1110-
return this._createBlock('data_variable', 'value', {
1251+
let opcode;
1252+
let name;
1253+
if (variable.type === Variable.SCALAR_TYPE) {
1254+
opcode = 'data_variable';
1255+
name = 'VARIABLE';
1256+
} else {
1257+
opcode = 'data_listcontents';
1258+
name = 'LIST';
1259+
}
1260+
return this._createBlock(opcode, 'value', {
11111261
fields: {
1112-
VARIABLE: {
1113-
name: 'VARIABLE',
1262+
[name]: {
1263+
name: name,
11141264
id: variable.id,
11151265
value: variable.name
11161266
}
@@ -1136,7 +1286,7 @@ class RubyToBlocksConverter {
11361286
return node.children[0].toString();
11371287
}
11381288

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

0 commit comments

Comments
 (0)