Skip to content

Commit 000f484

Browse files
authored
Merge pull request #153 from smalruby/issues/134_control2
convert Control blocks to Ruby. refs 134
2 parents 6ce5574 + 25ec89f commit 000f484

File tree

3 files changed

+702
-138
lines changed

3 files changed

+702
-138
lines changed

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* global Opal */
2+
import _ from 'lodash';
23

34
/* eslint-disable no-invalid-this */
45
const createControlRepeatBlock = function (times, body) {
@@ -39,6 +40,43 @@ const ControlConverter = {
3940
this._addSubstack(block, rubyBlock);
4041
}
4142
break;
43+
case 'stop':
44+
if (args.length === 1 &&
45+
_.isString(args[0]) && ['all', 'this script', 'other scripts in sprite'].indexOf(args[0]) >= 0) {
46+
block = this._createBlock('control_stop', 'statement');
47+
this._addField(block, 'STOP_OPTION', args[0]);
48+
}
49+
break;
50+
case 'create_clone':
51+
if (args.length === 1 && _.isString(args[0])) {
52+
block = this._createBlock('control_create_clone_of', 'statement');
53+
const optionBlock = this._createBlock('control_create_clone_of_menu', 'value', {
54+
shadow: true
55+
});
56+
this._addField(optionBlock, 'CLONE_OPTION', args[0]);
57+
this._addInput(block, 'CLONE_OPTION', optionBlock, optionBlock);
58+
}
59+
break;
60+
case 'delete_this_clone':
61+
if (args.length === 0) {
62+
block = this._createBlock('control_delete_this_clone', 'statement');
63+
}
64+
break;
65+
case 'when':
66+
if (args.length === 1 &&
67+
_.isString(args[0]) && args[0] === 'start_as_a_clone' &&
68+
rubyBlockArgs && rubyBlockArgs.length === 0 &&
69+
rubyBlock) {
70+
block = this._createBlock('control_start_as_clone', 'hat', {
71+
topLevel: true
72+
});
73+
74+
if (this._isBlock(rubyBlock[0])) {
75+
rubyBlock[0].parent = block.id;
76+
block.next = rubyBlock[0].id;
77+
}
78+
}
79+
break;
4280
}
4381
} else if (this._isNumberOrBlock(receiver)) {
4482
switch (name) {
@@ -55,6 +93,32 @@ const ControlConverter = {
5593
}
5694
}
5795
return block;
96+
},
97+
98+
onIf: function (cond, statement, elseStatement) {
99+
const block = this._createBlock('control_if', 'statement');
100+
if (cond !== false) {
101+
this._addInput(block, 'CONDITION', cond);
102+
}
103+
this._addSubstack(block, statement);
104+
if (elseStatement) {
105+
block.opcode = 'control_if_else';
106+
this._addSubstack(block, elseStatement, 2);
107+
}
108+
return block;
109+
},
110+
111+
onUntil: function (cond, statement) {
112+
const block = this._createBlock('control_repeat_until', 'statement');
113+
if (cond !== false) {
114+
this._addInput(block, 'CONDITION', cond);
115+
}
116+
if (statement.length === 1 && this._popWaitBlock(statement)) {
117+
block.opcode = 'control_wait_until';
118+
} else {
119+
this._addSubstack(block, statement);
120+
}
121+
return block;
58122
}
59123
};
60124

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

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,17 @@ class RubyToBlocksConverter {
310310
return block;
311311
}
312312

313+
_addField (block, name, value) {
314+
if (!this._isBlock(block)) {
315+
return;
316+
}
317+
block.fields[name] = {
318+
name: name,
319+
value: value
320+
};
321+
return block.fields[name];
322+
}
323+
313324
_addInput (block, name, inputBlock, shadowBlock) {
314325
if (!name) {
315326
name = inputBlock.id;
@@ -468,6 +479,20 @@ class RubyToBlocksConverter {
468479
return null;
469480
}
470481

482+
_processCondition (node) {
483+
let cond = this._process(node.children[0]);
484+
if (_.isArray(cond) && cond.length === 1) {
485+
cond = cond[0];
486+
}
487+
if (!this._isFalseOrBooleanBlock(cond)) {
488+
throw new RubyToBlocksConverterError(
489+
node,
490+
`condition is not boolean: ${this._getSource(node.children[0])}`
491+
);
492+
}
493+
return cond;
494+
}
495+
471496
_getBlockType (block) {
472497
return this._context.blockTypes[block.id];
473498
}
@@ -1225,28 +1250,45 @@ class RubyToBlocksConverter {
12251250
this._checkNumChildren(node, 3);
12261251

12271252
const saved = this._saveContext();
1228-
let cond = this._process(node.children[0]);
1229-
if (!this._isFalseOrBooleanBlock(cond)) {
1230-
this._restoreContext(saved);
1231-
cond = this._createRubyExpressionBlock(this._getSource(node.children[0]));
1232-
}
1253+
1254+
const cond = this._processCondition(node);
12331255
let statement = this._process(node.children[1]);
12341256
if (!_.isArray(statement)) {
12351257
statement = [statement];
12361258
}
1237-
let elseStatement = this._process(node.children[2]);
1238-
if (!_.isArray(elseStatement)) {
1239-
elseStatement = [elseStatement];
1259+
let elseStatement;
1260+
if (node.$loc().$else() !== Opal.nil) {
1261+
elseStatement = this._process(node.children[2]);
1262+
if (!_.isArray(elseStatement)) {
1263+
elseStatement = [elseStatement];
1264+
}
12401265
}
12411266

1242-
const block = this._createBlock('control_if', 'statement');
1243-
if (cond !== false) {
1244-
this._addInput(block, 'CONDITION', cond);
1267+
let block = this._callConvertersHandler('onIf', cond, statement, elseStatement);
1268+
if (!block) {
1269+
this._restoreContext(saved);
1270+
1271+
block = this._createRubyStatementBlock(this._getSource(node));
1272+
}
1273+
return block;
1274+
}
1275+
1276+
_onUntil (node) {
1277+
this._checkNumChildren(node, 2);
1278+
1279+
const saved = this._saveContext();
1280+
1281+
const cond = this._processCondition(node);
1282+
let statement = this._process(node.children[1]);
1283+
if (!_.isArray(statement)) {
1284+
statement = [statement];
12451285
}
1246-
this._addSubstack(block, statement);
1247-
if (this._isBlock(elseStatement[0])) {
1248-
block.opcode = 'control_if_else';
1249-
this._addSubstack(block, elseStatement, 2);
1286+
1287+
let block = this._callConvertersHandler('onUntil', cond, statement);
1288+
if (!block) {
1289+
this._restoreContext(saved);
1290+
1291+
block = this._createRubyStatementBlock(this._getSource(node));
12501292
}
12511293
return block;
12521294
}

0 commit comments

Comments
 (0)