loops.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /**
  2. * @license
  3. * Visual Blocks Language
  4. *
  5. * Copyright 2012 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 JavaScript for loop blocks.
  22. * @author fraser@google.com (Neil Fraser)
  23. */
  24. 'use strict';
  25. goog.provide('Blockly.JavaScript.loops');
  26. goog.require('Blockly.JavaScript');
  27. Blockly.JavaScript['controls_repeat_ext'] = function(block) {
  28. // Repeat n times.
  29. if (block.getField('TIMES')) {
  30. // Internal number.
  31. var repeats = String(Number(block.getFieldValue('TIMES')));
  32. } else {
  33. // External number.
  34. var repeats = Blockly.JavaScript.valueToCode(block, 'TIMES',
  35. Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  36. }
  37. var branch = Blockly.JavaScript.statementToCode(block, 'DO');
  38. branch = Blockly.JavaScript.addLoopTrap(branch, block.id);
  39. var code = '';
  40. var loopVar = Blockly.JavaScript.variableDB_.getDistinctName(
  41. 'count', Blockly.Variables.NAME_TYPE);
  42. var endVar = repeats;
  43. if (!repeats.match(/^\w+$/) && !Blockly.isNumber(repeats)) {
  44. var endVar = Blockly.JavaScript.variableDB_.getDistinctName(
  45. 'repeat_end', Blockly.Variables.NAME_TYPE);
  46. code += 'var ' + endVar + ' = ' + repeats + ';\n';
  47. }
  48. code += 'for (var ' + loopVar + ' = 0; ' +
  49. loopVar + ' < ' + endVar + '; ' +
  50. loopVar + '++) {\n' +
  51. branch + '}\n';
  52. return code;
  53. };
  54. Blockly.JavaScript['controls_repeat'] =
  55. Blockly.JavaScript['controls_repeat_ext'];
  56. Blockly.JavaScript['controls_whileUntil'] = function(block) {
  57. // Do while/until loop.
  58. var until = block.getFieldValue('MODE') == 'UNTIL';
  59. var argument0 = Blockly.JavaScript.valueToCode(block, 'BOOL',
  60. until ? Blockly.JavaScript.ORDER_LOGICAL_NOT :
  61. Blockly.JavaScript.ORDER_NONE) || 'false';
  62. var branch = Blockly.JavaScript.statementToCode(block, 'DO');
  63. branch = Blockly.JavaScript.addLoopTrap(branch, block.id);
  64. if (until) {
  65. argument0 = '!' + argument0;
  66. }
  67. return 'while (' + argument0 + ') {\n' + branch + '}\n';
  68. };
  69. Blockly.JavaScript['controls_for'] = function(block) {
  70. // For loop.
  71. var variable0 = Blockly.JavaScript.variableDB_.getName(
  72. block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
  73. var argument0 = Blockly.JavaScript.valueToCode(block, 'FROM',
  74. Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  75. var argument1 = Blockly.JavaScript.valueToCode(block, 'TO',
  76. Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  77. var increment = Blockly.JavaScript.valueToCode(block, 'BY',
  78. Blockly.JavaScript.ORDER_ASSIGNMENT) || '1';
  79. var branch = Blockly.JavaScript.statementToCode(block, 'DO');
  80. branch = Blockly.JavaScript.addLoopTrap(branch, block.id);
  81. var code;
  82. if (Blockly.isNumber(argument0) && Blockly.isNumber(argument1) &&
  83. Blockly.isNumber(increment)) {
  84. // All arguments are simple numbers.
  85. var up = parseFloat(argument0) <= parseFloat(argument1);
  86. code = 'for (' + variable0 + ' = ' + argument0 + '; ' +
  87. variable0 + (up ? ' <= ' : ' >= ') + argument1 + '; ' +
  88. variable0;
  89. var step = Math.abs(parseFloat(increment));
  90. if (step == 1) {
  91. code += up ? '++' : '--';
  92. } else {
  93. code += (up ? ' += ' : ' -= ') + step;
  94. }
  95. code += ') {\n' + branch + '}\n';
  96. } else {
  97. code = '';
  98. // Cache non-trivial values to variables to prevent repeated look-ups.
  99. var startVar = argument0;
  100. if (!argument0.match(/^\w+$/) && !Blockly.isNumber(argument0)) {
  101. startVar = Blockly.JavaScript.variableDB_.getDistinctName(
  102. variable0 + '_start', Blockly.Variables.NAME_TYPE);
  103. code += 'var ' + startVar + ' = ' + argument0 + ';\n';
  104. }
  105. var endVar = argument1;
  106. if (!argument1.match(/^\w+$/) && !Blockly.isNumber(argument1)) {
  107. var endVar = Blockly.JavaScript.variableDB_.getDistinctName(
  108. variable0 + '_end', Blockly.Variables.NAME_TYPE);
  109. code += 'var ' + endVar + ' = ' + argument1 + ';\n';
  110. }
  111. // Determine loop direction at start, in case one of the bounds
  112. // changes during loop execution.
  113. var incVar = Blockly.JavaScript.variableDB_.getDistinctName(
  114. variable0 + '_inc', Blockly.Variables.NAME_TYPE);
  115. code += 'var ' + incVar + ' = ';
  116. if (Blockly.isNumber(increment)) {
  117. code += Math.abs(increment) + ';\n';
  118. } else {
  119. code += 'Math.abs(' + increment + ');\n';
  120. }
  121. code += 'if (' + startVar + ' > ' + endVar + ') {\n';
  122. code += Blockly.JavaScript.INDENT + incVar + ' = -' + incVar + ';\n';
  123. code += '}\n';
  124. code += 'for (' + variable0 + ' = ' + startVar + ';\n' +
  125. ' ' + incVar + ' >= 0 ? ' +
  126. variable0 + ' <= ' + endVar + ' : ' +
  127. variable0 + ' >= ' + endVar + ';\n' +
  128. ' ' + variable0 + ' += ' + incVar + ') {\n' +
  129. branch + '}\n';
  130. }
  131. return code;
  132. };
  133. Blockly.JavaScript['controls_forEach'] = function(block) {
  134. // For each loop.
  135. var variable0 = Blockly.JavaScript.variableDB_.getName(
  136. block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
  137. var argument0 = Blockly.JavaScript.valueToCode(block, 'LIST',
  138. Blockly.JavaScript.ORDER_ASSIGNMENT) || '[]';
  139. var branch = Blockly.JavaScript.statementToCode(block, 'DO');
  140. branch = Blockly.JavaScript.addLoopTrap(branch, block.id);
  141. var code = '';
  142. // Cache non-trivial values to variables to prevent repeated look-ups.
  143. var listVar = argument0;
  144. if (!argument0.match(/^\w+$/)) {
  145. listVar = Blockly.JavaScript.variableDB_.getDistinctName(
  146. variable0 + '_list', Blockly.Variables.NAME_TYPE);
  147. code += 'var ' + listVar + ' = ' + argument0 + ';\n';
  148. }
  149. var indexVar = Blockly.JavaScript.variableDB_.getDistinctName(
  150. variable0 + '_index', Blockly.Variables.NAME_TYPE);
  151. branch = Blockly.JavaScript.INDENT + variable0 + ' = ' +
  152. listVar + '[' + indexVar + '];\n' + branch;
  153. code += 'for (var ' + indexVar + ' in ' + listVar + ') {\n' + branch + '}\n';
  154. return code;
  155. };
  156. Blockly.JavaScript['controls_flow_statements'] = function(block) {
  157. // Flow statements: continue, break.
  158. switch (block.getFieldValue('FLOW')) {
  159. case 'BREAK':
  160. return 'break;\n';
  161. case 'CONTINUE':
  162. return 'continue;\n';
  163. }
  164. throw 'Unknown flow statement.';
  165. };