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
61 changes: 31 additions & 30 deletions src/lib/ruby-to-blocks-converter/control.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,36 +20,6 @@ const StopOptions = [
*/
const ControlConverter = {

onIf: function (cond, statement, elseStatement) {
const block = this._createBlock('control_if', 'statement');
if (!this._isFalse(cond)) {
this._addInput(block, 'CONDITION', cond);
}
this._addSubstack(block, statement);
if (elseStatement) {
block.opcode = 'control_if_else';
this._addSubstack(block, elseStatement, 2);
}
return block;
},

onUntil: function (cond, statement) {
statement = this._removeWaitBlocks(statement);

let opcode;
if (statement === null) {
opcode = 'control_wait_until';
} else {
opcode = 'control_repeat_until';
}
const block = this._createBlock(opcode, 'statement');
if (!this._isFalse(cond)) {
this._addInput(block, 'CONDITION', cond);
}
this._addSubstack(block, statement);
return block;
},

register: function (converter) {
// sleep(duration) - control_wait
converter.registerCallMethod('self', 'sleep', 1, params => {
Expand Down Expand Up @@ -145,6 +115,37 @@ const ControlConverter = {

return null;
});

// Register onXxx handlers
converter.registerOnIf((cond, statement, elseStatement) => {
const block = converter._createBlock('control_if', 'statement');
if (!converter._isFalse(cond)) {
converter._addInput(block, 'CONDITION', cond);
}
converter._addSubstack(block, statement);
if (elseStatement) {
block.opcode = 'control_if_else';
converter._addSubstack(block, elseStatement, 2);
}
return block;
});

converter.registerOnUntil((cond, statement) => {
statement = converter._removeWaitBlocks(statement);

let opcode;
if (statement === null) {
opcode = 'control_wait_until';
} else {
opcode = 'control_repeat_until';
}
const block = converter._createBlock(opcode, 'statement');
if (!converter._isFalse(cond)) {
converter._addInput(block, 'CONDITION', cond);
}
converter._addSubstack(block, statement);
return block;
});
}
};

Expand Down
101 changes: 80 additions & 21 deletions src/lib/ruby-to-blocks-converter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,27 +89,16 @@ class RubyToBlocksConverter {
constructor (vm) {
this.vm = vm;
this._translator = message => message.defaultMessage;
this._converters = [
MusicConverter,
PenConverter,
EV3Converter,
GdxForConverter,
SmalrubotS1Converter,
BoostConverter,
TranslateConverter,
MakeyMakeyConverter,

MotionConverter,
LooksConverter,
SoundConverter,
ControlConverter,
SensingConverter,
OperatorsConverter,
VariablesConverter,
MyBlocksConverter
];
this._receiverToMethods = {};
this._receiverToMyBlocks = {};
this._onIfHandlers = [];
this._onUntilHandlers = [];
this._onOpAsgnHandlers = [];
this._onAndHandlers = [];
this._onOrHandlers = [];
this._onVarHandlers = [];
this._onVasgnHandlers = [];
this._onDefsHandlers = [];
this.reset();

[
Expand Down Expand Up @@ -368,6 +357,38 @@ class RubyToBlocksConverter {
this._receiverToMyBlocks[receiverName].push(myBlockHandler);
}

registerOnIf (handler) {
this._onIfHandlers.push(handler);
}

registerOnUntil (handler) {
this._onUntilHandlers.push(handler);
}

registerOnOpAsgn (handler) {
this._onOpAsgnHandlers.push(handler);
}

registerOnAnd (handler) {
this._onAndHandlers.push(handler);
}

registerOnOr (handler) {
this._onOrHandlers.push(handler);
}

registerOnVar (handler) {
this._onVarHandlers.push(handler);
}

registerOnVasgn (handler) {
this._onVasgnHandlers.push(handler);
}

registerOnDefs (handler) {
this._onDefsHandlers.push(handler);
}

callMethod (receiver, name, args, rubyBlockArgs, rubyBlock, node) {
const receiverName = this._getReceiverName(receiver);
if (!receiverName) return null;
Expand Down Expand Up @@ -531,15 +552,53 @@ class RubyToBlocksConverter {
}

_callConvertersHandler (handlerName, ...args) {
for (let i = 0; i < this._converters.length; i++) {
const converter = this._converters[i];
// First, check registered handlers based on handlerName
const handlersMap = {
onIf: this._onIfHandlers,
onUntil: this._onUntilHandlers,
onOpAsgn: this._onOpAsgnHandlers,
onAnd: this._onAndHandlers,
onOr: this._onOrHandlers,
onVar: this._onVarHandlers,
onVasgn: this._onVasgnHandlers,
onDefs: this._onDefsHandlers
};

const handlers = handlersMap[handlerName];
if (handlers) {
for (const handler of handlers) {
const block = handler.apply(this, args);
if (block) {
return block;
}
}
}

// Then, check legacy converter objects for remaining unmigrated handlers
const legacyConverters = [
MusicConverter,
PenConverter,
EV3Converter,
GdxForConverter,
SmalrubotS1Converter,
BoostConverter,
TranslateConverter,
MakeyMakeyConverter,
LooksConverter,
SoundConverter,
SensingConverter
];

for (let i = 0; i < legacyConverters.length; i++) {
const converter = legacyConverters[i];
if (Object.prototype.hasOwnProperty.call(converter, handlerName)) {
const block = converter[handlerName].apply(this, args);
if (block) {
return block;
}
}
}

return null;
}

Expand Down
46 changes: 23 additions & 23 deletions src/lib/ruby-to-blocks-converter/motion.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,31 +139,31 @@ const MotionConverter = {
// direction getter
converter.registerCallMethod('sprite', 'direction', 0, () =>
converter._createBlock('motion_direction', 'value'));
},

// Handle compound assignments like x += value, y += value
onOpAsgn: function (lh, operator, rh) {
let block;
if (this._isBlock(lh) && operator === '+' && this._isNumberOrBlock(rh)) {
let xy;
switch (lh.opcode) {
case 'motion_xposition':
case 'motion_yposition':
// All Motion blocks are sprite-only
if (this._isStage()) {
throw new RubyToBlocksConverterError(lh.node, 'Stage selected: no motion blocks');
}
if (lh.opcode === 'motion_xposition') {
xy = 'x';
} else {
xy = 'y';

// Register onXxx handlers
converter.registerOnOpAsgn((lh, operator, rh) => {
let block;
if (converter._isBlock(lh) && operator === '+' && converter._isNumberOrBlock(rh)) {
let xy;
switch (lh.opcode) {
case 'motion_xposition':
case 'motion_yposition':
// All Motion blocks are sprite-only
if (converter._isStage()) {
throw new RubyToBlocksConverterError(lh.node, 'Stage selected: no motion blocks');
}
if (lh.opcode === 'motion_xposition') {
xy = 'x';
} else {
xy = 'y';
}
block = converter._changeBlock(lh, `motion_change${xy}by`, 'statement');
converter._addNumberInput(block, `D${_.toUpper(xy)}`, 'math_number', rh, 10);
break;
}
block = this._changeBlock(lh, `motion_change${xy}by`, 'statement');
this._addNumberInput(block, `D${_.toUpper(xy)}`, 'math_number', rh, 10);
break;
}
}
return block;
return block;
});
}
};

Expand Down
Loading
Loading