loops.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /**
  2. * @license
  3. * Visual Blocks Language
  4. *
  5. * Copyright 2016 Google Inc.
  6. * https://developers.google.com/blockly/
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. /**
  21. * @fileoverview Generating Lua for loop blocks.
  22. * @author rodrigoq@google.com (Rodrigo Queiro)
  23. */
  24. 'use strict';
  25. goog.provide('Blockly.Lua.loops');
  26. goog.require('Blockly.Lua');
  27. /**
  28. * This is the text used to implement a <pre>continue</pre>.
  29. * It is also used to recognise <pre>continue</pre>s in generated code so that
  30. * the appropriate label can be put at the end of the loop body.
  31. * @const {string}
  32. */
  33. Blockly.Lua.CONTINUE_STATEMENT = 'goto continue\n';
  34. /**
  35. * If the loop body contains a "goto continue" statement, add a continue label
  36. * to the loop body. Slightly inefficient, as continue labels will be generated
  37. * in all outer loops, but this is safer than duplicating the logic of
  38. * blockToCode.
  39. *
  40. * @param {string} branch Generated code of the loop body
  41. * @return {string} Generated label or '' if unnecessary
  42. */
  43. Blockly.Lua.addContinueLabel = function(branch) {
  44. if (branch.indexOf(Blockly.Lua.CONTINUE_STATEMENT) > -1) {
  45. return branch + Blockly.Lua.INDENT + '::continue::\n';
  46. } else {
  47. return branch;
  48. }
  49. };
  50. Blockly.Lua['controls_repeat'] = function(block) {
  51. // Repeat n times (internal number).
  52. var repeats = parseInt(block.getFieldValue('TIMES'), 10);
  53. var branch = Blockly.Lua.statementToCode(block, 'DO') || '';
  54. branch = Blockly.Lua.addContinueLabel(branch);
  55. var loopVar = Blockly.Lua.variableDB_.getDistinctName(
  56. 'count', Blockly.Variables.NAME_TYPE);
  57. var code = 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' + branch + 'end\n';
  58. return code;
  59. };
  60. Blockly.Lua['controls_repeat_ext'] = function(block) {
  61. // Repeat n times (external number).
  62. var repeats = Blockly.Lua.valueToCode(block, 'TIMES',
  63. Blockly.Lua.ORDER_NONE) || '0';
  64. if (Blockly.isNumber(repeats)) {
  65. repeats = parseInt(repeats, 10);
  66. } else {
  67. repeats = 'math.floor(' + repeats + ')';
  68. }
  69. var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n';
  70. branch = Blockly.Lua.addContinueLabel(branch);
  71. var loopVar = Blockly.Lua.variableDB_.getDistinctName(
  72. 'count', Blockly.Variables.NAME_TYPE);
  73. var code = 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' +
  74. branch + 'end\n';
  75. return code;
  76. };
  77. Blockly.Lua['controls_whileUntil'] = function(block) {
  78. // Do while/until loop.
  79. var until = block.getFieldValue('MODE') == 'UNTIL';
  80. var argument0 = Blockly.Lua.valueToCode(block, 'BOOL',
  81. until ? Blockly.Lua.ORDER_UNARY :
  82. Blockly.Lua.ORDER_NONE) || 'false';
  83. var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n';
  84. branch = Blockly.Lua.addLoopTrap(branch, block.id);
  85. branch = Blockly.Lua.addContinueLabel(branch);
  86. if (until) {
  87. argument0 = 'not ' + argument0;
  88. }
  89. return 'while ' + argument0 + ' do\n' + branch + 'end\n';
  90. };
  91. Blockly.Lua['controls_for'] = function(block) {
  92. // For loop.
  93. var variable0 = Blockly.Lua.variableDB_.getName(
  94. block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
  95. var startVar = Blockly.Lua.valueToCode(block, 'FROM',
  96. Blockly.Lua.ORDER_NONE) || '0';
  97. var endVar = Blockly.Lua.valueToCode(block, 'TO',
  98. Blockly.Lua.ORDER_NONE) || '0';
  99. var increment = Blockly.Lua.valueToCode(block, 'BY',
  100. Blockly.Lua.ORDER_NONE) || '1';
  101. var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n';
  102. branch = Blockly.Lua.addLoopTrap(branch, block.id);
  103. branch = Blockly.Lua.addContinueLabel(branch);
  104. var code = '';
  105. var incValue;
  106. if (Blockly.isNumber(startVar) && Blockly.isNumber(endVar) &&
  107. Blockly.isNumber(increment)) {
  108. // All arguments are simple numbers.
  109. var up = parseFloat(startVar) <= parseFloat(endVar);
  110. var step = Math.abs(parseFloat(increment));
  111. incValue = (up ? '' : '-') + step;
  112. } else {
  113. code = '';
  114. // Determine loop direction at start, in case one of the bounds
  115. // changes during loop execution.
  116. incValue = Blockly.Lua.variableDB_.getDistinctName(
  117. variable0 + '_inc', Blockly.Variables.NAME_TYPE);
  118. code += incValue + ' = ';
  119. if (Blockly.isNumber(increment)) {
  120. code += Math.abs(increment) + '\n';
  121. } else {
  122. code += 'math.abs(' + increment + ')\n';
  123. }
  124. code += 'if (' + startVar + ') > (' + endVar + ') then\n';
  125. code += Blockly.Lua.INDENT + incValue + ' = -' + incValue + '\n';
  126. code += 'end\n';
  127. }
  128. code += 'for ' + variable0 + ' = ' + startVar + ', ' + endVar +
  129. ', ' + incValue;
  130. code += ' do\n' + branch + 'end\n';
  131. return code;
  132. };
  133. Blockly.Lua['controls_forEach'] = function(block) {
  134. // For each loop.
  135. var variable0 = Blockly.Lua.variableDB_.getName(
  136. block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
  137. var argument0 = Blockly.Lua.valueToCode(block, 'LIST',
  138. Blockly.Lua.ORDER_NONE) || '{}';
  139. var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n';
  140. branch = Blockly.Lua.addContinueLabel(branch);
  141. var code = 'for _, ' + variable0 + ' in ipairs(' + argument0 + ') do \n' +
  142. branch + 'end\n';
  143. return code;
  144. };
  145. Blockly.Lua['controls_flow_statements'] = function(block) {
  146. // Flow statements: continue, break.
  147. switch (block.getFieldValue('FLOW')) {
  148. case 'BREAK':
  149. return 'break\n';
  150. case 'CONTINUE':
  151. return Blockly.Lua.CONTINUE_STATEMENT;
  152. }
  153. throw 'Unknown flow statement.';
  154. };