loops.js 5.9 KB

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