loops.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /**
  2. * @license Licensed under the Apache License, Version 2.0 (the "License"):
  3. * http://www.apache.org/licenses/LICENSE-2.0
  4. */
  5. /**
  6. * @fileoverview Generating Arduino code for the loop blocks.
  7. *
  8. * TODO: 'For each' block needs to have lists implemented.
  9. */
  10. 'use strict';
  11. goog.provide('Blockly.Python.loops');
  12. goog.require('Blockly.Python');
  13. /**
  14. * Generator for the repeat block (number in a drop down) using a For loop
  15. * statement.
  16. * Arduino code: loop { for (int count = 0; count < X; count++) { Y } }
  17. * @param {!Blockly.Block} block Block to generate the code from.
  18. * @return {string} Completed code.
  19. */
  20. Blockly.Python['controls_repeat'] = function(block) {
  21. var repeats = Number(block.getFieldValue('TIMES'));
  22. var branch = Blockly.Python.statementToCode(block, 'DO');
  23. branch = Blockly.Python.addLoopTrap(branch, block.id);
  24. var loopVar = Blockly.Python.variableDB_.getDistinctName(
  25. 'count', Blockly.Variables.NAME_TYPE);
  26. var code = 'for (int ' + loopVar + ' = 0; ' +
  27. loopVar + ' < ' + repeats + '; ' +
  28. loopVar + '++) {\n' +
  29. branch + '}\n';
  30. return code;
  31. };
  32. /**
  33. * Generator for the repeat block (using external number block) using a
  34. * For loop statement.
  35. * Arduino code: loop { for (int count = 0; count < X; count++) { Y } }
  36. * @param {!Blockly.Block} block Block to generate the code from.
  37. * @return {string} Completed code.
  38. */
  39. Blockly.Python['controls_repeat_ext'] = function(block) {
  40. var repeats = Blockly.Python.valueToCode(block, 'TIMES',
  41. Blockly.Python.ORDER_ADDITIVE) || '0';
  42. var branch = Blockly.Python.statementToCode(block, 'DO');
  43. branch = Blockly.Python.addLoopTrap(branch, block.id);
  44. var code = '';
  45. var loopVar = Blockly.Python.variableDB_.getDistinctName(
  46. 'count', Blockly.Variables.NAME_TYPE);
  47. var endVar = repeats;
  48. if (!repeats.match(/^\w+$/) && !Blockly.isNumber(repeats)) {
  49. var endVar = Blockly.Python.variableDB_.getDistinctName(
  50. 'repeat_end', Blockly.Variables.NAME_TYPE);
  51. code += 'int ' + endVar + ' = ' + repeats + ';\n';
  52. }
  53. code += 'for (int ' + loopVar + ' = 0; ' +
  54. loopVar + ' < ' + endVar + '; ' +
  55. loopVar + '++) {\n' +
  56. branch + '}\n';
  57. return code;
  58. };
  59. /**
  60. * Generator for the repeat while block using a While statement.
  61. * Arduino code: loop { while (X) { Y } }
  62. * @param {!Blockly.Block} block Block to generate the code from.
  63. * @return {string} Completed code.
  64. */
  65. Blockly.Python['controls_whileUntil'] = function(block) {
  66. // Do while/until loop.
  67. var until = block.getFieldValue('MODE') == 'UNTIL';
  68. var argument0 = Blockly.Python.valueToCode(block, 'BOOL',
  69. until ? Blockly.Python.ORDER_LOGICAL_OR :
  70. Blockly.Python.ORDER_NONE) || 'false';
  71. var branch = Blockly.Python.statementToCode(block, 'DO');
  72. branch = Blockly.Python.addLoopTrap(branch, block.id);
  73. if (until) {
  74. if (!argument0.match(/^\w+$/)) {
  75. argument0 = '(' + argument0 + ')';
  76. }
  77. argument0 = '!' + argument0;
  78. }
  79. return 'while (' + argument0 + ') {\n' + branch + '}\n';
  80. };
  81. /**
  82. * Generator for the For loop statements.
  83. * Arduino code: loop { for (i = X; i <= Y; i+=Z) { } }
  84. * @param {!Blockly.Block} block Block to generate the code from.
  85. * @return {string} Completed code.
  86. */
  87. Blockly.Python['controls_for'] = function(block) {
  88. var variable0 = Blockly.Python.variableDB_.getName(
  89. block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
  90. var argument0 = Blockly.Python.valueToCode(block, 'FROM',
  91. Blockly.Python.ORDER_ASSIGNMENT) || '0';
  92. var argument1 = Blockly.Python.valueToCode(block, 'TO',
  93. Blockly.Python.ORDER_ASSIGNMENT) || '0';
  94. var increment = Blockly.Python.valueToCode(block, 'BY',
  95. Blockly.Python.ORDER_ASSIGNMENT) || '1';
  96. var branch = Blockly.Python.statementToCode(block, 'DO');
  97. branch = Blockly.Python.addLoopTrap(branch, block.id);
  98. var code;
  99. if (Blockly.isNumber(argument0) && Blockly.isNumber(argument1) &&
  100. Blockly.isNumber(increment)) {
  101. // All arguments are simple numbers.
  102. var up = parseFloat(argument0) <= parseFloat(argument1);
  103. code = 'for (' + variable0 + ' = ' + argument0 + '; ' +
  104. variable0 + (up ? ' <= ' : ' >= ') + argument1 + '; ' +
  105. variable0;
  106. var step = Math.abs(parseFloat(increment));
  107. if (step == 1) {
  108. code += up ? '++' : '--';
  109. } else {
  110. code += (up ? ' += ' : ' -= ') + step;
  111. }
  112. code += ') {\n' + branch + '}\n';
  113. } else {
  114. code = '';
  115. // Cache non-trivial values to variables to prevent repeated look-ups.
  116. var startVar = argument0;
  117. if (!argument0.match(/^\w+$/) && !Blockly.isNumber(argument0)) {
  118. var startVar = Blockly.Python.variableDB_.getDistinctName(
  119. variable0 + '_start', Blockly.Variables.NAME_TYPE);
  120. code += 'int ' + startVar + ' = ' + argument0 + ';\n';
  121. }
  122. var endVar = argument1;
  123. if (!argument1.match(/^\w+$/) && !Blockly.isNumber(argument1)) {
  124. var endVar = Blockly.Python.variableDB_.getDistinctName(
  125. variable0 + '_end', Blockly.Variables.NAME_TYPE);
  126. code += 'int ' + endVar + ' = ' + argument1 + ';\n';
  127. }
  128. // Determine loop direction at start, in case one of the bounds
  129. // changes during loop execution.
  130. var incVar = Blockly.Python.variableDB_.getDistinctName(
  131. variable0 + '_inc', Blockly.Variables.NAME_TYPE);
  132. code += 'int ' + incVar + ' = ';
  133. if (Blockly.isNumber(increment)) {
  134. code += Math.abs(increment) + ';\n';
  135. } else {
  136. code += 'abs(' + increment + ');\n';
  137. }
  138. code += 'if (' + startVar + ' > ' + endVar + ') {\n';
  139. code += Blockly.Python.INDENT + incVar + ' = -' + incVar + ';\n';
  140. code += '}\n';
  141. code += 'for (' + variable0 + ' = ' + startVar + ';\n' +
  142. ' ' + incVar + ' >= 0 ? ' +
  143. variable0 + ' <= ' + endVar + ' : ' +
  144. variable0 + ' >= ' + endVar + ';\n' +
  145. ' ' + variable0 + ' += ' + incVar + ') {\n' +
  146. branch + '}\n';
  147. }
  148. return code;
  149. };
  150. /**
  151. * A "for each" block.
  152. * TODO: Removed for now from toolbox as lists are not yet implemented.
  153. * @param {!Blockly.Block} block Block to generate the code from.
  154. * @return {string} Completed code.
  155. */
  156. Blockly.Python['controls_forEach'] = Blockly.Python.noGeneratorCodeLine;
  157. /**
  158. * Generator for the loop flow control statements.
  159. * Arduino code: loop { break;/continue; }
  160. * @param {!Blockly.Block} block Block to generate the code from.
  161. * @return {string} Completed code.
  162. */
  163. Blockly.Python['controls_flow_statements'] = function(block) {
  164. switch (block.getFieldValue('FLOW')) {
  165. case 'BREAK':
  166. return 'break;\n';
  167. case 'CONTINUE':
  168. return 'continue;\n';
  169. }
  170. throw 'Unknown flow statement.';
  171. };