summaryrefslogtreecommitdiff
path: root/blockly/generators/lua/loops.js
diff options
context:
space:
mode:
Diffstat (limited to 'blockly/generators/lua/loops.js')
-rw-r--r--blockly/generators/lua/loops.js166
1 files changed, 166 insertions, 0 deletions
diff --git a/blockly/generators/lua/loops.js b/blockly/generators/lua/loops.js
new file mode 100644
index 0000000..785398f
--- /dev/null
+++ b/blockly/generators/lua/loops.js
@@ -0,0 +1,166 @@
+/**
+ * @license
+ * Visual Blocks Language
+ *
+ * Copyright 2016 Google Inc.
+ * https://developers.google.com/blockly/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview Generating Lua for loop blocks.
+ * @author rodrigoq@google.com (Rodrigo Queiro)
+ */
+'use strict';
+
+goog.provide('Blockly.Lua.loops');
+
+goog.require('Blockly.Lua');
+
+
+/**
+ * This is the text used to implement a <pre>continue</pre>.
+ * It is also used to recognise <pre>continue</pre>s in generated code so that
+ * the appropriate label can be put at the end of the loop body.
+ * @const {string}
+ */
+Blockly.Lua.CONTINUE_STATEMENT = 'goto continue\n';
+
+/**
+ * If the loop body contains a "goto continue" statement, add a continue label
+ * to the loop body. Slightly inefficient, as continue labels will be generated
+ * in all outer loops, but this is safer than duplicating the logic of
+ * blockToCode.
+ *
+ * @param {string} branch Generated code of the loop body
+ * @return {string} Generated label or '' if unnecessary
+ */
+Blockly.Lua.addContinueLabel = function(branch) {
+ if (branch.indexOf(Blockly.Lua.CONTINUE_STATEMENT) > -1) {
+ return branch + Blockly.Lua.INDENT + '::continue::\n';
+ } else {
+ return branch;
+ }
+};
+
+Blockly.Lua['controls_repeat'] = function(block) {
+ // Repeat n times (internal number).
+ var repeats = parseInt(block.getFieldValue('TIMES'), 10);
+ var branch = Blockly.Lua.statementToCode(block, 'DO') || '';
+ branch = Blockly.Lua.addContinueLabel(branch);
+ var loopVar = Blockly.Lua.variableDB_.getDistinctName(
+ 'count', Blockly.Variables.NAME_TYPE);
+ var code = 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' + branch + 'end\n';
+ return code;
+};
+
+Blockly.Lua['controls_repeat_ext'] = function(block) {
+ // Repeat n times (external number).
+ var repeats = Blockly.Lua.valueToCode(block, 'TIMES',
+ Blockly.Lua.ORDER_NONE) || '0';
+ if (Blockly.isNumber(repeats)) {
+ repeats = parseInt(repeats, 10);
+ } else {
+ repeats = 'math.floor(' + repeats + ')';
+ }
+ var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n';
+ branch = Blockly.Lua.addContinueLabel(branch);
+ var loopVar = Blockly.Lua.variableDB_.getDistinctName(
+ 'count', Blockly.Variables.NAME_TYPE);
+ var code = 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' +
+ branch + 'end\n';
+ return code;
+};
+
+Blockly.Lua['controls_whileUntil'] = function(block) {
+ // Do while/until loop.
+ var until = block.getFieldValue('MODE') == 'UNTIL';
+ var argument0 = Blockly.Lua.valueToCode(block, 'BOOL',
+ until ? Blockly.Lua.ORDER_UNARY :
+ Blockly.Lua.ORDER_NONE) || 'false';
+ var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n';
+ branch = Blockly.Lua.addLoopTrap(branch, block.id);
+ branch = Blockly.Lua.addContinueLabel(branch);
+ if (until) {
+ argument0 = 'not ' + argument0;
+ }
+ return 'while ' + argument0 + ' do\n' + branch + 'end\n';
+};
+
+Blockly.Lua['controls_for'] = function(block) {
+ // For loop.
+ var variable0 = Blockly.Lua.variableDB_.getName(
+ block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
+ var startVar = Blockly.Lua.valueToCode(block, 'FROM',
+ Blockly.Lua.ORDER_NONE) || '0';
+ var endVar = Blockly.Lua.valueToCode(block, 'TO',
+ Blockly.Lua.ORDER_NONE) || '0';
+ var increment = Blockly.Lua.valueToCode(block, 'BY',
+ Blockly.Lua.ORDER_NONE) || '1';
+ var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n';
+ branch = Blockly.Lua.addLoopTrap(branch, block.id);
+ branch = Blockly.Lua.addContinueLabel(branch);
+ var code = '';
+ var incValue;
+ if (Blockly.isNumber(startVar) && Blockly.isNumber(endVar) &&
+ Blockly.isNumber(increment)) {
+ // All arguments are simple numbers.
+ var up = parseFloat(startVar) <= parseFloat(endVar);
+ var step = Math.abs(parseFloat(increment));
+ incValue = (up ? '' : '-') + step;
+ } else {
+ code = '';
+ // Determine loop direction at start, in case one of the bounds
+ // changes during loop execution.
+ incValue = Blockly.Lua.variableDB_.getDistinctName(
+ variable0 + '_inc', Blockly.Variables.NAME_TYPE);
+ code += incValue + ' = ';
+ if (Blockly.isNumber(increment)) {
+ code += Math.abs(increment) + '\n';
+ } else {
+ code += 'math.abs(' + increment + ')\n';
+ }
+ code += 'if (' + startVar + ') > (' + endVar + ') then\n';
+ code += Blockly.Lua.INDENT + incValue + ' = -' + incValue + '\n';
+ code += 'end\n';
+ }
+ code += 'for ' + variable0 + ' = ' + startVar + ', ' + endVar +
+ ', ' + incValue;
+ code += ' do\n' + branch + 'end\n';
+ return code;
+};
+
+Blockly.Lua['controls_forEach'] = function(block) {
+ // For each loop.
+ var variable0 = Blockly.Lua.variableDB_.getName(
+ block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
+ var argument0 = Blockly.Lua.valueToCode(block, 'LIST',
+ Blockly.Lua.ORDER_NONE) || '{}';
+ var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n';
+ branch = Blockly.Lua.addContinueLabel(branch);
+ var code = 'for _, ' + variable0 + ' in ipairs(' + argument0 + ') do \n' +
+ branch + 'end\n';
+ return code;
+};
+
+Blockly.Lua['controls_flow_statements'] = function(block) {
+ // Flow statements: continue, break.
+ switch (block.getFieldValue('FLOW')) {
+ case 'BREAK':
+ return 'break\n';
+ case 'CONTINUE':
+ return Blockly.Lua.CONTINUE_STATEMENT;
+ }
+ throw 'Unknown flow statement.';
+};