diff --git a/core/generator.ts b/core/generator.ts index 6c562fa81..2485e5898 100644 --- a/core/generator.ts +++ b/core/generator.ts @@ -24,11 +24,15 @@ import {warn} from './utils/deprecation.js'; * * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/generating-code} * @param block The Block instance to generate code for. + * @param genearator The CodeGenerator calling the function. * @returns A string containing the generated code (for statement blocks), * or a [code, precedence] tuple (for value/expression blocks), or * null if no code should be emitted for block. */ -export type BlockGenerator = (block: Block) => [string, number] | string | null; +export type BlockGenerator = ( + block: Block, + generator: CodeGenerator +) => [string, number] | string | null; /** * Class for a code generator that translates the blocks into a language. @@ -258,7 +262,7 @@ export class CodeGenerator { // The current preferred method of accessing the block is through the second // argument to func.call, which becomes the first parameter to the // generator. - let code = func.call(block, block); + let code = func.call(block, block, this); if (Array.isArray(code)) { // Value blocks return tuples of code and operator order. if (!block.outputConnection) { diff --git a/generators/dart/colour.js b/generators/dart/colour.js index 74f1406ce..f82e66977 100644 --- a/generators/dart/colour.js +++ b/generators/dart/colour.js @@ -16,18 +16,18 @@ import {dartGenerator, Order} from '../dart.js'; dartGenerator.addReservedWords('Math'); -dartGenerator.forBlock['colour_picker'] = function(block) { +dartGenerator.forBlock['colour_picker'] = function(block, generator) { // Colour picker. - const code = dartGenerator.quote_(block.getFieldValue('COLOUR')); + const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; }; -dartGenerator.forBlock['colour_random'] = function(block) { +dartGenerator.forBlock['colour_random'] = function(block, generator) { // Generate a random colour. - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = "import 'dart:math' as Math;"; - const functionName = dartGenerator.provideFunction_('colour_random', ` -String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}() { + const functionName = generator.provideFunction_('colour_random', ` +String ${generator.FUNCTION_NAME_PLACEHOLDER_}() { String hex = '0123456789abcdef'; var rnd = new Math.Random(); return '#\${hex[rnd.nextInt(16)]}\${hex[rnd.nextInt(16)]}' @@ -39,16 +39,16 @@ String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}() { return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['colour_rgb'] = function(block) { +dartGenerator.forBlock['colour_rgb'] = function(block, generator) { // Compose a colour from RGB components expressed as percentages. - const red = dartGenerator.valueToCode(block, 'RED', Order.NONE) || 0; - const green = dartGenerator.valueToCode(block, 'GREEN', Order.NONE) || 0; - const blue = dartGenerator.valueToCode(block, 'BLUE', Order.NONE) || 0; + const red = generator.valueToCode(block, 'RED', Order.NONE) || 0; + const green = generator.valueToCode(block, 'GREEN', Order.NONE) || 0; + const blue = generator.valueToCode(block, 'BLUE', Order.NONE) || 0; - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = "import 'dart:math' as Math;"; - const functionName = dartGenerator.provideFunction_('colour_rgb', ` -String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(num r, num g, num b) { + const functionName = generator.provideFunction_('colour_rgb', ` +String ${generator.FUNCTION_NAME_PLACEHOLDER_}(num r, num g, num b) { num rn = (Math.max(Math.min(r, 100), 0) * 2.55).round(); String rs = rn.toInt().toRadixString(16); rs = '0$rs'; @@ -68,19 +68,19 @@ String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(num r, num g, num b) { return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['colour_blend'] = function(block) { +dartGenerator.forBlock['colour_blend'] = function(block, generator) { // Blend two colours together. const c1 = - dartGenerator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; + generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; const c2 = - dartGenerator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; + generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; const ratio = - dartGenerator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; + generator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = "import 'dart:math' as Math;"; - const functionName = dartGenerator.provideFunction_('colour_blend', ` -String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String c1, String c2, num ratio) { + const functionName = generator.provideFunction_('colour_blend', ` +String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String c1, String c2, num ratio) { ratio = Math.max(Math.min(ratio, 1), 0); int r1 = int.parse('0x\${c1.substring(1, 3)}'); int g1 = int.parse('0x\${c1.substring(3, 5)}'); diff --git a/generators/dart/lists.js b/generators/dart/lists.js index 9a74cbbdb..2c9ef7456 100644 --- a/generators/dart/lists.js +++ b/generators/dart/lists.js @@ -17,53 +17,53 @@ import {dartGenerator, Order} from '../dart.js'; dartGenerator.addReservedWords('Math'); -dartGenerator.forBlock['lists_create_empty'] = function(block) { +dartGenerator.forBlock['lists_create_empty'] = function(block, generator) { // Create an empty list. return ['[]', Order.ATOMIC]; }; -dartGenerator.forBlock['lists_create_with'] = function(block) { +dartGenerator.forBlock['lists_create_with'] = function(block, generator) { // Create a list with any number of elements of any type. const elements = new Array(block.itemCount_); for (let i = 0; i < block.itemCount_; i++) { elements[i] = - dartGenerator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; + generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; } const code = '[' + elements.join(', ') + ']'; return [code, Order.ATOMIC]; }; -dartGenerator.forBlock['lists_repeat'] = function(block) { +dartGenerator.forBlock['lists_repeat'] = function(block, generator) { // Create a list with one element repeated. const element = - dartGenerator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; + generator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; const repeatCount = - dartGenerator.valueToCode(block, 'NUM', Order.NONE) || '0'; + generator.valueToCode(block, 'NUM', Order.NONE) || '0'; const code = 'new List.filled(' + repeatCount + ', ' + element + ')'; return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['lists_length'] = function(block) { +dartGenerator.forBlock['lists_length'] = function(block, generator) { // String or array length. const list = - dartGenerator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; return [list + '.length', Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['lists_isEmpty'] = function(block) { +dartGenerator.forBlock['lists_isEmpty'] = function(block, generator) { // Is the string null or array empty? const list = - dartGenerator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; return [list + '.isEmpty', Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['lists_indexOf'] = function(block) { +dartGenerator.forBlock['lists_indexOf'] = function(block, generator) { // Find an item in the list. const operator = block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; - const item = dartGenerator.valueToCode(block, 'FIND', Order.NONE) || "''"; + const item = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const list = - dartGenerator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; const code = list + '.' + operator + '(' + item + ')'; if (block.workspace.options.oneBasedIndex) { return [code + ' + 1', Order.ADDITIVE]; @@ -71,7 +71,7 @@ dartGenerator.forBlock['lists_indexOf'] = function(block) { return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['lists_getIndex'] = function(block) { +dartGenerator.forBlock['lists_getIndex'] = function(block, generator) { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; @@ -79,12 +79,12 @@ dartGenerator.forBlock['lists_getIndex'] = function(block) { const listOrder = (where === 'RANDOM' || where === 'FROM_END') ? Order.NONE : Order.UNARY_POSTFIX; - let list = dartGenerator.valueToCode(block, 'VALUE', listOrder) || '[]'; + let list = generator.valueToCode(block, 'VALUE', listOrder) || '[]'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. function cacheList() { const listVar = - dartGenerator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); const code = 'List ' + listVar + ' = ' + list + ';\n'; list = listVar; return code; @@ -96,12 +96,12 @@ dartGenerator.forBlock['lists_getIndex'] = function(block) { !list.match(/^\w+$/)) { // `list` is an expression, so we may not evaluate it more than once. if (where === 'RANDOM') { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; // We can use multiple statements. let code = cacheList(); const xVar = - dartGenerator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); + generator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); code += 'int ' + xVar + ' = new Math.Random().nextInt(' + list + '.length);\n'; code += list + '.removeAt(' + xVar + ');\n'; @@ -110,17 +110,17 @@ dartGenerator.forBlock['lists_getIndex'] = function(block) { if (mode === 'REMOVE') { // We can use multiple statements. const at = - dartGenerator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); + generator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); let code = cacheList(); code += list + '.removeAt(' + list + '.length' + ' - ' + at + ');\n'; return code; } else if (mode === 'GET') { - const at = dartGenerator.getAdjusted(block, 'AT', 1); + const at = generator.getAdjusted(block, 'AT', 1); // We need to create a procedure to avoid reevaluating values. - const functionName = dartGenerator.provideFunction_('lists_get_from_end', ` -dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { + const functionName = generator.provideFunction_('lists_get_from_end', ` +dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { x = my_list.length - x; return my_list[x]; } @@ -128,11 +128,11 @@ dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { const code = functionName + '(' + list + ', ' + at + ')'; return [code, Order.UNARY_POSTFIX]; } else if (mode === 'GET_REMOVE') { - const at = dartGenerator.getAdjusted(block, 'AT', 1); + const at = generator.getAdjusted(block, 'AT', 1); // We need to create a procedure to avoid reevaluating values. const functionName = - dartGenerator.provideFunction_('lists_remove_from_end', ` -dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { + generator.provideFunction_('lists_remove_from_end', ` +dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { x = my_list.length - x; return my_list.removeAt(x); } @@ -168,7 +168,7 @@ dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { } break; case 'FROM_START': { - const at = dartGenerator.getAdjusted(block, 'AT'); + const at = generator.getAdjusted(block, 'AT'); if (mode === 'GET') { const code = list + '[' + at + ']'; return [code, Order.UNARY_POSTFIX]; @@ -182,7 +182,7 @@ dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { } case 'FROM_END': { const at = - dartGenerator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); + generator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); if (mode === 'GET') { const code = list + '[' + list + '.length - ' + at + ']'; return [code, Order.UNARY_POSTFIX]; @@ -197,20 +197,20 @@ dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { break; } case 'RANDOM': - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; if (mode === 'REMOVE') { // We can use multiple statements. const xVar = - dartGenerator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); + generator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); let code = 'int ' + xVar + ' = new Math.Random().nextInt(' + list + '.length);\n'; code += list + '.removeAt(' + xVar + ');\n'; return code; } else if (mode === 'GET') { const functionName = - dartGenerator.provideFunction_('lists_get_random_item', ` -dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List my_list) { + generator.provideFunction_('lists_get_random_item', ` +dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list) { int x = new Math.Random().nextInt(my_list.length); return my_list[x]; } @@ -219,8 +219,8 @@ dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List my_list) { return [code, Order.UNARY_POSTFIX]; } else if (mode === 'GET_REMOVE') { const functionName = - dartGenerator.provideFunction_('lists_remove_random_item', ` -dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List my_list) { + generator.provideFunction_('lists_remove_random_item', ` +dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list) { int x = new Math.Random().nextInt(my_list.length); return my_list.removeAt(x); } @@ -234,15 +234,15 @@ dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List my_list) { throw Error('Unhandled combination (lists_getIndex).'); }; -dartGenerator.forBlock['lists_setIndex'] = function(block) { +dartGenerator.forBlock['lists_setIndex'] = function(block, generator) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; let list = - dartGenerator.valueToCode(block, 'LIST', Order.UNARY_POSTFIX) || '[]'; + generator.valueToCode(block, 'LIST', Order.UNARY_POSTFIX) || '[]'; const value = - dartGenerator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; + generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. function cacheList() { @@ -250,7 +250,7 @@ dartGenerator.forBlock['lists_setIndex'] = function(block) { return ''; } const listVar = - dartGenerator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); const code = 'List ' + listVar + ' = ' + list + ';\n'; list = listVar; return code; @@ -273,7 +273,7 @@ dartGenerator.forBlock['lists_setIndex'] = function(block) { } break; case 'FROM_START': { - const at = dartGenerator.getAdjusted(block, 'AT'); + const at = generator.getAdjusted(block, 'AT'); if (mode === 'SET') { return list + '[' + at + '] = ' + value + ';\n'; } else if (mode === 'INSERT') { @@ -283,7 +283,7 @@ dartGenerator.forBlock['lists_setIndex'] = function(block) { } case 'FROM_END': { const at = - dartGenerator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); + generator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); let code = cacheList(); if (mode === 'SET') { code += list + '[' + list + '.length - ' + at + '] = ' + value + ';\n'; @@ -296,11 +296,11 @@ dartGenerator.forBlock['lists_setIndex'] = function(block) { break; } case 'RANDOM': { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; let code = cacheList(); const xVar = - dartGenerator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); + generator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); code += 'int ' + xVar + ' = new Math.Random().nextInt(' + list + '.length);\n'; if (mode === 'SET') { @@ -316,10 +316,10 @@ dartGenerator.forBlock['lists_setIndex'] = function(block) { throw Error('Unhandled combination (lists_setIndex).'); }; -dartGenerator.forBlock['lists_getSublist'] = function(block) { +dartGenerator.forBlock['lists_getSublist'] = function(block, generator) { // Get sublist. const list = - dartGenerator.valueToCode(block, 'LIST', Order.UNARY_POSTFIX) || '[]'; + generator.valueToCode(block, 'LIST', Order.UNARY_POSTFIX) || '[]'; const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); let code; @@ -330,10 +330,10 @@ dartGenerator.forBlock['lists_getSublist'] = function(block) { let at1; switch (where1) { case 'FROM_START': - at1 = dartGenerator.getAdjusted(block, 'AT1'); + at1 = generator.getAdjusted(block, 'AT1'); break; case 'FROM_END': - at1 = dartGenerator.getAdjusted(block, 'AT1', 1, false, Order.ADDITIVE); + at1 = generator.getAdjusted(block, 'AT1', 1, false, Order.ADDITIVE); at1 = list + '.length - ' + at1; break; case 'FIRST': @@ -345,10 +345,10 @@ dartGenerator.forBlock['lists_getSublist'] = function(block) { let at2; switch (where2) { case 'FROM_START': - at2 = dartGenerator.getAdjusted(block, 'AT2', 1); + at2 = generator.getAdjusted(block, 'AT2', 1); break; case 'FROM_END': - at2 = dartGenerator.getAdjusted(block, 'AT2', 0, false, Order.ADDITIVE); + at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.ADDITIVE); at2 = list + '.length - ' + at2; break; case 'LAST': @@ -363,10 +363,10 @@ dartGenerator.forBlock['lists_getSublist'] = function(block) { code = list + '.sublist(' + at1 + ', ' + at2 + ')'; } } else { - const at1 = dartGenerator.getAdjusted(block, 'AT1'); - const at2 = dartGenerator.getAdjusted(block, 'AT2'); - const functionName = dartGenerator.provideFunction_('lists_get_sublist', ` -List ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List list, String where1, num at1, String where2, num at2) { + const at1 = generator.getAdjusted(block, 'AT1'); + const at2 = generator.getAdjusted(block, 'AT2'); + const functionName = generator.provideFunction_('lists_get_sublist', ` +List ${generator.FUNCTION_NAME_PLACEHOLDER_}(List list, String where1, num at1, String where2, num at2) { int getAt(String where, num at) { if (where == 'FROM_END') { at = list.length - 1 - at; @@ -390,13 +390,13 @@ List ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List list, String where1, num a return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['lists_sort'] = function(block) { +dartGenerator.forBlock['lists_sort'] = function(block, generator) { // Block for sorting a list. - const list = dartGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; const direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1; const type = block.getFieldValue('TYPE'); - const sortFunctionName = dartGenerator.provideFunction_('lists_sort', ` -List ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List list, String type, int direction) { + const sortFunctionName = generator.provideFunction_('lists_sort', ` +List ${generator.FUNCTION_NAME_PLACEHOLDER_}(List list, String type, int direction) { var compareFuncs = { 'NUMERIC': (a, b) => (direction * a.compareTo(b)).toInt(), 'TEXT': (a, b) => direction * a.toString().compareTo(b.toString()), @@ -417,11 +417,11 @@ List ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List list, String type, int dir ]; }; -dartGenerator.forBlock['lists_split'] = function(block) { +dartGenerator.forBlock['lists_split'] = function(block, generator) { // Block for splitting text into a list, or joining a list into text. - let input = dartGenerator.valueToCode(block, 'INPUT', Order.UNARY_POSTFIX); + let input = generator.valueToCode(block, 'INPUT', Order.UNARY_POSTFIX); const delimiter = - dartGenerator.valueToCode(block, 'DELIM', Order.NONE) || "''"; + generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; const mode = block.getFieldValue('MODE'); let functionName; if (mode === 'SPLIT') { @@ -441,9 +441,9 @@ dartGenerator.forBlock['lists_split'] = function(block) { return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['lists_reverse'] = function(block) { +dartGenerator.forBlock['lists_reverse'] = function(block, generator) { // Block for reversing a list. - const list = dartGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; // XXX What should the operator precedence be for a `new`? const code = 'new List.from(' + list + '.reversed)'; return [code, Order.UNARY_POSTFIX]; diff --git a/generators/dart/logic.js b/generators/dart/logic.js index e98929f78..01e4a4756 100644 --- a/generators/dart/logic.js +++ b/generators/dart/logic.js @@ -14,23 +14,23 @@ goog.declareModuleId('Blockly.Dart.logic'); import {dartGenerator, Order} from '../dart.js'; -dartGenerator.forBlock['controls_if'] = function(block) { +dartGenerator.forBlock['controls_if'] = function(block, generator) { // If/elseif/else condition. let n = 0; let code = '', branchCode, conditionCode; - if (dartGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - code += dartGenerator.injectId(dartGenerator.STATEMENT_PREFIX, block); + code += generator.injectId(generator.STATEMENT_PREFIX, block); } do { conditionCode = - dartGenerator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; - branchCode = dartGenerator.statementToCode(block, 'DO' + n); - if (dartGenerator.STATEMENT_SUFFIX) { + generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; + branchCode = generator.statementToCode(block, 'DO' + n); + if (generator.STATEMENT_SUFFIX) { branchCode = - dartGenerator.prefixLines( - dartGenerator.injectId( - dartGenerator.STATEMENT_SUFFIX, block), dartGenerator.INDENT) + + generator.prefixLines( + generator.injectId( + generator.STATEMENT_SUFFIX, block), generator.INDENT) + branchCode; } code += (n > 0 ? 'else ' : '') + 'if (' + conditionCode + ') {\n' + @@ -38,13 +38,13 @@ dartGenerator.forBlock['controls_if'] = function(block) { n++; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE') || dartGenerator.STATEMENT_SUFFIX) { - branchCode = dartGenerator.statementToCode(block, 'ELSE'); - if (dartGenerator.STATEMENT_SUFFIX) { + if (block.getInput('ELSE') || generator.STATEMENT_SUFFIX) { + branchCode = generator.statementToCode(block, 'ELSE'); + if (generator.STATEMENT_SUFFIX) { branchCode = - dartGenerator.prefixLines( - dartGenerator.injectId( - dartGenerator.STATEMENT_SUFFIX, block), dartGenerator.INDENT) + + generator.prefixLines( + generator.injectId( + generator.STATEMENT_SUFFIX, block), generator.INDENT) + branchCode; } code += ' else {\n' + branchCode + '}'; @@ -55,7 +55,7 @@ dartGenerator.forBlock['controls_if'] = function(block) { dartGenerator.forBlock['controls_ifelse'] = dartGenerator.forBlock['controls_if']; -dartGenerator.forBlock['logic_compare'] = function(block) { +dartGenerator.forBlock['logic_compare'] = function(block, generator) { // Comparison operator. const OPERATORS = {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; @@ -63,19 +63,19 @@ dartGenerator.forBlock['logic_compare'] = function(block) { const order = (operator === '==' || operator === '!=') ? Order.EQUALITY : Order.RELATIONAL; - const argument0 = dartGenerator.valueToCode(block, 'A', order) || '0'; - const argument1 = dartGenerator.valueToCode(block, 'B', order) || '0'; + const argument0 = generator.valueToCode(block, 'A', order) || '0'; + const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; -dartGenerator.forBlock['logic_operation'] = function(block) { +dartGenerator.forBlock['logic_operation'] = function(block, generator) { // Operations 'and', 'or'. const operator = (block.getFieldValue('OP') === 'AND') ? '&&' : '||'; const order = (operator === '&&') ? Order.LOGICAL_AND : Order.LOGICAL_OR; - let argument0 = dartGenerator.valueToCode(block, 'A', order); - let argument1 = dartGenerator.valueToCode(block, 'B', order); + let argument0 = generator.valueToCode(block, 'A', order); + let argument1 = generator.valueToCode(block, 'B', order); if (!argument0 && !argument1) { // If there are no arguments, then the return value is false. argument0 = 'false'; @@ -94,33 +94,33 @@ dartGenerator.forBlock['logic_operation'] = function(block) { return [code, order]; }; -dartGenerator.forBlock['logic_negate'] = function(block) { +dartGenerator.forBlock['logic_negate'] = function(block, generator) { // Negation. const order = Order.UNARY_PREFIX; - const argument0 = dartGenerator.valueToCode(block, 'BOOL', order) || 'true'; + const argument0 = generator.valueToCode(block, 'BOOL', order) || 'true'; const code = '!' + argument0; return [code, order]; }; -dartGenerator.forBlock['logic_boolean'] = function(block) { +dartGenerator.forBlock['logic_boolean'] = function(block, generator) { // Boolean values true and false. const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'true' : 'false'; return [code, Order.ATOMIC]; }; -dartGenerator.forBlock['logic_null'] = function(block) { +dartGenerator.forBlock['logic_null'] = function(block, generator) { // Null data type. return ['null', Order.ATOMIC]; }; -dartGenerator.forBlock['logic_ternary'] = function(block) { +dartGenerator.forBlock['logic_ternary'] = function(block, generator) { // Ternary operator. const value_if = - dartGenerator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; + generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; const value_then = - dartGenerator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; + generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; const value_else = - dartGenerator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'null'; + generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'null'; const code = value_if + ' ? ' + value_then + ' : ' + value_else; return [code, Order.CONDITIONAL]; }; diff --git a/generators/dart/loops.js b/generators/dart/loops.js index f57bc1811..8951d02df 100644 --- a/generators/dart/loops.js +++ b/generators/dart/loops.js @@ -16,7 +16,7 @@ import * as stringUtils from '../../core/utils/string.js'; import {NameType} from '../../core/names.js'; -dartGenerator.forBlock['controls_repeat_ext'] = function(block) { +dartGenerator.forBlock['controls_repeat_ext'] = function(block, generator) { let repeats; // Repeat n times. if (block.getField('TIMES')) { @@ -25,17 +25,17 @@ dartGenerator.forBlock['controls_repeat_ext'] = function(block) { } else { // External number. repeats = - dartGenerator.valueToCode(block, 'TIMES', Order.ASSIGNMENT) || '0'; + generator.valueToCode(block, 'TIMES', Order.ASSIGNMENT) || '0'; } - let branch = dartGenerator.statementToCode(block, 'DO'); - branch = dartGenerator.addLoopTrap(branch, block); + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); let code = ''; const loopVar = - dartGenerator.nameDB_.getDistinctName('count', NameType.VARIABLE); + generator.nameDB_.getDistinctName('count', NameType.VARIABLE); let endVar = repeats; if (!repeats.match(/^\w+$/) && !stringUtils.isNumber(repeats)) { endVar = - dartGenerator.nameDB_.getDistinctName('repeat_end', NameType.VARIABLE); + generator.nameDB_.getDistinctName('repeat_end', NameType.VARIABLE); code += 'var ' + endVar + ' = ' + repeats + ';\n'; } code += 'for (int ' + loopVar + ' = 0; ' + loopVar + ' < ' + endVar + '; ' + @@ -46,34 +46,34 @@ dartGenerator.forBlock['controls_repeat_ext'] = function(block) { dartGenerator.forBlock['controls_repeat'] = dartGenerator.forBlock['controls_repeat_ext']; -dartGenerator.forBlock['controls_whileUntil'] = function(block) { +dartGenerator.forBlock['controls_whileUntil'] = function(block, generator) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; let argument0 = - dartGenerator.valueToCode( + generator.valueToCode( block, 'BOOL', until ? Order.UNARY_PREFIX : Order.NONE) || 'false'; - let branch = dartGenerator.statementToCode(block, 'DO'); - branch = dartGenerator.addLoopTrap(branch, block); + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); if (until) { argument0 = '!' + argument0; } return 'while (' + argument0 + ') {\n' + branch + '}\n'; }; -dartGenerator.forBlock['controls_for'] = function(block) { +dartGenerator.forBlock['controls_for'] = function(block, generator) { // For loop. const variable0 = - dartGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); const argument0 = - dartGenerator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; + generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; const argument1 = - dartGenerator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; + generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; const increment = - dartGenerator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; - let branch = dartGenerator.statementToCode(block, 'DO'); - branch = dartGenerator.addLoopTrap(branch, block); + generator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); let code; if (stringUtils.isNumber(argument0) && stringUtils.isNumber(argument1) && stringUtils.isNumber(increment)) { @@ -94,21 +94,21 @@ dartGenerator.forBlock['controls_for'] = function(block) { let startVar = argument0; if (!argument0.match(/^\w+$/) && !stringUtils.isNumber(argument0)) { startVar = - dartGenerator.nameDB_.getDistinctName( + generator.nameDB_.getDistinctName( variable0 + '_start', NameType.VARIABLE); code += 'var ' + startVar + ' = ' + argument0 + ';\n'; } let endVar = argument1; if (!argument1.match(/^\w+$/) && !stringUtils.isNumber(argument1)) { endVar = - dartGenerator.nameDB_.getDistinctName( + generator.nameDB_.getDistinctName( variable0 + '_end', NameType.VARIABLE); code += 'var ' + endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. const incVar = - dartGenerator.nameDB_.getDistinctName( + generator.nameDB_.getDistinctName( variable0 + '_inc', NameType.VARIABLE); code += 'num ' + incVar + ' = '; if (stringUtils.isNumber(increment)) { @@ -117,7 +117,7 @@ dartGenerator.forBlock['controls_for'] = function(block) { code += '(' + increment + ').abs();\n'; } code += 'if (' + startVar + ' > ' + endVar + ') {\n'; - code += dartGenerator.INDENT + incVar + ' = -' + incVar + ';\n'; + code += generator.INDENT + incVar + ' = -' + incVar + ';\n'; code += '}\n'; code += 'for (' + variable0 + ' = ' + startVar + '; ' + incVar + ' >= 0 ? ' + variable0 + ' <= ' + endVar + ' : ' + variable0 + @@ -127,39 +127,39 @@ dartGenerator.forBlock['controls_for'] = function(block) { return code; }; -dartGenerator.forBlock['controls_forEach'] = function(block) { +dartGenerator.forBlock['controls_forEach'] = function(block, generator) { // For each loop. const variable0 = - dartGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); const argument0 = - dartGenerator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; - let branch = dartGenerator.statementToCode(block, 'DO'); - branch = dartGenerator.addLoopTrap(branch, block); + generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); const code = 'for (var ' + variable0 + ' in ' + argument0 + ') {\n' + branch + '}\n'; return code; }; -dartGenerator.forBlock['controls_flow_statements'] = function(block) { +dartGenerator.forBlock['controls_flow_statements'] = function(block, generator) { // Flow statements: continue, break. let xfix = ''; - if (dartGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - xfix += dartGenerator.injectId(dartGenerator.STATEMENT_PREFIX, block); + xfix += generator.injectId(generator.STATEMENT_PREFIX, block); } - if (dartGenerator.STATEMENT_SUFFIX) { + if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. - xfix += dartGenerator.injectId(dartGenerator.STATEMENT_SUFFIX, block); + xfix += generator.injectId(generator.STATEMENT_SUFFIX, block); } - if (dartGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { const loop = block.getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. - xfix += dartGenerator.injectId(dartGenerator.STATEMENT_PREFIX, loop); + xfix += generator.injectId(generator.STATEMENT_PREFIX, loop); } } switch (block.getFieldValue('FLOW')) { diff --git a/generators/dart/math.js b/generators/dart/math.js index b6bc35f8f..2233e51be 100644 --- a/generators/dart/math.js +++ b/generators/dart/math.js @@ -17,7 +17,7 @@ import {dartGenerator, Order} from '../dart.js'; dartGenerator.addReservedWords('Math'); -dartGenerator.forBlock['math_number'] = function(block) { +dartGenerator.forBlock['math_number'] = function(block, generator) { // Numeric value. let code = Number(block.getFieldValue('NUM')); let order; @@ -28,14 +28,14 @@ dartGenerator.forBlock['math_number'] = function(block) { code = '-double.infinity'; order = Order.UNARY_PREFIX; } else { - // -4.abs() returns -4 in dartGenerator due to strange order of operation choices. + // -4.abs() returns -4 in generator due to strange order of operation choices. // -4 is actually an operator and a number. Reflect this in the order. order = code < 0 ? Order.UNARY_PREFIX : Order.ATOMIC; } return [code, order]; }; -dartGenerator.forBlock['math_arithmetic'] = function(block) { +dartGenerator.forBlock['math_arithmetic'] = function(block, generator) { // Basic arithmetic operators, and power. const OPERATORS = { 'ADD': [' + ', Order.ADDITIVE], @@ -47,12 +47,12 @@ dartGenerator.forBlock['math_arithmetic'] = function(block) { const tuple = OPERATORS[block.getFieldValue('OP')]; const operator = tuple[0]; const order = tuple[1]; - const argument0 = dartGenerator.valueToCode(block, 'A', order) || '0'; - const argument1 = dartGenerator.valueToCode(block, 'B', order) || '0'; + const argument0 = generator.valueToCode(block, 'A', order) || '0'; + const argument1 = generator.valueToCode(block, 'B', order) || '0'; let code; - // Power in dartGenerator requires a special case since it has no operator. + // Power in generator requires a special case since it has no operator. if (!operator) { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; code = 'Math.pow(' + argument0 + ', ' + argument1 + ')'; return [code, Order.UNARY_POSTFIX]; @@ -61,29 +61,29 @@ dartGenerator.forBlock['math_arithmetic'] = function(block) { return [code, order]; }; -dartGenerator.forBlock['math_single'] = function(block) { +dartGenerator.forBlock['math_single'] = function(block, generator) { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; let arg; if (operator === 'NEG') { // Negation is a special case given its different operator precedence. - arg = dartGenerator.valueToCode(block, 'NUM', Order.UNARY_PREFIX) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.UNARY_PREFIX) || '0'; if (arg[0] === '-') { - // --3 is not legal in dartGenerator. + // --3 is not legal in generator. arg = ' ' + arg; } code = '-' + arg; return [code, Order.UNARY_PREFIX]; } - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; if (operator === 'ABS' || operator.substring(0, 5) === 'ROUND') { - arg = dartGenerator.valueToCode(block, 'NUM', Order.UNARY_POSTFIX) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.UNARY_POSTFIX) || '0'; } else if (operator === 'SIN' || operator === 'COS' || operator === 'TAN') { - arg = dartGenerator.valueToCode(block, 'NUM', Order.MULTIPLICATIVE) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.MULTIPLICATIVE) || '0'; } else { - arg = dartGenerator.valueToCode(block, 'NUM', Order.NONE) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; } // First, handle cases which generate values that don't need parentheses // wrapping the code. @@ -146,7 +146,7 @@ dartGenerator.forBlock['math_single'] = function(block) { return [code, Order.MULTIPLICATIVE]; }; -dartGenerator.forBlock['math_constant'] = function(block) { +dartGenerator.forBlock['math_constant'] = function(block, generator) { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. const CONSTANTS = { 'PI': ['Math.pi', Order.UNARY_POSTFIX], @@ -158,13 +158,13 @@ dartGenerator.forBlock['math_constant'] = function(block) { }; const constant = block.getFieldValue('CONSTANT'); if (constant !== 'INFINITY') { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; } return CONSTANTS[constant]; }; -dartGenerator.forBlock['math_number_property'] = function(block) { +dartGenerator.forBlock['math_number_property'] = function(block, generator) { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. const PROPERTIES = { @@ -178,15 +178,15 @@ dartGenerator.forBlock['math_number_property'] = function(block) { }; const dropdownProperty = block.getFieldValue('PROPERTY'); const [suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty]; - const numberToCheck = dartGenerator.valueToCode(block, 'NUMBER_TO_CHECK', + const numberToCheck = generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || '0'; let code; if (dropdownProperty === 'PRIME') { // Prime is a special case as it is not a one-liner test. - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; - const functionName = dartGenerator.provideFunction_('math_isPrime', ` -bool ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(n) { + const functionName = generator.provideFunction_('math_isPrime', ` +bool ${generator.FUNCTION_NAME_PLACEHOLDER_}(n) { // https://en.wikipedia.org/wiki/Primality_test#Naive_methods if (n == 2 || n == 3) { return true; @@ -207,7 +207,7 @@ bool ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(n) { `); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = dartGenerator.valueToCode(block, 'DIVISOR', + const divisor = generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; if (divisor === '0') { return ['false', Order.ATOMIC]; @@ -219,12 +219,12 @@ bool ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(n) { return [code, outputOrder]; }; -dartGenerator.forBlock['math_change'] = function(block) { +dartGenerator.forBlock['math_change'] = function(block, generator) { // Add to a variable in place. const argument0 = - dartGenerator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; + generator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; const varName = - dartGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' = (' + varName + ' is num ? ' + varName + ' : 0) + ' + argument0 + ';\n'; @@ -235,15 +235,15 @@ dartGenerator.forBlock['math_round'] = dartGenerator.forBlock['math_single']; // Trigonometry functions have a single operand. dartGenerator.forBlock['math_trig'] = dartGenerator.forBlock['math_single']; -dartGenerator.forBlock['math_on_list'] = function(block) { +dartGenerator.forBlock['math_on_list'] = function(block, generator) { // Math functions for lists. const func = block.getFieldValue('OP'); - const list = dartGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; let code; switch (func) { case 'SUM': { - const functionName = dartGenerator.provideFunction_('math_sum', ` -num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { + const functionName = generator.provideFunction_('math_sum', ` +num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { num sumVal = 0; myList.forEach((num entry) {sumVal += entry;}); return sumVal; @@ -253,10 +253,10 @@ num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { break; } case 'MIN': { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; - const functionName = dartGenerator.provideFunction_('math_min', ` -num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { + const functionName = generator.provideFunction_('math_min', ` +num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { if (myList.isEmpty) return null; num minVal = myList[0]; myList.forEach((num entry) {minVal = Math.min(minVal, entry);}); @@ -267,10 +267,10 @@ num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { break; } case 'MAX': { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; - const functionName = dartGenerator.provideFunction_('math_max', ` -num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { + const functionName = generator.provideFunction_('math_max', ` +num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { if (myList.isEmpty) return null; num maxVal = myList[0]; myList.forEach((num entry) {maxVal = Math.max(maxVal, entry);}); @@ -283,8 +283,8 @@ num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { case 'AVERAGE': { // This operation exclude null and values that are not int or float: // math_mean([null,null,"aString",1,9]) -> 5.0 - const functionName = dartGenerator.provideFunction_('math_mean', ` -num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { + const functionName = generator.provideFunction_('math_mean', ` +num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { // First filter list for numbers only. List localList = new List.from(myList); localList.removeWhere((a) => a is! num); @@ -298,8 +298,8 @@ num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { break; } case 'MEDIAN': { - const functionName = dartGenerator.provideFunction_('math_median', ` -num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { + const functionName = generator.provideFunction_('math_median', ` +num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { // First filter list for numbers only, then sort, then return middle value // or the average of two middle values if list has an even number of elements. List localList = new List.from(myList); @@ -318,13 +318,13 @@ num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { break; } case 'MODE': { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1] - const functionName = dartGenerator.provideFunction_('math_modes', ` -List ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List values) { + const functionName = generator.provideFunction_('math_modes', ` +List ${generator.FUNCTION_NAME_PLACEHOLDER_}(List values) { List modes = []; List counts = []; int maxCount = 0; @@ -357,11 +357,11 @@ List ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List values) { break; } case 'STD_DEV': { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; const functionName = - dartGenerator.provideFunction_('math_standard_deviation', ` -num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { + generator.provideFunction_('math_standard_deviation', ` +num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { // First filter list for numbers only. List numbers = new List.from(myList); numbers.removeWhere((a) => a is! num); @@ -379,10 +379,10 @@ num ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { break; } case 'RANDOM': { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; - const functionName = dartGenerator.provideFunction_('math_random_item', ` -dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { + const functionName = generator.provideFunction_('math_random_item', ` +dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { int x = new Math.Random().nextInt(myList.length); return myList[x]; } @@ -396,38 +396,38 @@ dynamic ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['math_modulo'] = function(block) { +dartGenerator.forBlock['math_modulo'] = function(block, generator) { // Remainder computation. const argument0 = - dartGenerator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || '0'; const argument1 = - dartGenerator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MULTIPLICATIVE]; }; -dartGenerator.forBlock['math_constrain'] = function(block) { +dartGenerator.forBlock['math_constrain'] = function(block, generator) { // Constrain a number between two limits. - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; const argument0 = - dartGenerator.valueToCode(block, 'VALUE', Order.NONE) || '0'; - const argument1 = dartGenerator.valueToCode(block, 'LOW', Order.NONE) || '0'; + generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'LOW', Order.NONE) || '0'; const argument2 = - dartGenerator.valueToCode(block, 'HIGH', Order.NONE) || 'double.infinity'; + generator.valueToCode(block, 'HIGH', Order.NONE) || 'double.infinity'; const code = 'Math.min(Math.max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['math_random_int'] = function(block) { +dartGenerator.forBlock['math_random_int'] = function(block, generator) { // Random integer between [X] and [Y]. - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; - const argument0 = dartGenerator.valueToCode(block, 'FROM', Order.NONE) || '0'; - const argument1 = dartGenerator.valueToCode(block, 'TO', Order.NONE) || '0'; - const functionName = dartGenerator.provideFunction_('math_random_int', ` -int ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(num a, num b) { + const argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; + const functionName = generator.provideFunction_('math_random_int', ` +int ${generator.FUNCTION_NAME_PLACEHOLDER_}(num a, num b) { if (a > b) { // Swap a and b to ensure a is smaller. num c = a; @@ -441,19 +441,19 @@ int ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(num a, num b) { return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['math_random_float'] = function(block) { +dartGenerator.forBlock['math_random_float'] = function(block, generator) { // Random fraction between 0 and 1. - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; return ['new Math.Random().nextDouble()', Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['math_atan2'] = function(block) { +dartGenerator.forBlock['math_atan2'] = function(block, generator) { // Arctangent of point (X, Y) in degrees from -180 to 180. - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; - const argument0 = dartGenerator.valueToCode(block, 'X', Order.NONE) || '0'; - const argument1 = dartGenerator.valueToCode(block, 'Y', Order.NONE) || '0'; + const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; return [ 'Math.atan2(' + argument1 + ', ' + argument0 + ') / Math.pi * 180', Order.MULTIPLICATIVE diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js index d86cd2f7c..18712f142 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.js @@ -15,49 +15,49 @@ import {NameType} from '../../core/names.js'; import {dartGenerator, Order} from '../dart.js'; -dartGenerator.forBlock['procedures_defreturn'] = function(block) { +dartGenerator.forBlock['procedures_defreturn'] = function(block, generator) { // Define a procedure with a return value. const funcName = - dartGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('NAME'), NameType.PROCEDURE); let xfix1 = ''; - if (dartGenerator.STATEMENT_PREFIX) { - xfix1 += dartGenerator.injectId(dartGenerator.STATEMENT_PREFIX, block); + if (generator.STATEMENT_PREFIX) { + xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block); } - if (dartGenerator.STATEMENT_SUFFIX) { - xfix1 += dartGenerator.injectId(dartGenerator.STATEMENT_SUFFIX, block); + if (generator.STATEMENT_SUFFIX) { + xfix1 += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (xfix1) { - xfix1 = dartGenerator.prefixLines(xfix1, dartGenerator.INDENT); + xfix1 = generator.prefixLines(xfix1, generator.INDENT); } let loopTrap = ''; - if (dartGenerator.INFINITE_LOOP_TRAP) { - loopTrap = dartGenerator.prefixLines( - dartGenerator.injectId(dartGenerator.INFINITE_LOOP_TRAP, block), - dartGenerator.INDENT); + if (generator.INFINITE_LOOP_TRAP) { + loopTrap = generator.prefixLines( + generator.injectId(generator.INFINITE_LOOP_TRAP, block), + generator.INDENT); } - const branch = dartGenerator.statementToCode(block, 'STACK'); + const branch = generator.statementToCode(block, 'STACK'); let returnValue = - dartGenerator.valueToCode(block, 'RETURN', Order.NONE) || ''; + generator.valueToCode(block, 'RETURN', Order.NONE) || ''; let xfix2 = ''; if (branch && returnValue) { // After executing the function body, revisit this block for the return. xfix2 = xfix1; } if (returnValue) { - returnValue = dartGenerator.INDENT + 'return ' + returnValue + ';\n'; + returnValue = generator.INDENT + 'return ' + returnValue + ';\n'; } const returnType = returnValue ? 'dynamic' : 'void'; const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = dartGenerator.nameDB_.getName(variables[i], NameType.VARIABLE); + args[i] = generator.nameDB_.getName(variables[i], NameType.VARIABLE); } let code = returnType + ' ' + funcName + '(' + args.join(', ') + ') {\n' + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; - code = dartGenerator.scrub_(block, code); + code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - dartGenerator.definitions_['%' + funcName] = code; + generator.definitions_['%' + funcName] = code; return null; }; @@ -65,46 +65,46 @@ dartGenerator.forBlock['procedures_defreturn'] = function(block) { // a procedure with a return value. dartGenerator.forBlock['procedures_defnoreturn'] = dartGenerator.forBlock['procedures_defreturn']; -dartGenerator.forBlock['procedures_callreturn'] = function(block) { +dartGenerator.forBlock['procedures_callreturn'] = function(block, generator) { // Call a procedure with a return value. const funcName = - dartGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('NAME'),NameType.PROCEDURE); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = dartGenerator.valueToCode(block, 'ARG' + i, Order.NONE) || 'null'; + args[i] = generator.valueToCode(block, 'ARG' + i, Order.NONE) || 'null'; } let code = funcName + '(' + args.join(', ') + ')'; return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['procedures_callnoreturn'] = function(block) { +dartGenerator.forBlock['procedures_callnoreturn'] = function(block, generator) { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = dartGenerator.forBlock['procedures_callreturn'](block); + const tuple = generator.forBlock['procedures_callreturn'](block, generator); return tuple[0] + ';\n'; }; -dartGenerator.forBlock['procedures_ifreturn'] = function(block) { +dartGenerator.forBlock['procedures_ifreturn'] = function(block, generator) { // Conditionally return value from a procedure. const condition = - dartGenerator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; let code = 'if (' + condition + ') {\n'; - if (dartGenerator.STATEMENT_SUFFIX) { + if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. - code += dartGenerator.prefixLines( - dartGenerator.injectId( - dartGenerator.STATEMENT_SUFFIX, block), dartGenerator.INDENT); + code += generator.prefixLines( + generator.injectId( + generator.STATEMENT_SUFFIX, block), generator.INDENT); } if (block.hasReturnValue_) { const value = - dartGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; - code += dartGenerator.INDENT + 'return ' + value + ';\n'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; + code += generator.INDENT + 'return ' + value + ';\n'; } else { - code += dartGenerator.INDENT + 'return;\n'; + code += generator.INDENT + 'return;\n'; } code += '}\n'; return code; diff --git a/generators/dart/text.js b/generators/dart/text.js index de6f011d1..472c161df 100644 --- a/generators/dart/text.js +++ b/generators/dart/text.js @@ -17,28 +17,28 @@ import {dartGenerator, Order} from '../dart.js'; dartGenerator.addReservedWords('Html,Math'); -dartGenerator.forBlock['text'] = function(block) { +dartGenerator.forBlock['text'] = function(block, generator) { // Text value. - const code = dartGenerator.quote_(block.getFieldValue('TEXT')); + const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; }; -dartGenerator.forBlock['text_multiline'] = function(block) { +dartGenerator.forBlock['text_multiline'] = function(block, generator) { // Text value. - const code = dartGenerator.multiline_quote_(block.getFieldValue('TEXT')); + const code = generator.multiline_quote_(block.getFieldValue('TEXT')); const order = code.indexOf('+') !== -1 ? Order.ADDITIVE : Order.ATOMIC; return [code, order]; }; -dartGenerator.forBlock['text_join'] = function(block) { +dartGenerator.forBlock['text_join'] = function(block, generator) { // Create a string made up of any number of elements of any type. switch (block.itemCount_) { case 0: return ["''", Order.ATOMIC]; case 1: { const element = - dartGenerator.valueToCode(block, 'ADD0', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'ADD0', Order.UNARY_POSTFIX) || "''"; const code = element + '.toString()'; return [code, Order.UNARY_POSTFIX]; } @@ -46,7 +46,7 @@ dartGenerator.forBlock['text_join'] = function(block) { const elements = new Array(block.itemCount_); for (let i = 0; i < block.itemCount_; i++) { elements[i] = - dartGenerator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; + generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } const code = '[' + elements.join(',') + '].join()'; return [code, Order.UNARY_POSTFIX]; @@ -54,37 +54,37 @@ dartGenerator.forBlock['text_join'] = function(block) { } }; -dartGenerator.forBlock['text_append'] = function(block) { +dartGenerator.forBlock['text_append'] = function(block, generator) { // Append to a variable in place. const varName = - dartGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); - const value = dartGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const value = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return varName + ' = [' + varName + ', ' + value + '].join();\n'; }; -dartGenerator.forBlock['text_length'] = function(block) { +dartGenerator.forBlock['text_length'] = function(block, generator) { // String or array length. const text = - dartGenerator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; return [text + '.length', Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['text_isEmpty'] = function(block) { +dartGenerator.forBlock['text_isEmpty'] = function(block, generator) { // Is the string null or array empty? const text = - dartGenerator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; return [text + '.isEmpty', Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['text_indexOf'] = function(block) { +dartGenerator.forBlock['text_indexOf'] = function(block, generator) { // Search the text for a substring. const operator = block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; const substring = - dartGenerator.valueToCode(block, 'FIND', Order.NONE) || "''"; + generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const text = - dartGenerator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; const code = text + '.' + operator + '(' + substring + ')'; if (block.workspace.options.oneBasedIndex) { return [code + ' + 1', Order.ADDITIVE]; @@ -92,14 +92,14 @@ dartGenerator.forBlock['text_indexOf'] = function(block) { return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['text_charAt'] = function(block) { +dartGenerator.forBlock['text_charAt'] = function(block, generator) { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. const where = block.getFieldValue('WHERE') || 'FROM_START'; const textOrder = (where === 'FIRST' || where === 'FROM_START') ? Order.UNARY_POSTFIX : Order.NONE; - const text = dartGenerator.valueToCode(block, 'VALUE', textOrder) || "''"; + const text = generator.valueToCode(block, 'VALUE', textOrder) || "''"; let at; switch (where) { case 'FIRST': { @@ -107,7 +107,7 @@ dartGenerator.forBlock['text_charAt'] = function(block) { return [code, Order.UNARY_POSTFIX]; } case 'FROM_START': { - at = dartGenerator.getAdjusted(block, 'AT'); + at = generator.getAdjusted(block, 'AT'); const code = text + '[' + at + ']'; return [code, Order.UNARY_POSTFIX]; } @@ -115,9 +115,9 @@ dartGenerator.forBlock['text_charAt'] = function(block) { at = 1; // Fall through. case 'FROM_END': { - at = dartGenerator.getAdjusted(block, 'AT', 1); - const functionName = dartGenerator.provideFunction_('text_get_from_end', ` -String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String text, num x) { + at = generator.getAdjusted(block, 'AT', 1); + const functionName = generator.provideFunction_('text_get_from_end', ` +String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String text, num x) { return text[text.length - x]; } `); @@ -125,11 +125,11 @@ String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String text, num x) { return [code, Order.UNARY_POSTFIX]; } case 'RANDOM': { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; const functionName = - dartGenerator.provideFunction_('text_random_letter', ` -String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String text) { + generator.provideFunction_('text_random_letter', ` +String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String text) { int x = new Math.Random().nextInt(text.length); return text[x]; } @@ -141,14 +141,14 @@ String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String text) { throw Error('Unhandled option (text_charAt).'); }; -dartGenerator.forBlock['text_getSubstring'] = function(block) { +dartGenerator.forBlock['text_getSubstring'] = function(block, generator) { // Get substring. const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); const requiresLengthCall = (where1 !== 'FROM_END' && where2 === 'FROM_START'); const textOrder = requiresLengthCall ? Order.UNARY_POSTFIX : Order.NONE; - const text = dartGenerator.valueToCode(block, 'STRING', textOrder) || "''"; + const text = generator.valueToCode(block, 'STRING', textOrder) || "''"; let code; if (where1 === 'FIRST' && where2 === 'LAST') { code = text; @@ -159,10 +159,10 @@ dartGenerator.forBlock['text_getSubstring'] = function(block) { let at1; switch (where1) { case 'FROM_START': - at1 = dartGenerator.getAdjusted(block, 'AT1'); + at1 = generator.getAdjusted(block, 'AT1'); break; case 'FROM_END': - at1 = dartGenerator.getAdjusted(block, 'AT1', 1, false, Order.ADDITIVE); + at1 = generator.getAdjusted(block, 'AT1', 1, false, Order.ADDITIVE); at1 = text + '.length - ' + at1; break; case 'FIRST': @@ -174,10 +174,10 @@ dartGenerator.forBlock['text_getSubstring'] = function(block) { let at2; switch (where2) { case 'FROM_START': - at2 = dartGenerator.getAdjusted(block, 'AT2', 1); + at2 = generator.getAdjusted(block, 'AT2', 1); break; case 'FROM_END': - at2 = dartGenerator.getAdjusted(block, 'AT2', 0, false, Order.ADDITIVE); + at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.ADDITIVE); at2 = text + '.length - ' + at2; break; case 'LAST': @@ -192,11 +192,11 @@ dartGenerator.forBlock['text_getSubstring'] = function(block) { code = text + '.substring(' + at1 + ', ' + at2 + ')'; } } else { - const at1 = dartGenerator.getAdjusted(block, 'AT1'); - const at2 = dartGenerator.getAdjusted(block, 'AT2'); + const at1 = generator.getAdjusted(block, 'AT1'); + const at2 = generator.getAdjusted(block, 'AT2'); const functionName = - dartGenerator.provideFunction_('text_get_substring', ` -String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String text, String where1, num at1, String where2, num at2) { + generator.provideFunction_('text_get_substring', ` +String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String text, String where1, num at1, String where2, num at2) { int getAt(String where, num at) { if (where == 'FROM_END') { at = text.length - 1 - at; @@ -220,7 +220,7 @@ String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String text, String where1, n return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['text_changeCase'] = function(block) { +dartGenerator.forBlock['text_changeCase'] = function(block, generator) { // Change capitalization. const OPERATORS = { 'UPPERCASE': '.toUpperCase()', @@ -229,15 +229,15 @@ dartGenerator.forBlock['text_changeCase'] = function(block) { }; const operator = OPERATORS[block.getFieldValue('CASE')]; const textOrder = operator ? Order.UNARY_POSTFIX : Order.NONE; - const text = dartGenerator.valueToCode(block, 'TEXT', textOrder) || "''"; + const text = generator.valueToCode(block, 'TEXT', textOrder) || "''"; let code; if (operator) { - // Upper and lower case are functions built into dartGenerator. + // Upper and lower case are functions built into generator. code = text + operator; } else { - // Title case is not a native dartGenerator function. Define one. - const functionName = dartGenerator.provideFunction_('text_toTitleCase', ` -String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String str) { + // Title case is not a native generator function. Define one. + const functionName = generator.provideFunction_('text_toTitleCase', ` +String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String str) { RegExp exp = new RegExp(r'\\b'); List list = str.split(exp); final title = new StringBuffer(); @@ -257,7 +257,7 @@ String ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String str) { return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['text_trim'] = function(block) { +dartGenerator.forBlock['text_trim'] = function(block, generator) { // Trim spaces. const OPERATORS = { 'LEFT': '.replaceFirst(new RegExp(r\'^\\s+\'), \'\')', @@ -266,32 +266,32 @@ dartGenerator.forBlock['text_trim'] = function(block) { }; const operator = OPERATORS[block.getFieldValue('MODE')]; const text = - dartGenerator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; return [text + operator, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['text_print'] = function(block) { +dartGenerator.forBlock['text_print'] = function(block, generator) { // Print statement. - const msg = dartGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'print(' + msg + ');\n'; }; -dartGenerator.forBlock['text_prompt_ext'] = function(block) { +dartGenerator.forBlock['text_prompt_ext'] = function(block, generator) { // Prompt function. - dartGenerator.definitions_['import_dart_html'] = + generator.definitions_['import_dart_html'] = 'import \'dart:html\' as Html;'; let msg; if (block.getField('TEXT')) { // Internal message. - msg = dartGenerator.quote_(block.getFieldValue('TEXT')); + msg = generator.quote_(block.getFieldValue('TEXT')); } else { // External message. - msg = dartGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; } let code = 'Html.window.prompt(' + msg + ', \'\')'; const toNumber = block.getFieldValue('TYPE') === 'NUMBER'; if (toNumber) { - dartGenerator.definitions_['import_dart_math'] = + generator.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; code = 'Math.parseDouble(' + code + ')'; } @@ -301,12 +301,12 @@ dartGenerator.forBlock['text_prompt_ext'] = function(block) { dartGenerator.forBlock['text_prompt'] = dartGenerator.forBlock['text_prompt_ext']; -dartGenerator.forBlock['text_count'] = function(block) { - const text = dartGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; - const sub = dartGenerator.valueToCode(block, 'SUB', Order.NONE) || "''"; - // Substring count is not a native dartGenerator function. Define one. - const functionName = dartGenerator.provideFunction_('text_count', ` -int ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String haystack, String needle) { +dartGenerator.forBlock['text_count'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; + // Substring count is not a native generator function. Define one. + const functionName = generator.provideFunction_('text_count', ` +int ${generator.FUNCTION_NAME_PLACEHOLDER_}(String haystack, String needle) { if (needle.length == 0) { return haystack.length + 1; } @@ -326,21 +326,21 @@ int ${dartGenerator.FUNCTION_NAME_PLACEHOLDER_}(String haystack, String needle) return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['text_replace'] = function(block) { +dartGenerator.forBlock['text_replace'] = function(block, generator) { const text = - dartGenerator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; - const from = dartGenerator.valueToCode(block, 'FROM', Order.NONE) || "''"; - const to = dartGenerator.valueToCode(block, 'TO', Order.NONE) || "''"; + generator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; + const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; + const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; const code = text + '.replaceAll(' + from + ', ' + to + ')'; return [code, Order.UNARY_POSTFIX]; }; -dartGenerator.forBlock['text_reverse'] = function(block) { - // There isn't a sensible way to do this in dartGenerator. See: +dartGenerator.forBlock['text_reverse'] = function(block, generator) { + // There isn't a sensible way to do this in generator. See: // http://stackoverflow.com/a/21613700/3529104 // Implementing something is possibly better than not implementing anything? const text = - dartGenerator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; const code = 'new String.fromCharCodes(' + text + '.runes.toList().reversed)'; return [code, Order.UNARY_PREFIX]; }; diff --git a/generators/dart/variables.js b/generators/dart/variables.js index 930f6d342..61a9b97c4 100644 --- a/generators/dart/variables.js +++ b/generators/dart/variables.js @@ -15,20 +15,20 @@ import {NameType} from '../../core/names.js'; import {dartGenerator, Order} from '../dart.js'; -dartGenerator.forBlock['variables_get'] = function(block) { +dartGenerator.forBlock['variables_get'] = function(block, generator) { // Variable getter. const code = - dartGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return [code, Order.ATOMIC]; }; -dartGenerator.forBlock['variables_set'] = function(block) { +dartGenerator.forBlock['variables_set'] = function(block, generator) { // Variable setter. const argument0 = - dartGenerator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; + generator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; const varName = - dartGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' = ' + argument0 + ';\n'; }; diff --git a/generators/dart/variables_dynamic.js b/generators/dart/variables_dynamic.js index 6b33f4b59..f19320ded 100644 --- a/generators/dart/variables_dynamic.js +++ b/generators/dart/variables_dynamic.js @@ -15,7 +15,7 @@ import {dartGenerator} from '../dart.js'; import './variables.js'; -// dartGenerator is dynamically typed. +// generator is dynamically typed. dartGenerator.forBlock['variables_get_dynamic'] = dartGenerator.forBlock['variables_get']; dartGenerator.forBlock['variables_set_dynamic'] = diff --git a/generators/javascript/colour.js b/generators/javascript/colour.js index 9ffd901d9..3e0ab2882 100644 --- a/generators/javascript/colour.js +++ b/generators/javascript/colour.js @@ -14,16 +14,16 @@ goog.declareModuleId('Blockly.JavaScript.colour'); import {Order, javascriptGenerator} from '../javascript.js'; -javascriptGenerator.forBlock['colour_picker'] = function(block) { +javascriptGenerator.forBlock['colour_picker'] = function(block, generator) { // Colour picker. - const code = javascriptGenerator.quote_(block.getFieldValue('COLOUR')); + const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; }; -javascriptGenerator.forBlock['colour_random'] = function(block) { +javascriptGenerator.forBlock['colour_random'] = function(block, generator) { // Generate a random colour. - const functionName = javascriptGenerator.provideFunction_('colourRandom', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}() { + const functionName = generator.provideFunction_('colourRandom', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}() { var num = Math.floor(Math.random() * Math.pow(2, 24)); return '#' + ('00000' + num.toString(16)).substr(-6); } @@ -32,15 +32,15 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}() { return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['colour_rgb'] = function(block) { +javascriptGenerator.forBlock['colour_rgb'] = function(block, generator) { // Compose a colour from RGB components expressed as percentages. - const red = javascriptGenerator.valueToCode(block, 'RED', Order.NONE) || 0; + const red = generator.valueToCode(block, 'RED', Order.NONE) || 0; const green = - javascriptGenerator.valueToCode(block, 'GREEN', Order.NONE) || 0; + generator.valueToCode(block, 'GREEN', Order.NONE) || 0; const blue = - javascriptGenerator.valueToCode(block, 'BLUE', Order.NONE) || 0; - const functionName = javascriptGenerator.provideFunction_('colourRgb', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b) { + generator.valueToCode(block, 'BLUE', Order.NONE) || 0; + const functionName = generator.provideFunction_('colourRgb', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b) { r = Math.max(Math.min(Number(r), 100), 0) * 2.55; g = Math.max(Math.min(Number(g), 100), 0) * 2.55; b = Math.max(Math.min(Number(b), 100), 0) * 2.55; @@ -54,16 +54,16 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b) { return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['colour_blend'] = function(block) { +javascriptGenerator.forBlock['colour_blend'] = function(block, generator) { // Blend two colours together. - const c1 = javascriptGenerator.valueToCode(block, 'COLOUR1', Order.NONE) || + const c1 = generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; - const c2 = javascriptGenerator.valueToCode(block, 'COLOUR2', Order.NONE) || + const c2 = generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; const ratio = - javascriptGenerator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; - const functionName = javascriptGenerator.provideFunction_('colourBlend', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(c1, c2, ratio) { + generator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; + const functionName = generator.provideFunction_('colourBlend', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(c1, c2, ratio) { ratio = Math.max(Math.min(Number(ratio), 1), 0); var r1 = parseInt(c1.substring(1, 3), 16); var g1 = parseInt(c1.substring(3, 5), 16); diff --git a/generators/javascript/lists.js b/generators/javascript/lists.js index f2a3f531e..ff9041ea2 100644 --- a/generators/javascript/lists.js +++ b/generators/javascript/lists.js @@ -16,27 +16,27 @@ import {NameType} from '../../core/names.js'; import {Order, javascriptGenerator} from '../javascript.js'; -javascriptGenerator.forBlock['lists_create_empty'] = function(block) { +javascriptGenerator.forBlock['lists_create_empty'] = function(block, generator) { // Create an empty list. return ['[]', Order.ATOMIC]; }; -javascriptGenerator.forBlock['lists_create_with'] = function(block) { +javascriptGenerator.forBlock['lists_create_with'] = function(block, generator) { // Create a list with any number of elements of any type. const elements = new Array(block.itemCount_); for (let i = 0; i < block.itemCount_; i++) { elements[i] = - javascriptGenerator.valueToCode(block, 'ADD' + i, Order.NONE) || + generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; } const code = '[' + elements.join(', ') + ']'; return [code, Order.ATOMIC]; }; -javascriptGenerator.forBlock['lists_repeat'] = function(block) { +javascriptGenerator.forBlock['lists_repeat'] = function(block, generator) { // Create a list with one element repeated. - const functionName = javascriptGenerator.provideFunction_('listsRepeat', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(value, n) { + const functionName = generator.provideFunction_('listsRepeat', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(value, n) { var array = []; for (var i = 0; i < n; i++) { array[i] = value; @@ -45,35 +45,35 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(value, n) { } `); const element = - javascriptGenerator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; + generator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; const repeatCount = - javascriptGenerator.valueToCode(block, 'NUM', Order.NONE) || '0'; + generator.valueToCode(block, 'NUM', Order.NONE) || '0'; const code = functionName + '(' + element + ', ' + repeatCount + ')'; return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['lists_length'] = function(block) { +javascriptGenerator.forBlock['lists_length'] = function(block, generator) { // String or array length. const list = - javascriptGenerator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; return [list + '.length', Order.MEMBER]; }; -javascriptGenerator.forBlock['lists_isEmpty'] = function(block) { +javascriptGenerator.forBlock['lists_isEmpty'] = function(block, generator) { // Is the string null or array empty? const list = - javascriptGenerator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; return ['!' + list + '.length', Order.LOGICAL_NOT]; }; -javascriptGenerator.forBlock['lists_indexOf'] = function(block) { +javascriptGenerator.forBlock['lists_indexOf'] = function(block, generator) { // Find an item in the list. const operator = block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; const item = - javascriptGenerator.valueToCode(block, 'FIND', Order.NONE) || "''"; + generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const list = - javascriptGenerator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; const code = list + '.' + operator + '(' + item + ')'; if (block.workspace.options.oneBasedIndex) { return [code + ' + 1', Order.ADDITION]; @@ -81,7 +81,7 @@ javascriptGenerator.forBlock['lists_indexOf'] = function(block) { return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['lists_getIndex'] = function(block) { +javascriptGenerator.forBlock['lists_getIndex'] = function(block, generator) { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; @@ -89,7 +89,7 @@ javascriptGenerator.forBlock['lists_getIndex'] = function(block) { const listOrder = (where === 'RANDOM') ? Order.NONE : Order.MEMBER; const list = - javascriptGenerator.valueToCode(block, 'VALUE', listOrder) || '[]'; + generator.valueToCode(block, 'VALUE', listOrder) || '[]'; switch (where) { case ('FIRST'): @@ -115,7 +115,7 @@ javascriptGenerator.forBlock['lists_getIndex'] = function(block) { } break; case ('FROM_START'): { - const at = javascriptGenerator.getAdjusted(block, 'AT'); + const at = generator.getAdjusted(block, 'AT'); if (mode === 'GET') { const code = list + '[' + at + ']'; return [code, Order.MEMBER]; @@ -128,7 +128,7 @@ javascriptGenerator.forBlock['lists_getIndex'] = function(block) { break; } case ('FROM_END'): { - const at = javascriptGenerator.getAdjusted(block, 'AT', 1, true); + const at = generator.getAdjusted(block, 'AT', 1, true); if (mode === 'GET') { const code = list + '.slice(' + at + ')[0]'; return [code, Order.FUNCTION_CALL]; @@ -142,8 +142,8 @@ javascriptGenerator.forBlock['lists_getIndex'] = function(block) { } case ('RANDOM'): { const functionName = - javascriptGenerator.provideFunction_('listsGetRandomItem', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(list, remove) { + generator.provideFunction_('listsGetRandomItem', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list, remove) { var x = Math.floor(Math.random() * list.length); if (remove) { return list.splice(x, 1)[0]; @@ -164,15 +164,15 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(list, remove) { throw Error('Unhandled combination (lists_getIndex).'); }; -javascriptGenerator.forBlock['lists_setIndex'] = function(block) { +javascriptGenerator.forBlock['lists_setIndex'] = function(block, generator) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. let list = - javascriptGenerator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; + generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; const value = - javascriptGenerator.valueToCode(block, 'TO', Order.ASSIGNMENT) || + generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. @@ -181,7 +181,7 @@ javascriptGenerator.forBlock['lists_setIndex'] = function(block) { return ''; } const listVar = - javascriptGenerator.nameDB_.getDistinctName( + generator.nameDB_.getDistinctName( 'tmpList', NameType.VARIABLE); const code = 'var ' + listVar + ' = ' + list + ';\n'; list = listVar; @@ -205,7 +205,7 @@ javascriptGenerator.forBlock['lists_setIndex'] = function(block) { } break; case ('FROM_START'): { - const at = javascriptGenerator.getAdjusted(block, 'AT'); + const at = generator.getAdjusted(block, 'AT'); if (mode === 'SET') { return list + '[' + at + '] = ' + value + ';\n'; } else if (mode === 'INSERT') { @@ -214,7 +214,7 @@ javascriptGenerator.forBlock['lists_setIndex'] = function(block) { break; } case ('FROM_END'): { - const at = javascriptGenerator.getAdjusted( + const at = generator.getAdjusted( block, 'AT', 1, false, Order.SUBTRACTION); let code = cacheList(); if (mode === 'SET') { @@ -230,7 +230,7 @@ javascriptGenerator.forBlock['lists_setIndex'] = function(block) { case ('RANDOM'): { let code = cacheList(); const xVar = - javascriptGenerator.nameDB_.getDistinctName( + generator.nameDB_.getDistinctName( 'tmpX', NameType.VARIABLE); code += 'var ' + xVar + ' = Math.floor(Math.random() * ' + list + '.length);\n'; @@ -266,10 +266,10 @@ const getSubstringIndex = function(listName, where, opt_at) { } }; -javascriptGenerator.forBlock['lists_getSublist'] = function(block) { +javascriptGenerator.forBlock['lists_getSublist'] = function(block, generator) { // Get sublist. const list = - javascriptGenerator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; + generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); let code; @@ -283,10 +283,10 @@ javascriptGenerator.forBlock['lists_getSublist'] = function(block) { let at1; switch (where1) { case 'FROM_START': - at1 = javascriptGenerator.getAdjusted(block, 'AT1'); + at1 = generator.getAdjusted(block, 'AT1'); break; case 'FROM_END': - at1 = javascriptGenerator.getAdjusted( + at1 = generator.getAdjusted( block, 'AT1', 1, false, Order.SUBTRACTION); at1 = list + '.length - ' + at1; break; @@ -299,10 +299,10 @@ javascriptGenerator.forBlock['lists_getSublist'] = function(block) { let at2; switch (where2) { case 'FROM_START': - at2 = javascriptGenerator.getAdjusted(block, 'AT2', 1); + at2 = generator.getAdjusted(block, 'AT2', 1); break; case 'FROM_END': - at2 = javascriptGenerator.getAdjusted( + at2 = generator.getAdjusted( block, 'AT2', 0, false, Order.SUBTRACTION); at2 = list + '.length - ' + at2; break; @@ -314,8 +314,8 @@ javascriptGenerator.forBlock['lists_getSublist'] = function(block) { } code = list + '.slice(' + at1 + ', ' + at2 + ')'; } else { - const at1 = javascriptGenerator.getAdjusted(block, 'AT1'); - const at2 = javascriptGenerator.getAdjusted(block, 'AT2'); + const at1 = generator.getAdjusted(block, 'AT1'); + const at2 = generator.getAdjusted(block, 'AT2'); const wherePascalCase = { 'FIRST': 'First', 'LAST': 'Last', @@ -328,9 +328,9 @@ javascriptGenerator.forBlock['lists_getSublist'] = function(block) { (where1 === 'FROM_END' || where1 === 'FROM_START') ? ', at1' : ''; const at2Param = (where2 === 'FROM_END' || where2 === 'FROM_START') ? ', at2' : ''; - const functionName = javascriptGenerator.provideFunction_( + const functionName = generator.provideFunction_( 'subsequence' + wherePascalCase[where1] + wherePascalCase[where2], ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(sequence${at1Param}${at2Param}) { +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(sequence${at1Param}${at2Param}) { var start = ${getSubstringIndex('sequence', where1, 'at1')}; var end = ${getSubstringIndex('sequence', where2, 'at2')} + 1; return sequence.slice(start, end); @@ -346,16 +346,16 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(sequence${at1Param}${ return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['lists_sort'] = function(block) { +javascriptGenerator.forBlock['lists_sort'] = function(block, generator) { // Block for sorting a list. const list = - javascriptGenerator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || '[]'; const direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1; const type = block.getFieldValue('TYPE'); const getCompareFunctionName = - javascriptGenerator.provideFunction_('listsGetSortCompare', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(type, direction) { + generator.provideFunction_('listsGetSortCompare', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(type, direction) { var compareFuncs = { 'NUMERIC': function(a, b) { return Number(a) - Number(b); }, @@ -375,11 +375,11 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(type, direction) { ]; }; -javascriptGenerator.forBlock['lists_split'] = function(block) { +javascriptGenerator.forBlock['lists_split'] = function(block, generator) { // Block for splitting text into a list, or joining a list into text. - let input = javascriptGenerator.valueToCode(block, 'INPUT', Order.MEMBER); + let input = generator.valueToCode(block, 'INPUT', Order.MEMBER); const delimiter = - javascriptGenerator.valueToCode(block, 'DELIM', Order.NONE) || "''"; + generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; const mode = block.getFieldValue('MODE'); let functionName; if (mode === 'SPLIT') { @@ -399,10 +399,10 @@ javascriptGenerator.forBlock['lists_split'] = function(block) { return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['lists_reverse'] = function(block) { +javascriptGenerator.forBlock['lists_reverse'] = function(block, generator) { // Block for reversing a list. const list = - javascriptGenerator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || '[]'; const code = list + '.slice().reverse()'; return [code, Order.FUNCTION_CALL]; diff --git a/generators/javascript/logic.js b/generators/javascript/logic.js index 7206b63a6..2070e1e04 100644 --- a/generators/javascript/logic.js +++ b/generators/javascript/logic.js @@ -14,25 +14,25 @@ goog.declareModuleId('Blockly.JavaScript.logic'); import {Order, javascriptGenerator} from '../javascript.js'; -javascriptGenerator.forBlock['controls_if'] = function(block) { +javascriptGenerator.forBlock['controls_if'] = function(block, generator) { // If/elseif/else condition. let n = 0; let code = ''; - if (javascriptGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - code += javascriptGenerator.injectId( - javascriptGenerator.STATEMENT_PREFIX, block); + code += generator.injectId( + generator.STATEMENT_PREFIX, block); } do { const conditionCode = - javascriptGenerator.valueToCode(block, 'IF' + n, Order.NONE) || + generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; - let branchCode = javascriptGenerator.statementToCode(block, 'DO' + n); - if (javascriptGenerator.STATEMENT_SUFFIX) { - branchCode = javascriptGenerator.prefixLines( - javascriptGenerator.injectId( - javascriptGenerator.STATEMENT_SUFFIX, block), - javascriptGenerator.INDENT) + + let branchCode = generator.statementToCode(block, 'DO' + n); + if (generator.STATEMENT_SUFFIX) { + branchCode = generator.prefixLines( + generator.injectId( + generator.STATEMENT_SUFFIX, block), + generator.INDENT) + branchCode; } code += (n > 0 ? ' else ' : '') + 'if (' + conditionCode + ') {\n' + @@ -40,13 +40,13 @@ javascriptGenerator.forBlock['controls_if'] = function(block) { n++; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE') || javascriptGenerator.STATEMENT_SUFFIX) { - let branchCode = javascriptGenerator.statementToCode(block, 'ELSE'); - if (javascriptGenerator.STATEMENT_SUFFIX) { - branchCode = javascriptGenerator.prefixLines( - javascriptGenerator.injectId( - javascriptGenerator.STATEMENT_SUFFIX, block), - javascriptGenerator.INDENT) + + if (block.getInput('ELSE') || generator.STATEMENT_SUFFIX) { + let branchCode = generator.statementToCode(block, 'ELSE'); + if (generator.STATEMENT_SUFFIX) { + branchCode = generator.prefixLines( + generator.injectId( + generator.STATEMENT_SUFFIX, block), + generator.INDENT) + branchCode; } code += ' else {\n' + branchCode + '}'; @@ -57,7 +57,7 @@ javascriptGenerator.forBlock['controls_if'] = function(block) { javascriptGenerator.forBlock['controls_ifelse'] = javascriptGenerator.forBlock['controls_if']; -javascriptGenerator.forBlock['logic_compare'] = function(block) { +javascriptGenerator.forBlock['logic_compare'] = function(block, generator) { // Comparison operator. const OPERATORS = {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; @@ -65,19 +65,19 @@ javascriptGenerator.forBlock['logic_compare'] = function(block) { const order = (operator === '==' || operator === '!=') ? Order.EQUALITY : Order.RELATIONAL; - const argument0 = javascriptGenerator.valueToCode(block, 'A', order) || '0'; - const argument1 = javascriptGenerator.valueToCode(block, 'B', order) || '0'; + const argument0 = generator.valueToCode(block, 'A', order) || '0'; + const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; -javascriptGenerator.forBlock['logic_operation'] = function(block) { +javascriptGenerator.forBlock['logic_operation'] = function(block, generator) { // Operations 'and', 'or'. const operator = (block.getFieldValue('OP') === 'AND') ? '&&' : '||'; const order = (operator === '&&') ? Order.LOGICAL_AND : Order.LOGICAL_OR; - let argument0 = javascriptGenerator.valueToCode(block, 'A', order); - let argument1 = javascriptGenerator.valueToCode(block, 'B', order); + let argument0 = generator.valueToCode(block, 'A', order); + let argument1 = generator.valueToCode(block, 'B', order); if (!argument0 && !argument1) { // If there are no arguments, then the return value is false. argument0 = 'false'; @@ -96,36 +96,36 @@ javascriptGenerator.forBlock['logic_operation'] = function(block) { return [code, order]; }; -javascriptGenerator.forBlock['logic_negate'] = function(block) { +javascriptGenerator.forBlock['logic_negate'] = function(block, generator) { // Negation. const order = Order.LOGICAL_NOT; const argument0 = - javascriptGenerator.valueToCode(block, 'BOOL', order) || 'true'; + generator.valueToCode(block, 'BOOL', order) || 'true'; const code = '!' + argument0; return [code, order]; }; -javascriptGenerator.forBlock['logic_boolean'] = function(block) { +javascriptGenerator.forBlock['logic_boolean'] = function(block, generator) { // Boolean values true and false. const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'true' : 'false'; return [code, Order.ATOMIC]; }; -javascriptGenerator.forBlock['logic_null'] = function(block) { +javascriptGenerator.forBlock['logic_null'] = function(block, generator) { // Null data type. return ['null', Order.ATOMIC]; }; -javascriptGenerator.forBlock['logic_ternary'] = function(block) { +javascriptGenerator.forBlock['logic_ternary'] = function(block, generator) { // Ternary operator. const value_if = - javascriptGenerator.valueToCode(block, 'IF', Order.CONDITIONAL) || + generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; const value_then = - javascriptGenerator.valueToCode(block, 'THEN', Order.CONDITIONAL) || + generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; const value_else = - javascriptGenerator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || + generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'null'; const code = value_if + ' ? ' + value_then + ' : ' + value_else; return [code, Order.CONDITIONAL]; diff --git a/generators/javascript/loops.js b/generators/javascript/loops.js index d11728a1d..cafbd3a50 100644 --- a/generators/javascript/loops.js +++ b/generators/javascript/loops.js @@ -16,7 +16,7 @@ import {NameType} from '../../core/names.js'; import {Order, javascriptGenerator} from '../javascript.js'; -javascriptGenerator.forBlock['controls_repeat_ext'] = function(block) { +javascriptGenerator.forBlock['controls_repeat_ext'] = function(block, generator) { // Repeat n times. let repeats; if (block.getField('TIMES')) { @@ -25,18 +25,18 @@ javascriptGenerator.forBlock['controls_repeat_ext'] = function(block) { } else { // External number. repeats = - javascriptGenerator.valueToCode(block, 'TIMES', Order.ASSIGNMENT) || + generator.valueToCode(block, 'TIMES', Order.ASSIGNMENT) || '0'; } - let branch = javascriptGenerator.statementToCode(block, 'DO'); - branch = javascriptGenerator.addLoopTrap(branch, block); + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); let code = ''; const loopVar = - javascriptGenerator.nameDB_.getDistinctName('count', NameType.VARIABLE); + generator.nameDB_.getDistinctName('count', NameType.VARIABLE); let endVar = repeats; if (!repeats.match(/^\w+$/) && !stringUtils.isNumber(repeats)) { endVar = - javascriptGenerator.nameDB_.getDistinctName( + generator.nameDB_.getDistinctName( 'repeat_end', NameType.VARIABLE); code += 'var ' + endVar + ' = ' + repeats + ';\n'; } @@ -48,35 +48,35 @@ javascriptGenerator.forBlock['controls_repeat_ext'] = function(block) { javascriptGenerator.forBlock['controls_repeat'] = javascriptGenerator.forBlock['controls_repeat_ext']; -javascriptGenerator.forBlock['controls_whileUntil'] = function(block) { +javascriptGenerator.forBlock['controls_whileUntil'] = function(block, generator) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; let argument0 = - javascriptGenerator.valueToCode( + generator.valueToCode( block, 'BOOL', until ? Order.LOGICAL_NOT : Order.NONE) || 'false'; - let branch = javascriptGenerator.statementToCode(block, 'DO'); - branch = javascriptGenerator.addLoopTrap(branch, block); + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); if (until) { argument0 = '!' + argument0; } return 'while (' + argument0 + ') {\n' + branch + '}\n'; }; -javascriptGenerator.forBlock['controls_for'] = function(block) { +javascriptGenerator.forBlock['controls_for'] = function(block, generator) { // For loop. const variable0 = - javascriptGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); const argument0 = - javascriptGenerator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; + generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; const argument1 = - javascriptGenerator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; + generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; const increment = - javascriptGenerator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; - let branch = javascriptGenerator.statementToCode(block, 'DO'); - branch = javascriptGenerator.addLoopTrap(branch, block); + generator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); let code; if (stringUtils.isNumber(argument0) && stringUtils.isNumber(argument1) && stringUtils.isNumber(increment)) { @@ -96,19 +96,19 @@ javascriptGenerator.forBlock['controls_for'] = function(block) { // Cache non-trivial values to variables to prevent repeated look-ups. let startVar = argument0; if (!argument0.match(/^\w+$/) && !stringUtils.isNumber(argument0)) { - startVar = javascriptGenerator.nameDB_.getDistinctName( + startVar = generator.nameDB_.getDistinctName( variable0 + '_start', NameType.VARIABLE); code += 'var ' + startVar + ' = ' + argument0 + ';\n'; } let endVar = argument1; if (!argument1.match(/^\w+$/) && !stringUtils.isNumber(argument1)) { - endVar = javascriptGenerator.nameDB_.getDistinctName( + endVar = generator.nameDB_.getDistinctName( variable0 + '_end', NameType.VARIABLE); code += 'var ' + endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. - const incVar = javascriptGenerator.nameDB_.getDistinctName( + const incVar = generator.nameDB_.getDistinctName( variable0 + '_inc', NameType.VARIABLE); code += 'var ' + incVar + ' = '; if (stringUtils.isNumber(increment)) { @@ -117,7 +117,7 @@ javascriptGenerator.forBlock['controls_for'] = function(block) { code += 'Math.abs(' + increment + ');\n'; } code += 'if (' + startVar + ' > ' + endVar + ') {\n'; - code += javascriptGenerator.INDENT + incVar + ' = -' + incVar + ';\n'; + code += generator.INDENT + incVar + ' = -' + incVar + ';\n'; code += '}\n'; code += 'for (' + variable0 + ' = ' + startVar + '; ' + incVar + ' >= 0 ? ' + variable0 + ' <= ' + endVar + ' : ' + variable0 + @@ -127,54 +127,54 @@ javascriptGenerator.forBlock['controls_for'] = function(block) { return code; }; -javascriptGenerator.forBlock['controls_forEach'] = function(block) { +javascriptGenerator.forBlock['controls_forEach'] = function(block, generator) { // For each loop. const variable0 = - javascriptGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); const argument0 = - javascriptGenerator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || + generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; - let branch = javascriptGenerator.statementToCode(block, 'DO'); - branch = javascriptGenerator.addLoopTrap(branch, block); + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); let code = ''; // Cache non-trivial values to variables to prevent repeated look-ups. let listVar = argument0; if (!argument0.match(/^\w+$/)) { - listVar = javascriptGenerator.nameDB_.getDistinctName( + listVar = generator.nameDB_.getDistinctName( variable0 + '_list', NameType.VARIABLE); code += 'var ' + listVar + ' = ' + argument0 + ';\n'; } - const indexVar = javascriptGenerator.nameDB_.getDistinctName( + const indexVar = generator.nameDB_.getDistinctName( variable0 + '_index', NameType.VARIABLE); - branch = javascriptGenerator.INDENT + variable0 + ' = ' + listVar + + branch = generator.INDENT + variable0 + ' = ' + listVar + '[' + indexVar + '];\n' + branch; code += 'for (var ' + indexVar + ' in ' + listVar + ') {\n' + branch + '}\n'; return code; }; -javascriptGenerator.forBlock['controls_flow_statements'] = function(block) { +javascriptGenerator.forBlock['controls_flow_statements'] = function(block, generator) { // Flow statements: continue, break. let xfix = ''; - if (javascriptGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - xfix += javascriptGenerator.injectId( - javascriptGenerator.STATEMENT_PREFIX, block); + xfix += generator.injectId( + generator.STATEMENT_PREFIX, block); } - if (javascriptGenerator.STATEMENT_SUFFIX) { + if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. - xfix += javascriptGenerator.injectId( - javascriptGenerator.STATEMENT_SUFFIX, block); + xfix += generator.injectId( + generator.STATEMENT_SUFFIX, block); } - if (javascriptGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { const loop = block.getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. - xfix += javascriptGenerator.injectId( - javascriptGenerator.STATEMENT_PREFIX, loop); + xfix += generator.injectId( + generator.STATEMENT_PREFIX, loop); } } switch (block.getFieldValue('FLOW')) { diff --git a/generators/javascript/math.js b/generators/javascript/math.js index dff0ba824..7089f8ac3 100644 --- a/generators/javascript/math.js +++ b/generators/javascript/math.js @@ -16,7 +16,7 @@ import {NameType} from '../../core/names.js'; import {Order, javascriptGenerator} from '../javascript.js'; -javascriptGenerator.forBlock['math_number'] = function(block) { +javascriptGenerator.forBlock['math_number'] = function(block, generator) { // Numeric value. const code = Number(block.getFieldValue('NUM')); const order = code >= 0 ? Order.ATOMIC : @@ -24,7 +24,7 @@ javascriptGenerator.forBlock['math_number'] = function(block) { return [code, order]; }; -javascriptGenerator.forBlock['math_arithmetic'] = function(block) { +javascriptGenerator.forBlock['math_arithmetic'] = function(block, generator) { // Basic arithmetic operators, and power. const OPERATORS = { 'ADD': [' + ', Order.ADDITION], @@ -36,8 +36,8 @@ javascriptGenerator.forBlock['math_arithmetic'] = function(block) { const tuple = OPERATORS[block.getFieldValue('OP')]; const operator = tuple[0]; const order = tuple[1]; - const argument0 = javascriptGenerator.valueToCode(block, 'A', order) || '0'; - const argument1 = javascriptGenerator.valueToCode(block, 'B', order) || '0'; + const argument0 = generator.valueToCode(block, 'A', order) || '0'; + const argument1 = generator.valueToCode(block, 'B', order) || '0'; let code; // Power in JavaScript requires a special case since it has no operator. if (!operator) { @@ -48,14 +48,14 @@ javascriptGenerator.forBlock['math_arithmetic'] = function(block) { return [code, order]; }; -javascriptGenerator.forBlock['math_single'] = function(block) { +javascriptGenerator.forBlock['math_single'] = function(block, generator) { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; let arg; if (operator === 'NEG') { // Negation is a special case given its different operator precedence. - arg = javascriptGenerator.valueToCode(block, 'NUM', + arg = generator.valueToCode(block, 'NUM', Order.UNARY_NEGATION) || '0'; if (arg[0] === '-') { // --3 is not legal in JS. @@ -65,10 +65,10 @@ javascriptGenerator.forBlock['math_single'] = function(block) { return [code, Order.UNARY_NEGATION]; } if (operator === 'SIN' || operator === 'COS' || operator === 'TAN') { - arg = javascriptGenerator.valueToCode(block, 'NUM', + arg = generator.valueToCode(block, 'NUM', Order.DIVISION) || '0'; } else { - arg = javascriptGenerator.valueToCode(block, 'NUM', + arg = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; } // First, handle cases which generate values that don't need parentheses @@ -132,7 +132,7 @@ javascriptGenerator.forBlock['math_single'] = function(block) { return [code, Order.DIVISION]; }; -javascriptGenerator.forBlock['math_constant'] = function(block) { +javascriptGenerator.forBlock['math_constant'] = function(block, generator) { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. const CONSTANTS = { 'PI': ['Math.PI', Order.MEMBER], @@ -145,7 +145,7 @@ javascriptGenerator.forBlock['math_constant'] = function(block) { return CONSTANTS[block.getFieldValue('CONSTANT')]; }; -javascriptGenerator.forBlock['math_number_property'] = function(block) { +javascriptGenerator.forBlock['math_number_property'] = function(block, generator) { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. const PROPERTIES = { @@ -163,13 +163,13 @@ javascriptGenerator.forBlock['math_number_property'] = function(block) { const dropdownProperty = block.getFieldValue('PROPERTY'); const [suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty]; const numberToCheck = - javascriptGenerator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || + generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || '0'; let code; if (dropdownProperty === 'PRIME') { // Prime is a special case as it is not a one-liner test. - const functionName = javascriptGenerator.provideFunction_('mathIsPrime', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(n) { + const functionName = generator.provideFunction_('mathIsPrime', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(n) { // https://en.wikipedia.org/wiki/Primality_test#Naive_methods if (n == 2 || n == 3) { return true; @@ -190,7 +190,7 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(n) { `); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = javascriptGenerator.valueToCode(block, 'DIVISOR', + const divisor = generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; code = numberToCheck + ' % ' + divisor + ' === 0'; } else { @@ -199,11 +199,11 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(n) { return [code, outputOrder]; }; -javascriptGenerator.forBlock['math_change'] = function(block) { +javascriptGenerator.forBlock['math_change'] = function(block, generator) { // Add to a variable in place. - const argument0 = javascriptGenerator.valueToCode(block, 'DELTA', + const argument0 = generator.valueToCode(block, 'DELTA', Order.ADDITION) || '0'; - const varName = javascriptGenerator.nameDB_.getName( + const varName = generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' = (typeof ' + varName + ' === \'number\' ? ' + varName + ' : 0) + ' + argument0 + ';\n'; @@ -216,43 +216,43 @@ javascriptGenerator.forBlock['math_round'] = javascriptGenerator.forBlock['math_trig'] = javascriptGenerator.forBlock['math_single']; -javascriptGenerator.forBlock['math_on_list'] = function(block) { +javascriptGenerator.forBlock['math_on_list'] = function(block, generator) { // Math functions for lists. const func = block.getFieldValue('OP'); let list; let code; switch (func) { case 'SUM': - list = javascriptGenerator.valueToCode(block, 'LIST', + list = generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; code = list + '.reduce(function(x, y) {return x + y;}, 0)'; break; case 'MIN': - list = javascriptGenerator.valueToCode(block, 'LIST', + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = 'Math.min.apply(null, ' + list + ')'; break; case 'MAX': - list = javascriptGenerator.valueToCode(block, 'LIST', + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = 'Math.max.apply(null, ' + list + ')'; break; case 'AVERAGE': { // mathMean([null,null,1,3]) === 2.0. - const functionName = javascriptGenerator.provideFunction_('mathMean', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList) { + const functionName = generator.provideFunction_('mathMean', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList) { return myList.reduce(function(x, y) {return x + y;}, 0) / myList.length; } `); - list = javascriptGenerator.valueToCode(block, 'LIST', + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'MEDIAN': { // mathMedian([null,null,1,3]) === 2.0. - const functionName = javascriptGenerator.provideFunction_('mathMedian', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList) { + const functionName = generator.provideFunction_('mathMedian', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList) { var localList = myList.filter(function (x) {return typeof x === 'number';}); if (!localList.length) return null; localList.sort(function(a, b) {return b - a;}); @@ -263,7 +263,7 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList) { } } `); - list = javascriptGenerator.valueToCode(block, 'LIST', + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; @@ -272,8 +272,8 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList) { // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1]. - const functionName = javascriptGenerator.provideFunction_('mathModes', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(values) { + const functionName = generator.provideFunction_('mathModes', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(values) { var modes = []; var counts = []; var maxCount = 0; @@ -302,15 +302,15 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(values) { return modes; } `); - list = javascriptGenerator.valueToCode(block, 'LIST', + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'STD_DEV': { const functionName = - javascriptGenerator.provideFunction_('mathStandardDeviation', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(numbers) { + generator.provideFunction_('mathStandardDeviation', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(numbers) { var n = numbers.length; if (!n) return null; var mean = numbers.reduce(function(x, y) {return x + y;}) / n; @@ -322,20 +322,20 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(numbers) { return Math.sqrt(variance); } `); - list = javascriptGenerator.valueToCode(block, 'LIST', + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'RANDOM': { const functionName = - javascriptGenerator.provideFunction_('mathRandomList', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(list) { + generator.provideFunction_('mathRandomList', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list) { var x = Math.floor(Math.random() * list.length); return list[x]; } `); - list = javascriptGenerator.valueToCode(block, 'LIST', + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; @@ -346,37 +346,37 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(list) { return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['math_modulo'] = function(block) { +javascriptGenerator.forBlock['math_modulo'] = function(block, generator) { // Remainder computation. - const argument0 = javascriptGenerator.valueToCode(block, 'DIVIDEND', + const argument0 = generator.valueToCode(block, 'DIVIDEND', Order.MODULUS) || '0'; - const argument1 = javascriptGenerator.valueToCode(block, 'DIVISOR', + const argument1 = generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MODULUS]; }; -javascriptGenerator.forBlock['math_constrain'] = function(block) { +javascriptGenerator.forBlock['math_constrain'] = function(block, generator) { // Constrain a number between two limits. - const argument0 = javascriptGenerator.valueToCode(block, 'VALUE', + const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; - const argument1 = javascriptGenerator.valueToCode(block, 'LOW', + const argument1 = generator.valueToCode(block, 'LOW', Order.NONE) || '0'; - const argument2 = javascriptGenerator.valueToCode(block, 'HIGH', + const argument2 = generator.valueToCode(block, 'HIGH', Order.NONE) || 'Infinity'; const code = 'Math.min(Math.max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['math_random_int'] = function(block) { +javascriptGenerator.forBlock['math_random_int'] = function(block, generator) { // Random integer between [X] and [Y]. - const argument0 = javascriptGenerator.valueToCode(block, 'FROM', + const argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; - const argument1 = javascriptGenerator.valueToCode(block, 'TO', + const argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; - const functionName = javascriptGenerator.provideFunction_('mathRandomInt', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(a, b) { + const functionName = generator.provideFunction_('mathRandomInt', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(a, b) { if (a > b) { // Swap a and b to ensure a is smaller. var c = a; @@ -390,16 +390,16 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(a, b) { return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['math_random_float'] = function(block) { +javascriptGenerator.forBlock['math_random_float'] = function(block, generator) { // Random fraction between 0 and 1. return ['Math.random()', Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['math_atan2'] = function(block) { +javascriptGenerator.forBlock['math_atan2'] = function(block, generator) { // Arctangent of point (X, Y) in degrees from -180 to 180. - const argument0 = javascriptGenerator.valueToCode(block, 'X', + const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; - const argument1 = javascriptGenerator.valueToCode(block, 'Y', + const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; return ['Math.atan2(' + argument1 + ', ' + argument0 + ') / Math.PI * 180', Order.DIVISION]; diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index fd4d896ce..1dae9c327 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -15,51 +15,51 @@ import {NameType} from '../../core/names.js'; import {Order, javascriptGenerator} from '../javascript.js'; -javascriptGenerator.forBlock['procedures_defreturn'] = function(block) { +javascriptGenerator.forBlock['procedures_defreturn'] = function(block, generator) { // Define a procedure with a return value. - const funcName = javascriptGenerator.nameDB_.getName( + const funcName = generator.nameDB_.getName( block.getFieldValue('NAME'), NameType.PROCEDURE); let xfix1 = ''; - if (javascriptGenerator.STATEMENT_PREFIX) { - xfix1 += javascriptGenerator.injectId( - javascriptGenerator.STATEMENT_PREFIX, block); + if (generator.STATEMENT_PREFIX) { + xfix1 += generator.injectId( + generator.STATEMENT_PREFIX, block); } - if (javascriptGenerator.STATEMENT_SUFFIX) { - xfix1 += javascriptGenerator.injectId( - javascriptGenerator.STATEMENT_SUFFIX, block); + if (generator.STATEMENT_SUFFIX) { + xfix1 += generator.injectId( + generator.STATEMENT_SUFFIX, block); } if (xfix1) { - xfix1 = javascriptGenerator.prefixLines(xfix1, javascriptGenerator.INDENT); + xfix1 = generator.prefixLines(xfix1, generator.INDENT); } let loopTrap = ''; - if (javascriptGenerator.INFINITE_LOOP_TRAP) { - loopTrap = javascriptGenerator.prefixLines( - javascriptGenerator.injectId( - javascriptGenerator.INFINITE_LOOP_TRAP, block), - javascriptGenerator.INDENT); + if (generator.INFINITE_LOOP_TRAP) { + loopTrap = generator.prefixLines( + generator.injectId( + generator.INFINITE_LOOP_TRAP, block), + generator.INDENT); } - const branch = javascriptGenerator.statementToCode(block, 'STACK'); + const branch = generator.statementToCode(block, 'STACK'); let returnValue = - javascriptGenerator.valueToCode(block, 'RETURN', Order.NONE) || ''; + generator.valueToCode(block, 'RETURN', Order.NONE) || ''; let xfix2 = ''; if (branch && returnValue) { // After executing the function body, revisit this block for the return. xfix2 = xfix1; } if (returnValue) { - returnValue = javascriptGenerator.INDENT + 'return ' + returnValue + ';\n'; + returnValue = generator.INDENT + 'return ' + returnValue + ';\n'; } const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { args[i] = - javascriptGenerator.nameDB_.getName(variables[i], NameType.VARIABLE); + generator.nameDB_.getName(variables[i], NameType.VARIABLE); } let code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; - code = javascriptGenerator.scrub_(block, code); + code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - javascriptGenerator.definitions_['%' + funcName] = code; + generator.definitions_['%' + funcName] = code; return null; }; @@ -68,56 +68,48 @@ javascriptGenerator.forBlock['procedures_defreturn'] = function(block) { javascriptGenerator.forBlock['procedures_defnoreturn'] = javascriptGenerator.forBlock['procedures_defreturn']; -javascriptGenerator.forBlock['procedures_callreturn'] = function(block) { +javascriptGenerator.forBlock['procedures_callreturn'] = function(block, generator) { // Call a procedure with a return value. - const funcName = javascriptGenerator.nameDB_.getName( + const funcName = generator.nameDB_.getName( block.getFieldValue('NAME'), NameType.PROCEDURE); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = javascriptGenerator.valueToCode(block, 'ARG' + i, Order.NONE) || + args[i] = generator.valueToCode(block, 'ARG' + i, Order.NONE) || 'null'; } const code = funcName + '(' + args.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['procedures_callnoreturn'] = function(block) { +javascriptGenerator.forBlock['procedures_callnoreturn'] = function(block, generator) { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = javascriptGenerator.forBlock['procedures_callreturn'](block); + const tuple = generator.forBlock['procedures_callreturn'](block, generator); return tuple[0] + ';\n'; }; -javascriptGenerator.forBlock['procedures_callnoreturn'] = function(block) { - // Call a procedure with no return value. - // Generated code is for a function call as a statement is the same as a - // function call as a value, with the addition of line ending. - const tuple = javascriptGenerator.forBlock['procedures_callreturn'](block); - return tuple[0] + ';\n'; -}; - -javascriptGenerator.forBlock['procedures_ifreturn'] = function(block) { +javascriptGenerator.forBlock['procedures_ifreturn'] = function(block, generator) { // Conditionally return value from a procedure. const condition = - javascriptGenerator.valueToCode(block, 'CONDITION', Order.NONE) || + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; let code = 'if (' + condition + ') {\n'; - if (javascriptGenerator.STATEMENT_SUFFIX) { + if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. - code += javascriptGenerator.prefixLines( - javascriptGenerator.injectId( - javascriptGenerator.STATEMENT_SUFFIX, block), - javascriptGenerator.INDENT); + code += generator.prefixLines( + generator.injectId( + generator.STATEMENT_SUFFIX, block), + generator.INDENT); } if (block.hasReturnValue_) { const value = - javascriptGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; - code += javascriptGenerator.INDENT + 'return ' + value + ';\n'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; + code += generator.INDENT + 'return ' + value + ';\n'; } else { - code += javascriptGenerator.INDENT + 'return;\n'; + code += generator.INDENT + 'return;\n'; } code += '}\n'; return code; diff --git a/generators/javascript/text.js b/generators/javascript/text.js index ea3edb4bb..e4da2b9df 100644 --- a/generators/javascript/text.js +++ b/generators/javascript/text.js @@ -53,36 +53,36 @@ const getSubstringIndex = function(stringName, where, opt_at) { } }; -javascriptGenerator.forBlock['text'] = function(block) { +javascriptGenerator.forBlock['text'] = function(block, generator) { // Text value. - const code = javascriptGenerator.quote_(block.getFieldValue('TEXT')); + const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; }; -javascriptGenerator.forBlock['text_multiline'] = function(block) { +javascriptGenerator.forBlock['text_multiline'] = function(block, generator) { // Text value. const code = - javascriptGenerator.multiline_quote_(block.getFieldValue('TEXT')); + generator.multiline_quote_(block.getFieldValue('TEXT')); const order = code.indexOf('+') !== -1 ? Order.ADDITION : Order.ATOMIC; return [code, order]; }; -javascriptGenerator.forBlock['text_join'] = function(block) { +javascriptGenerator.forBlock['text_join'] = function(block, generator) { // Create a string made up of any number of elements of any type. switch (block.itemCount_) { case 0: return ["''", Order.ATOMIC]; case 1: { - const element = javascriptGenerator.valueToCode(block, 'ADD0', + const element = generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; const codeAndOrder = forceString(element); return codeAndOrder; } case 2: { - const element0 = javascriptGenerator.valueToCode(block, 'ADD0', + const element0 = generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; - const element1 = javascriptGenerator.valueToCode(block, 'ADD1', + const element1 = generator.valueToCode(block, 'ADD1', Order.NONE) || "''"; const code = forceString(element0)[0] + ' + ' + forceString(element1)[0]; @@ -91,7 +91,7 @@ javascriptGenerator.forBlock['text_join'] = function(block) { default: { const elements = new Array(block.itemCount_); for (let i = 0; i < block.itemCount_; i++) { - elements[i] = javascriptGenerator.valueToCode(block, 'ADD' + i, + elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } const code = '[' + elements.join(',') + '].join(\'\')'; @@ -100,38 +100,38 @@ javascriptGenerator.forBlock['text_join'] = function(block) { } }; -javascriptGenerator.forBlock['text_append'] = function(block) { +javascriptGenerator.forBlock['text_append'] = function(block, generator) { // Append to a variable in place. - const varName = javascriptGenerator.nameDB_.getName( + const varName = generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); - const value = javascriptGenerator.valueToCode(block, 'TEXT', + const value = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const code = varName + ' += ' + forceString(value)[0] + ';\n'; return code; }; -javascriptGenerator.forBlock['text_length'] = function(block) { +javascriptGenerator.forBlock['text_length'] = function(block, generator) { // String or array length. - const text = javascriptGenerator.valueToCode(block, 'VALUE', + const text = generator.valueToCode(block, 'VALUE', Order.MEMBER) || "''"; return [text + '.length', Order.MEMBER]; }; -javascriptGenerator.forBlock['text_isEmpty'] = function(block) { +javascriptGenerator.forBlock['text_isEmpty'] = function(block, generator) { // Is the string null or array empty? - const text = javascriptGenerator.valueToCode(block, 'VALUE', + const text = generator.valueToCode(block, 'VALUE', Order.MEMBER) || "''"; return ['!' + text + '.length', Order.LOGICAL_NOT]; }; -javascriptGenerator.forBlock['text_indexOf'] = function(block) { +javascriptGenerator.forBlock['text_indexOf'] = function(block, generator) { // Search the text for a substring. const operator = block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; - const substring = javascriptGenerator.valueToCode(block, 'FIND', + const substring = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; - const text = javascriptGenerator.valueToCode(block, 'VALUE', + const text = generator.valueToCode(block, 'VALUE', Order.MEMBER) || "''"; const code = text + '.' + operator + '(' + substring + ')'; // Adjust index if using one-based indices. @@ -141,14 +141,14 @@ javascriptGenerator.forBlock['text_indexOf'] = function(block) { return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['text_charAt'] = function(block) { +javascriptGenerator.forBlock['text_charAt'] = function(block, generator) { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. const where = block.getFieldValue('WHERE') || 'FROM_START'; const textOrder = (where === 'RANDOM') ? Order.NONE : Order.MEMBER; const text = - javascriptGenerator.valueToCode(block, 'VALUE', textOrder) || "''"; + generator.valueToCode(block, 'VALUE', textOrder) || "''"; switch (where) { case 'FIRST': { const code = text + '.charAt(0)'; @@ -159,20 +159,20 @@ javascriptGenerator.forBlock['text_charAt'] = function(block) { return [code, Order.FUNCTION_CALL]; } case 'FROM_START': { - const at = javascriptGenerator.getAdjusted(block, 'AT'); + const at = generator.getAdjusted(block, 'AT'); // Adjust index if using one-based indices. const code = text + '.charAt(' + at + ')'; return [code, Order.FUNCTION_CALL]; } case 'FROM_END': { - const at = javascriptGenerator.getAdjusted(block, 'AT', 1, true); + const at = generator.getAdjusted(block, 'AT', 1, true); const code = text + '.slice(' + at + ').charAt(0)'; return [code, Order.FUNCTION_CALL]; } case 'RANDOM': { const functionName = - javascriptGenerator.provideFunction_('textRandomLetter', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(text) { + generator.provideFunction_('textRandomLetter', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(text) { var x = Math.floor(Math.random() * text.length); return text[x]; } @@ -184,7 +184,7 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(text) { throw Error('Unhandled option (text_charAt).'); }; -javascriptGenerator.forBlock['text_getSubstring'] = function(block) { +javascriptGenerator.forBlock['text_getSubstring'] = function(block, generator) { // Get substring. const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); @@ -193,7 +193,7 @@ javascriptGenerator.forBlock['text_getSubstring'] = function(block) { const textOrder = requiresLengthCall ? Order.MEMBER : Order.NONE; const text = - javascriptGenerator.valueToCode(block, 'STRING', textOrder) || "''"; + generator.valueToCode(block, 'STRING', textOrder) || "''"; let code; if (where1 === 'FIRST' && where2 === 'LAST') { code = text; @@ -204,10 +204,10 @@ javascriptGenerator.forBlock['text_getSubstring'] = function(block) { let at1; switch (where1) { case 'FROM_START': - at1 = javascriptGenerator.getAdjusted(block, 'AT1'); + at1 = generator.getAdjusted(block, 'AT1'); break; case 'FROM_END': - at1 = javascriptGenerator.getAdjusted(block, 'AT1', 1, false, + at1 = generator.getAdjusted(block, 'AT1', 1, false, Order.SUBTRACTION); at1 = text + '.length - ' + at1; break; @@ -220,10 +220,10 @@ javascriptGenerator.forBlock['text_getSubstring'] = function(block) { let at2; switch (where2) { case 'FROM_START': - at2 = javascriptGenerator.getAdjusted(block, 'AT2', 1); + at2 = generator.getAdjusted(block, 'AT2', 1); break; case 'FROM_END': - at2 = javascriptGenerator.getAdjusted(block, 'AT2', 0, false, + at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); at2 = text + '.length - ' + at2; break; @@ -235,8 +235,8 @@ javascriptGenerator.forBlock['text_getSubstring'] = function(block) { } code = text + '.slice(' + at1 + ', ' + at2 + ')'; } else { - const at1 = javascriptGenerator.getAdjusted(block, 'AT1'); - const at2 = javascriptGenerator.getAdjusted(block, 'AT2'); + const at1 = generator.getAdjusted(block, 'AT1'); + const at2 = generator.getAdjusted(block, 'AT2'); const wherePascalCase = {'FIRST': 'First', 'LAST': 'Last', 'FROM_START': 'FromStart', 'FROM_END': 'FromEnd'}; // The value for 'FROM_END' and'FROM_START' depends on `at` so @@ -245,9 +245,9 @@ javascriptGenerator.forBlock['text_getSubstring'] = function(block) { (where1 === 'FROM_END' || where1 === 'FROM_START') ? ', at1' : ''; const at2Param = (where2 === 'FROM_END' || where2 === 'FROM_START') ? ', at2' : ''; - const functionName = javascriptGenerator.provideFunction_( + const functionName = generator.provideFunction_( 'subsequence' + wherePascalCase[where1] + wherePascalCase[where2], ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(sequence${at1Param}${at2Param}) { +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(sequence${at1Param}${at2Param}) { var start = ${getSubstringIndex('sequence', where1, 'at1')}; var end = ${getSubstringIndex('sequence', where2, 'at2')} + 1; return sequence.slice(start, end); @@ -263,7 +263,7 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(sequence${at1Param}${ return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['text_changeCase'] = function(block) { +javascriptGenerator.forBlock['text_changeCase'] = function(block, generator) { // Change capitalization. const OPERATORS = { 'UPPERCASE': '.toUpperCase()', @@ -273,16 +273,16 @@ javascriptGenerator.forBlock['text_changeCase'] = function(block) { const operator = OPERATORS[block.getFieldValue('CASE')]; const textOrder = operator ? Order.MEMBER : Order.NONE; const text = - javascriptGenerator.valueToCode(block, 'TEXT', textOrder) || "''"; + generator.valueToCode(block, 'TEXT', textOrder) || "''"; let code; if (operator) { - // Upper and lower case are functions built into javascriptGenerator. + // Upper and lower case are functions built into generator. code = text + operator; } else { // Title case is not a native JavaScript function. Define one. const functionName = - javascriptGenerator.provideFunction_('textToTitleCase', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(str) { + generator.provideFunction_('textToTitleCase', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str) { return str.replace(/\\S+/g, function(txt) {return txt[0].toUpperCase() + txt.substring(1).toLowerCase();}); } @@ -292,7 +292,7 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(str) { return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['text_trim'] = function(block) { +javascriptGenerator.forBlock['text_trim'] = function(block, generator) { // Trim spaces. const OPERATORS = { 'LEFT': ".replace(/^[\\s\\xa0]+/, '')", @@ -300,27 +300,27 @@ javascriptGenerator.forBlock['text_trim'] = function(block) { 'BOTH': '.trim()', }; const operator = OPERATORS[block.getFieldValue('MODE')]; - const text = javascriptGenerator.valueToCode(block, 'TEXT', + const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; return [text + operator, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['text_print'] = function(block) { +javascriptGenerator.forBlock['text_print'] = function(block, generator) { // Print statement. - const msg = javascriptGenerator.valueToCode(block, 'TEXT', + const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'window.alert(' + msg + ');\n'; }; -javascriptGenerator.forBlock['text_prompt_ext'] = function(block) { +javascriptGenerator.forBlock['text_prompt_ext'] = function(block, generator) { // Prompt function. let msg; if (block.getField('TEXT')) { // Internal message. - msg = javascriptGenerator.quote_(block.getFieldValue('TEXT')); + msg = generator.quote_(block.getFieldValue('TEXT')); } else { // External message. - msg = javascriptGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; } let code = 'window.prompt(' + msg + ')'; const toNumber = block.getFieldValue('TYPE') === 'NUMBER'; @@ -333,13 +333,13 @@ javascriptGenerator.forBlock['text_prompt_ext'] = function(block) { javascriptGenerator.forBlock['text_prompt'] = javascriptGenerator.forBlock['text_prompt_ext']; -javascriptGenerator.forBlock['text_count'] = function(block) { - const text = javascriptGenerator.valueToCode(block, 'TEXT', +javascriptGenerator.forBlock['text_count'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; - const sub = javascriptGenerator.valueToCode(block, 'SUB', + const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; - const functionName = javascriptGenerator.provideFunction_('textCount', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle) { + const functionName = generator.provideFunction_('textCount', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle) { if (needle.length === 0) { return haystack.length + 1; } else { @@ -351,16 +351,16 @@ function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle) { return [code, Order.FUNCTION_CALL]; }; -javascriptGenerator.forBlock['text_replace'] = function(block) { - const text = javascriptGenerator.valueToCode(block, 'TEXT', +javascriptGenerator.forBlock['text_replace'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; - const from = javascriptGenerator.valueToCode(block, 'FROM', + const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; - const to = javascriptGenerator.valueToCode(block, 'TO', Order.NONE) || "''"; + const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; // The regex escaping code below is taken from the implementation of // goog.string.regExpEscape. - const functionName = javascriptGenerator.provideFunction_('textReplace', ` -function ${javascriptGenerator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle, replacement) { + const functionName = generator.provideFunction_('textReplace', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle, replacement) { needle = needle.replace(/([-()\\[\\]{}+?*.$\\^|,:# 0 ? 'else' : '') + 'if ' + conditionCode + ' then\n' + branchCode; n++; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE') || luaGenerator.STATEMENT_SUFFIX) { - let branchCode = luaGenerator.statementToCode(block, 'ELSE'); - if (luaGenerator.STATEMENT_SUFFIX) { + if (block.getInput('ELSE') || generator.STATEMENT_SUFFIX) { + let branchCode = generator.statementToCode(block, 'ELSE'); + if (generator.STATEMENT_SUFFIX) { branchCode = - luaGenerator.prefixLines( - luaGenerator.injectId( - luaGenerator.STATEMENT_SUFFIX, block), - luaGenerator.INDENT) + + generator.prefixLines( + generator.injectId( + generator.STATEMENT_SUFFIX, block), + generator.INDENT) + branchCode; } code += 'else\n' + branchCode; @@ -53,25 +53,25 @@ luaGenerator.forBlock['controls_if'] = function(block) { luaGenerator.forBlock['controls_ifelse'] = luaGenerator.forBlock['controls_if']; -luaGenerator.forBlock['logic_compare'] = function(block) { +luaGenerator.forBlock['logic_compare'] = function(block, generator) { // Comparison operator. const OPERATORS = {'EQ': '==', 'NEQ': '~=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; const operator = OPERATORS[block.getFieldValue('OP')]; const argument0 = - luaGenerator.valueToCode(block, 'A', Order.RELATIONAL) || '0'; + generator.valueToCode(block, 'A', Order.RELATIONAL) || '0'; const argument1 = - luaGenerator.valueToCode(block, 'B', Order.RELATIONAL) || '0'; + generator.valueToCode(block, 'B', Order.RELATIONAL) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, Order.RELATIONAL]; }; -luaGenerator.forBlock['logic_operation'] = function(block) { +luaGenerator.forBlock['logic_operation'] = function(block, generator) { // Operations 'and', 'or'. const operator = (block.getFieldValue('OP') === 'AND') ? 'and' : 'or'; const order = (operator === 'and') ? Order.AND : Order.OR; - let argument0 = luaGenerator.valueToCode(block, 'A', order); - let argument1 = luaGenerator.valueToCode(block, 'B', order); + let argument0 = generator.valueToCode(block, 'A', order); + let argument1 = generator.valueToCode(block, 'B', order); if (!argument0 && !argument1) { // If there are no arguments, then the return value is false. argument0 = 'false'; @@ -90,31 +90,31 @@ luaGenerator.forBlock['logic_operation'] = function(block) { return [code, order]; }; -luaGenerator.forBlock['logic_negate'] = function(block) { +luaGenerator.forBlock['logic_negate'] = function(block, generator) { // Negation. const argument0 = - luaGenerator.valueToCode(block, 'BOOL', Order.UNARY) || 'true'; + generator.valueToCode(block, 'BOOL', Order.UNARY) || 'true'; const code = 'not ' + argument0; return [code, Order.UNARY]; }; -luaGenerator.forBlock['logic_boolean'] = function(block) { +luaGenerator.forBlock['logic_boolean'] = function(block, generator) { // Boolean values true and false. const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'true' : 'false'; return [code, Order.ATOMIC]; }; -luaGenerator.forBlock['logic_null'] = function(block) { +luaGenerator.forBlock['logic_null'] = function(block, generator) { // Null data type. return ['nil', Order.ATOMIC]; }; -luaGenerator.forBlock['logic_ternary'] = function(block) { +luaGenerator.forBlock['logic_ternary'] = function(block, generator) { // Ternary operator. - const value_if = luaGenerator.valueToCode(block, 'IF', Order.AND) || 'false'; + const value_if = generator.valueToCode(block, 'IF', Order.AND) || 'false'; const value_then = - luaGenerator.valueToCode(block, 'THEN', Order.AND) || 'nil'; - const value_else = luaGenerator.valueToCode(block, 'ELSE', Order.OR) || 'nil'; + generator.valueToCode(block, 'THEN', Order.AND) || 'nil'; + const value_else = generator.valueToCode(block, 'ELSE', Order.OR) || 'nil'; const code = value_if + ' and ' + value_then + ' or ' + value_else; return [code, Order.OR]; }; diff --git a/generators/lua/loops.js b/generators/lua/loops.js index 9a1b71b45..02f40b410 100644 --- a/generators/lua/loops.js +++ b/generators/lua/loops.js @@ -31,18 +31,19 @@ const CONTINUE_STATEMENT = 'goto continue\n'; * blockToCode. * * @param {string} branch Generated code of the loop body + * @param {string} indent Whitespace by which to indent a continue statement. * @return {string} Generated label or '' if unnecessary */ -const addContinueLabel = function(branch) { +function addContinueLabel(branch, indent) { if (branch.indexOf(CONTINUE_STATEMENT) !== -1) { // False positives are possible (e.g. a string literal), but are harmless. - return branch + luaGenerator.INDENT + '::continue::\n'; + return branch + indent + '::continue::\n'; } else { return branch; } }; -luaGenerator.forBlock['controls_repeat_ext'] = function(block) { +luaGenerator.forBlock['controls_repeat_ext'] = function(block, generator) { // Repeat n times. let repeats; if (block.getField('TIMES')) { @@ -50,17 +51,17 @@ luaGenerator.forBlock['controls_repeat_ext'] = function(block) { repeats = String(Number(block.getFieldValue('TIMES'))); } else { // External number. - repeats = luaGenerator.valueToCode(block, 'TIMES', Order.NONE) || '0'; + repeats = generator.valueToCode(block, 'TIMES', Order.NONE) || '0'; } if (stringUtils.isNumber(repeats)) { repeats = parseInt(repeats, 10); } else { repeats = 'math.floor(' + repeats + ')'; } - let branch = luaGenerator.statementToCode(block, 'DO'); - branch = luaGenerator.addLoopTrap(branch, block); - branch = addContinueLabel(branch); - const loopVar = luaGenerator.nameDB_.getDistinctName('count', NameType.VARIABLE); + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); + branch = addContinueLabel(branch, generator.INDENT); + const loopVar = generator.nameDB_.getDistinctName('count', NameType.VARIABLE); const code = 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' + branch + 'end\n'; return code; @@ -69,33 +70,33 @@ luaGenerator.forBlock['controls_repeat_ext'] = function(block) { luaGenerator.forBlock['controls_repeat'] = luaGenerator.forBlock['controls_repeat_ext']; -luaGenerator.forBlock['controls_whileUntil'] = function(block) { +luaGenerator.forBlock['controls_whileUntil'] = function(block, generator) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; let argument0 = - luaGenerator.valueToCode( + generator.valueToCode( block, 'BOOL', until ? Order.UNARY : Order.NONE) || 'false'; - let branch = luaGenerator.statementToCode(block, 'DO'); - branch = luaGenerator.addLoopTrap(branch, block); - branch = addContinueLabel(branch); + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); + branch = addContinueLabel(branch, generator.INDENT); if (until) { argument0 = 'not ' + argument0; } return 'while ' + argument0 + ' do\n' + branch + 'end\n'; }; -luaGenerator.forBlock['controls_for'] = function(block) { +luaGenerator.forBlock['controls_for'] = function(block, generator) { // For loop. const variable0 = - luaGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); - const startVar = luaGenerator.valueToCode(block, 'FROM', Order.NONE) || '0'; - const endVar = luaGenerator.valueToCode(block, 'TO', Order.NONE) || '0'; - const increment = luaGenerator.valueToCode(block, 'BY', Order.NONE) || '1'; - let branch = luaGenerator.statementToCode(block, 'DO'); - branch = luaGenerator.addLoopTrap(branch, block); - branch = addContinueLabel(branch); + const startVar = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; + const endVar = generator.valueToCode(block, 'TO', Order.NONE) || '0'; + const increment = generator.valueToCode(block, 'BY', Order.NONE) || '1'; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); + branch = addContinueLabel(branch, generator.INDENT); let code = ''; let incValue; if (stringUtils.isNumber(startVar) && stringUtils.isNumber(endVar) && @@ -109,7 +110,7 @@ luaGenerator.forBlock['controls_for'] = function(block) { // Determine loop direction at start, in case one of the bounds // changes during loop execution. incValue = - luaGenerator.nameDB_.getDistinctName( + generator.nameDB_.getDistinctName( variable0 + '_inc', NameType.VARIABLE); code += incValue + ' = '; if (stringUtils.isNumber(increment)) { @@ -118,7 +119,7 @@ luaGenerator.forBlock['controls_for'] = function(block) { code += 'math.abs(' + increment + ')\n'; } code += 'if (' + startVar + ') > (' + endVar + ') then\n'; - code += luaGenerator.INDENT + incValue + ' = -' + incValue + '\n'; + code += generator.INDENT + incValue + ' = -' + incValue + '\n'; code += 'end\n'; } code += @@ -127,39 +128,39 @@ luaGenerator.forBlock['controls_for'] = function(block) { return code; }; -luaGenerator.forBlock['controls_forEach'] = function(block) { +luaGenerator.forBlock['controls_forEach'] = function(block, generator) { // For each loop. const variable0 = - luaGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); - const argument0 = luaGenerator.valueToCode(block, 'LIST', Order.NONE) || '{}'; - let branch = luaGenerator.statementToCode(block, 'DO'); - branch = luaGenerator.addLoopTrap(branch, block); - branch = addContinueLabel(branch); + const argument0 = generator.valueToCode(block, 'LIST', Order.NONE) || '{}'; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); + branch = addContinueLabel(branch, generator.INDENT); const code = 'for _, ' + variable0 + ' in ipairs(' + argument0 + ') do \n' + branch + 'end\n'; return code; }; -luaGenerator.forBlock['controls_flow_statements'] = function(block) { +luaGenerator.forBlock['controls_flow_statements'] = function(block, generator) { // Flow statements: continue, break. let xfix = ''; - if (luaGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - xfix += luaGenerator.injectId(luaGenerator.STATEMENT_PREFIX, block); + xfix += generator.injectId(generator.STATEMENT_PREFIX, block); } - if (luaGenerator.STATEMENT_SUFFIX) { + if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. - xfix += luaGenerator.injectId(luaGenerator.STATEMENT_SUFFIX, block); + xfix += generator.injectId(generator.STATEMENT_SUFFIX, block); } - if (luaGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { const loop = block.getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. - xfix += luaGenerator.injectId(luaGenerator.STATEMENT_PREFIX, loop); + xfix += generator.injectId(generator.STATEMENT_PREFIX, loop); } } switch (block.getFieldValue('FLOW')) { diff --git a/generators/lua/math.js b/generators/lua/math.js index 5b1ac2849..b6d69fa1a 100644 --- a/generators/lua/math.js +++ b/generators/lua/math.js @@ -15,14 +15,14 @@ import {NameType} from '../../core/names.js'; import {luaGenerator, Order} from '../lua.js'; -luaGenerator.forBlock['math_number'] = function(block) { +luaGenerator.forBlock['math_number'] = function(block, generator) { // Numeric value. const code = Number(block.getFieldValue('NUM')); const order = code < 0 ? Order.UNARY : Order.ATOMIC; return [code, order]; }; -luaGenerator.forBlock['math_arithmetic'] = function(block) { +luaGenerator.forBlock['math_arithmetic'] = function(block, generator) { // Basic arithmetic operators, and power. const OPERATORS = { 'ADD': [' + ', Order.ADDITIVE], @@ -34,29 +34,29 @@ luaGenerator.forBlock['math_arithmetic'] = function(block) { const tuple = OPERATORS[block.getFieldValue('OP')]; const operator = tuple[0]; const order = tuple[1]; - const argument0 = luaGenerator.valueToCode(block, 'A', order) || '0'; - const argument1 = luaGenerator.valueToCode(block, 'B', order) || '0'; + const argument0 = generator.valueToCode(block, 'A', order) || '0'; + const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + operator + argument1; return [code, order]; }; -luaGenerator.forBlock['math_single'] = function(block) { +luaGenerator.forBlock['math_single'] = function(block, generator) { // Math operators with single operand. const operator = block.getFieldValue('OP'); let arg; if (operator === 'NEG') { // Negation is a special case given its different operator precedence. - arg = luaGenerator.valueToCode(block, 'NUM', Order.UNARY) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.UNARY) || '0'; return ['-' + arg, Order.UNARY]; } if (operator === 'POW10') { - arg = luaGenerator.valueToCode(block, 'NUM', Order.EXPONENTIATION) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.EXPONENTIATION) || '0'; return ['10 ^ ' + arg, Order.EXPONENTIATION]; } if (operator === 'ROUND') { - arg = luaGenerator.valueToCode(block, 'NUM', Order.ADDITIVE) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.ADDITIVE) || '0'; } else { - arg = luaGenerator.valueToCode(block, 'NUM', Order.NONE) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; } let code; @@ -110,7 +110,7 @@ luaGenerator.forBlock['math_single'] = function(block) { return [code, Order.HIGH]; }; -luaGenerator.forBlock['math_constant'] = function(block) { +luaGenerator.forBlock['math_constant'] = function(block, generator) { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. const CONSTANTS = { 'PI': ['math.pi', Order.HIGH], @@ -123,7 +123,7 @@ luaGenerator.forBlock['math_constant'] = function(block) { return CONSTANTS[block.getFieldValue('CONSTANT')]; }; -luaGenerator.forBlock['math_number_property'] = function(block) { +luaGenerator.forBlock['math_number_property'] = function(block, generator) { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. const PROPERTIES = { @@ -137,13 +137,13 @@ luaGenerator.forBlock['math_number_property'] = function(block) { }; const dropdownProperty = block.getFieldValue('PROPERTY'); const [suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty]; - const numberToCheck = luaGenerator.valueToCode(block, 'NUMBER_TO_CHECK', + const numberToCheck = generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || '0'; let code; if (dropdownProperty === 'PRIME') { // Prime is a special case as it is not a one-liner test. - const functionName = luaGenerator.provideFunction_('math_isPrime', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(n) + const functionName = generator.provideFunction_('math_isPrime', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(n) -- https://en.wikipedia.org/wiki/Primality_test#Naive_methods if n == 2 or n == 3 then return true @@ -164,9 +164,9 @@ end `); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = luaGenerator.valueToCode(block, 'DIVISOR', + const divisor = generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; - // If 'divisor' is some code that evals to 0, luaGenerator will produce a nan. + // If 'divisor' is some code that evals to 0, generator will produce a nan. // Let's produce nil if we can determine this at compile-time. if (divisor === '0') { return ['nil', Order.ATOMIC]; @@ -181,12 +181,12 @@ end return [code, outputOrder]; }; -luaGenerator.forBlock['math_change'] = function(block) { +luaGenerator.forBlock['math_change'] = function(block, generator) { // Add to a variable in place. const argument0 = - luaGenerator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; + generator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; const varName = - luaGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' = ' + varName + ' + ' + argument0 + '\n'; }; @@ -196,16 +196,16 @@ luaGenerator.forBlock['math_round'] = luaGenerator.forBlock['math_single']; // Trigonometry functions have a single operand. luaGenerator.forBlock['math_trig'] = luaGenerator.forBlock['math_single']; -luaGenerator.forBlock['math_on_list'] = function(block) { +luaGenerator.forBlock['math_on_list'] = function(block, generator) { // Math functions for lists. const func = block.getFieldValue('OP'); - const list = luaGenerator.valueToCode(block, 'LIST', Order.NONE) || '{}'; + const list = generator.valueToCode(block, 'LIST', Order.NONE) || '{}'; let functionName; // Functions needed in more than one case. function provideSum() { - return luaGenerator.provideFunction_('math_sum', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(t) + return generator.provideFunction_('math_sum', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) local result = 0 for _, v in ipairs(t) do result = result + v @@ -222,8 +222,8 @@ end case 'MIN': // Returns 0 for the empty list. - functionName = luaGenerator.provideFunction_('math_min', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(t) + functionName = generator.provideFunction_('math_min', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) if #t == 0 then return 0 end @@ -240,8 +240,8 @@ end case 'AVERAGE': // Returns 0 for the empty list. - functionName = luaGenerator.provideFunction_('math_average', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(t) + functionName = generator.provideFunction_('math_average', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) if #t == 0 then return 0 end @@ -252,8 +252,8 @@ end case 'MAX': // Returns 0 for the empty list. - functionName = luaGenerator.provideFunction_('math_max', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(t) + functionName = generator.provideFunction_('math_max', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) if #t == 0 then return 0 end @@ -270,8 +270,8 @@ end case 'MEDIAN': // This operation excludes non-numbers. - functionName = luaGenerator.provideFunction_('math_median', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(t) + functionName = generator.provideFunction_('math_median', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) -- Source: http://lua-users.org/wiki/SimpleStats if #t == 0 then return 0 @@ -295,9 +295,9 @@ end case 'MODE': // As a list of numbers can contain more than one mode, // the returned result is provided as an array. - // The luaGenerator version includes non-numbers. - functionName = luaGenerator.provideFunction_('math_modes', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(t) + // The generator version includes non-numbers. + functionName = generator.provideFunction_('math_modes', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) -- Source: http://lua-users.org/wiki/SimpleStats local counts = {} for _, v in ipairs(t) do @@ -325,8 +325,8 @@ end break; case 'STD_DEV': - functionName = luaGenerator.provideFunction_('math_standard_deviation', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(t) + functionName = generator.provideFunction_('math_standard_deviation', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) local m local vm local total = 0 @@ -347,8 +347,8 @@ end break; case 'RANDOM': - functionName = luaGenerator.provideFunction_('math_random_list', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(t) + functionName = generator.provideFunction_('math_random_list', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) if #t == 0 then return nil end @@ -363,45 +363,45 @@ end return [functionName + '(' + list + ')', Order.HIGH]; }; -luaGenerator.forBlock['math_modulo'] = function(block) { +luaGenerator.forBlock['math_modulo'] = function(block, generator) { // Remainder computation. const argument0 = - luaGenerator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || '0'; const argument1 = - luaGenerator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MULTIPLICATIVE]; }; -luaGenerator.forBlock['math_constrain'] = function(block) { +luaGenerator.forBlock['math_constrain'] = function(block, generator) { // Constrain a number between two limits. - const argument0 = luaGenerator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; const argument1 = - luaGenerator.valueToCode(block, 'LOW', Order.NONE) || '-math.huge'; + generator.valueToCode(block, 'LOW', Order.NONE) || '-math.huge'; const argument2 = - luaGenerator.valueToCode(block, 'HIGH', Order.NONE) || 'math.huge'; + generator.valueToCode(block, 'HIGH', Order.NONE) || 'math.huge'; const code = 'math.min(math.max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Order.HIGH]; }; -luaGenerator.forBlock['math_random_int'] = function(block) { +luaGenerator.forBlock['math_random_int'] = function(block, generator) { // Random integer between [X] and [Y]. - const argument0 = luaGenerator.valueToCode(block, 'FROM', Order.NONE) || '0'; - const argument1 = luaGenerator.valueToCode(block, 'TO', Order.NONE) || '0'; + const argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; const code = 'math.random(' + argument0 + ', ' + argument1 + ')'; return [code, Order.HIGH]; }; -luaGenerator.forBlock['math_random_float'] = function(block) { +luaGenerator.forBlock['math_random_float'] = function(block, generator) { // Random fraction between 0 and 1. return ['math.random()', Order.HIGH]; }; -luaGenerator.forBlock['math_atan2'] = function(block) { +luaGenerator.forBlock['math_atan2'] = function(block, generator) { // Arctangent of point (X, Y) in degrees from -180 to 180. - const argument0 = luaGenerator.valueToCode(block, 'X', Order.NONE) || '0'; - const argument1 = luaGenerator.valueToCode(block, 'Y', Order.NONE) || '0'; + const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; return [ 'math.deg(math.atan2(' + argument1 + ', ' + argument0 + '))', Order.HIGH ]; diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js index 93563d857..e73f14413 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.js @@ -15,49 +15,49 @@ import {NameType} from '../../core/names.js'; import {luaGenerator, Order} from '../lua.js'; -luaGenerator.forBlock['procedures_defreturn'] = function(block) { +luaGenerator.forBlock['procedures_defreturn'] = function(block, generator) { // Define a procedure with a return value. const funcName = - luaGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('NAME'), NameType.PROCEDURE); let xfix1 = ''; - if (luaGenerator.STATEMENT_PREFIX) { - xfix1 += luaGenerator.injectId(luaGenerator.STATEMENT_PREFIX, block); + if (generator.STATEMENT_PREFIX) { + xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block); } - if (luaGenerator.STATEMENT_SUFFIX) { - xfix1 += luaGenerator.injectId(luaGenerator.STATEMENT_SUFFIX, block); + if (generator.STATEMENT_SUFFIX) { + xfix1 += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (xfix1) { - xfix1 = luaGenerator.prefixLines(xfix1, luaGenerator.INDENT); + xfix1 = generator.prefixLines(xfix1, generator.INDENT); } let loopTrap = ''; - if (luaGenerator.INFINITE_LOOP_TRAP) { - loopTrap = luaGenerator.prefixLines( - luaGenerator.injectId( - luaGenerator.INFINITE_LOOP_TRAP, block), luaGenerator.INDENT); + if (generator.INFINITE_LOOP_TRAP) { + loopTrap = generator.prefixLines( + generator.injectId( + generator.INFINITE_LOOP_TRAP, block), generator.INDENT); } - let branch = luaGenerator.statementToCode(block, 'STACK'); - let returnValue = luaGenerator.valueToCode(block, 'RETURN', Order.NONE) || ''; + let branch = generator.statementToCode(block, 'STACK'); + let returnValue = generator.valueToCode(block, 'RETURN', Order.NONE) || ''; let xfix2 = ''; if (branch && returnValue) { // After executing the function body, revisit this block for the return. xfix2 = xfix1; } if (returnValue) { - returnValue = luaGenerator.INDENT + 'return ' + returnValue + '\n'; + returnValue = generator.INDENT + 'return ' + returnValue + '\n'; } else if (!branch) { branch = ''; } const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = luaGenerator.nameDB_.getName(variables[i], NameType.VARIABLE); + args[i] = generator.nameDB_.getName(variables[i], NameType.VARIABLE); } let code = 'function ' + funcName + '(' + args.join(', ') + ')\n' + xfix1 + loopTrap + branch + xfix2 + returnValue + 'end\n'; - code = luaGenerator.scrub_(block, code); + code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - luaGenerator.definitions_['%' + funcName] = code; + generator.definitions_['%' + funcName] = code; return null; }; @@ -66,46 +66,46 @@ luaGenerator.forBlock['procedures_defreturn'] = function(block) { luaGenerator.forBlock['procedures_defnoreturn'] = luaGenerator.forBlock['procedures_defreturn']; -luaGenerator.forBlock['procedures_callreturn'] = function(block) { +luaGenerator.forBlock['procedures_callreturn'] = function(block, generator) { // Call a procedure with a return value. const funcName = - luaGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('NAME'), NameType.PROCEDURE); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = luaGenerator.valueToCode(block, 'ARG' + i, Order.NONE) || 'nil'; + args[i] = generator.valueToCode(block, 'ARG' + i, Order.NONE) || 'nil'; } const code = funcName + '(' + args.join(', ') + ')'; return [code, Order.HIGH]; }; -luaGenerator.forBlock['procedures_callnoreturn'] = function(block) { +luaGenerator.forBlock['procedures_callnoreturn'] = function(block, generator) { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = luaGenerator.forBlock['procedures_callreturn'](block); + const tuple = generator.forBlock['procedures_callreturn'](block, generator); return tuple[0] + '\n'; }; -luaGenerator.forBlock['procedures_ifreturn'] = function(block) { +luaGenerator.forBlock['procedures_ifreturn'] = function(block, generator) { // Conditionally return value from a procedure. const condition = - luaGenerator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; let code = 'if ' + condition + ' then\n'; - if (luaGenerator.STATEMENT_SUFFIX) { + if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. code += - luaGenerator.prefixLines( - luaGenerator.injectId(luaGenerator.STATEMENT_SUFFIX, block), - luaGenerator.INDENT); + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT); } if (block.hasReturnValue_) { - const value = luaGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'nil'; - code += luaGenerator.INDENT + 'return ' + value + '\n'; + const value = generator.valueToCode(block, 'VALUE', Order.NONE) || 'nil'; + code += generator.INDENT + 'return ' + value + '\n'; } else { - code += luaGenerator.INDENT + 'return\n'; + code += generator.INDENT + 'return\n'; } code += 'end\n'; return code; diff --git a/generators/lua/text.js b/generators/lua/text.js index 0c25a69c3..dc29b800e 100644 --- a/generators/lua/text.js +++ b/generators/lua/text.js @@ -15,76 +15,76 @@ import {NameType} from '../../core/names.js'; import {luaGenerator, Order} from '../lua.js'; -luaGenerator.forBlock['text'] = function(block) { +luaGenerator.forBlock['text'] = function(block, generator) { // Text value. - const code = luaGenerator.quote_(block.getFieldValue('TEXT')); + const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; }; -luaGenerator.forBlock['text_multiline'] = function(block) { +luaGenerator.forBlock['text_multiline'] = function(block, generator) { // Text value. - const code = luaGenerator.multiline_quote_(block.getFieldValue('TEXT')); + const code = generator.multiline_quote_(block.getFieldValue('TEXT')); const order = code.indexOf('..') !== -1 ? Order.CONCATENATION : Order.ATOMIC; return [code, order]; }; -luaGenerator.forBlock['text_join'] = function(block) { +luaGenerator.forBlock['text_join'] = function(block, generator) { // Create a string made up of any number of elements of any type. if (block.itemCount_ === 0) { return ["''", Order.ATOMIC]; } else if (block.itemCount_ === 1) { - const element = luaGenerator.valueToCode(block, 'ADD0', Order.NONE) || "''"; + const element = generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; const code = 'tostring(' + element + ')'; return [code, Order.HIGH]; } else if (block.itemCount_ === 2) { const element0 = - luaGenerator.valueToCode(block, 'ADD0', Order.CONCATENATION) || "''"; + generator.valueToCode(block, 'ADD0', Order.CONCATENATION) || "''"; const element1 = - luaGenerator.valueToCode(block, 'ADD1', Order.CONCATENATION) || "''"; + generator.valueToCode(block, 'ADD1', Order.CONCATENATION) || "''"; const code = element0 + ' .. ' + element1; return [code, Order.CONCATENATION]; } else { const elements = []; for (let i = 0; i < block.itemCount_; i++) { elements[i] = - luaGenerator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; + generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } const code = 'table.concat({' + elements.join(', ') + '})'; return [code, Order.HIGH]; } }; -luaGenerator.forBlock['text_append'] = function(block) { +luaGenerator.forBlock['text_append'] = function(block, generator) { // Append to a variable in place. const varName = - luaGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); const value = - luaGenerator.valueToCode(block, 'TEXT', Order.CONCATENATION) || "''"; + generator.valueToCode(block, 'TEXT', Order.CONCATENATION) || "''"; return varName + ' = ' + varName + ' .. ' + value + '\n'; }; -luaGenerator.forBlock['text_length'] = function(block) { +luaGenerator.forBlock['text_length'] = function(block, generator) { // String or array length. - const text = luaGenerator.valueToCode(block, 'VALUE', Order.UNARY) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.UNARY) || "''"; return ['#' + text, Order.UNARY]; }; -luaGenerator.forBlock['text_isEmpty'] = function(block) { +luaGenerator.forBlock['text_isEmpty'] = function(block, generator) { // Is the string null or array empty? - const text = luaGenerator.valueToCode(block, 'VALUE', Order.UNARY) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.UNARY) || "''"; return ['#' + text + ' == 0', Order.RELATIONAL]; }; -luaGenerator.forBlock['text_indexOf'] = function(block) { +luaGenerator.forBlock['text_indexOf'] = function(block, generator) { // Search the text for a substring. - const substring = luaGenerator.valueToCode(block, 'FIND', Order.NONE) || "''"; - const text = luaGenerator.valueToCode(block, 'VALUE', Order.NONE) || "''"; + const substring = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; let functionName; if (block.getFieldValue('END') === 'FIRST') { - functionName = luaGenerator.provideFunction_('firstIndexOf', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(str, substr) + functionName = generator.provideFunction_('firstIndexOf', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str, substr) local i = string.find(str, substr, 1, true) if i == nil then return 0 @@ -93,8 +93,8 @@ function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(str, substr) end `); } else { - functionName = luaGenerator.provideFunction_('lastIndexOf', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(str, substr) + functionName = generator.provideFunction_('lastIndexOf', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str, substr) local i = string.find(string.reverse(str), string.reverse(substr), 1, true) if i then return #str + 2 - i - #substr @@ -107,17 +107,17 @@ end return [code, Order.HIGH]; }; -luaGenerator.forBlock['text_charAt'] = function(block) { +luaGenerator.forBlock['text_charAt'] = function(block, generator) { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. const where = block.getFieldValue('WHERE') || 'FROM_START'; const atOrder = (where === 'FROM_END') ? Order.UNARY : Order.NONE; - const at = luaGenerator.valueToCode(block, 'AT', atOrder) || '1'; - const text = luaGenerator.valueToCode(block, 'VALUE', Order.NONE) || "''"; + const at = generator.valueToCode(block, 'AT', atOrder) || '1'; + const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; let code; if (where === 'RANDOM') { - const functionName = luaGenerator.provideFunction_('text_random_letter', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(str) + const functionName = generator.provideFunction_('text_random_letter', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str) local index = math.random(string.len(str)) return string.sub(str, index, index) end @@ -142,8 +142,8 @@ end code = 'string.sub(' + text + ', ' + start + ', ' + start + ')'; } else { // use function to avoid reevaluation - const functionName = luaGenerator.provideFunction_('text_char_at', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(str, index) + const functionName = generator.provideFunction_('text_char_at', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str, index) return string.sub(str, index, index) end `); @@ -153,14 +153,14 @@ end return [code, Order.HIGH]; }; -luaGenerator.forBlock['text_getSubstring'] = function(block) { +luaGenerator.forBlock['text_getSubstring'] = function(block, generator) { // Get substring. - const text = luaGenerator.valueToCode(block, 'STRING', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'STRING', Order.NONE) || "''"; // Get start index. const where1 = block.getFieldValue('WHERE1'); const at1Order = (where1 === 'FROM_END') ? Order.UNARY : Order.NONE; - const at1 = luaGenerator.valueToCode(block, 'AT1', at1Order) || '1'; + const at1 = generator.valueToCode(block, 'AT1', at1Order) || '1'; let start; if (where1 === 'FIRST') { start = 1; @@ -175,7 +175,7 @@ luaGenerator.forBlock['text_getSubstring'] = function(block) { // Get end index. const where2 = block.getFieldValue('WHERE2'); const at2Order = (where2 === 'FROM_END') ? Order.UNARY : Order.NONE; - const at2 = luaGenerator.valueToCode(block, 'AT2', at2Order) || '1'; + const at2 = generator.valueToCode(block, 'AT2', at2Order) || '1'; let end; if (where2 === 'LAST') { end = -1; @@ -190,10 +190,10 @@ luaGenerator.forBlock['text_getSubstring'] = function(block) { return [code, Order.HIGH]; }; -luaGenerator.forBlock['text_changeCase'] = function(block) { +luaGenerator.forBlock['text_changeCase'] = function(block, generator) { // Change capitalization. const operator = block.getFieldValue('CASE'); - const text = luaGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; let functionName; if (operator === 'UPPERCASE') { functionName = 'string.upper'; @@ -203,8 +203,8 @@ luaGenerator.forBlock['text_changeCase'] = function(block) { // There are shorter versions at // http://lua-users.org/wiki/SciteTitleCase // that do not preserve whitespace. - functionName = luaGenerator.provideFunction_('text_titlecase', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(str) + functionName = generator.provideFunction_('text_titlecase', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str) local buf = {} local inWord = false for i = 1, #str do @@ -227,34 +227,34 @@ end return [code, Order.HIGH]; }; -luaGenerator.forBlock['text_trim'] = function(block) { +luaGenerator.forBlock['text_trim'] = function(block, generator) { // Trim spaces. const OPERATORS = {LEFT: '^%s*(,-)', RIGHT: '(.-)%s*$', BOTH: '^%s*(.-)%s*$'}; const operator = OPERATORS[block.getFieldValue('MODE')]; - const text = luaGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const code = 'string.gsub(' + text + ', "' + operator + '", "%1")'; return [code, Order.HIGH]; }; -luaGenerator.forBlock['text_print'] = function(block) { +luaGenerator.forBlock['text_print'] = function(block, generator) { // Print statement. - const msg = luaGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'print(' + msg + ')\n'; }; -luaGenerator.forBlock['text_prompt_ext'] = function(block) { +luaGenerator.forBlock['text_prompt_ext'] = function(block, generator) { // Prompt function. let msg; if (block.getField('TEXT')) { // Internal message. - msg = luaGenerator.quote_(block.getFieldValue('TEXT')); + msg = generator.quote_(block.getFieldValue('TEXT')); } else { // External message. - msg = luaGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; } - const functionName = luaGenerator.provideFunction_('text_prompt', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(msg) + const functionName = generator.provideFunction_('text_prompt', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(msg) io.write(msg) io.flush() return io.read() @@ -271,11 +271,11 @@ end luaGenerator.forBlock['text_prompt'] = luaGenerator.forBlock['text_prompt_ext']; -luaGenerator.forBlock['text_count'] = function(block) { - const text = luaGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; - const sub = luaGenerator.valueToCode(block, 'SUB', Order.NONE) || "''"; - const functionName = luaGenerator.provideFunction_('text_count', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle) +luaGenerator.forBlock['text_count'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; + const functionName = generator.provideFunction_('text_count', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle) if #needle == 0 then return #haystack + 1 end @@ -296,12 +296,12 @@ end return [code, Order.HIGH]; }; -luaGenerator.forBlock['text_replace'] = function(block) { - const text = luaGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; - const from = luaGenerator.valueToCode(block, 'FROM', Order.NONE) || "''"; - const to = luaGenerator.valueToCode(block, 'TO', Order.NONE) || "''"; - const functionName = luaGenerator.provideFunction_('text_replace', ` -function ${luaGenerator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle, replacement) +luaGenerator.forBlock['text_replace'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; + const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; + const functionName = generator.provideFunction_('text_replace', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle, replacement) local buf = {} local i = 1 while i <= #haystack do @@ -322,8 +322,8 @@ end return [code, Order.HIGH]; }; -luaGenerator.forBlock['text_reverse'] = function(block) { - const text = luaGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; +luaGenerator.forBlock['text_reverse'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const code = 'string.reverse(' + text + ')'; return [code, Order.HIGH]; }; diff --git a/generators/lua/variables.js b/generators/lua/variables.js index c125472e2..e90179101 100644 --- a/generators/lua/variables.js +++ b/generators/lua/variables.js @@ -15,19 +15,19 @@ import {NameType} from '../../core/names.js'; import {luaGenerator, Order} from '../lua.js'; -luaGenerator.forBlock['variables_get'] = function(block) { +luaGenerator.forBlock['variables_get'] = function(block, generator) { // Variable getter. const code = - luaGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return [code, Order.ATOMIC]; }; -luaGenerator.forBlock['variables_set'] = function(block) { +luaGenerator.forBlock['variables_set'] = function(block, generator) { // Variable setter. - const argument0 = luaGenerator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; const varName = - luaGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' = ' + argument0 + '\n'; }; diff --git a/generators/php/colour.js b/generators/php/colour.js index bd8cf4cb3..58f5dd645 100644 --- a/generators/php/colour.js +++ b/generators/php/colour.js @@ -14,16 +14,16 @@ goog.declareModuleId('Blockly.PHP.colour'); import {phpGenerator, Order} from '../php.js'; -phpGenerator.forBlock['colour_picker'] = function(block) { +phpGenerator.forBlock['colour_picker'] = function(block, generator) { // Colour picker. - const code = phpGenerator.quote_(block.getFieldValue('COLOUR')); + const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; }; -phpGenerator.forBlock['colour_random'] = function(block) { +phpGenerator.forBlock['colour_random'] = function(block, generator) { // Generate a random colour. - const functionName = phpGenerator.provideFunction_('colour_random', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}() { + const functionName = generator.provideFunction_('colour_random', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}() { return '#' . str_pad(dechex(mt_rand(0, 0xFFFFFF)), 6, '0', STR_PAD_LEFT); } `); @@ -31,13 +31,13 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}() { return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['colour_rgb'] = function(block) { +phpGenerator.forBlock['colour_rgb'] = function(block, generator) { // Compose a colour from RGB components expressed as percentages. - const red = phpGenerator.valueToCode(block, 'RED', Order.NONE) || 0; - const green = phpGenerator.valueToCode(block, 'GREEN', Order.NONE) || 0; - const blue = phpGenerator.valueToCode(block, 'BLUE', Order.NONE) || 0; - const functionName = phpGenerator.provideFunction_('colour_rgb', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($r, $g, $b) { + const red = generator.valueToCode(block, 'RED', Order.NONE) || 0; + const green = generator.valueToCode(block, 'GREEN', Order.NONE) || 0; + const blue = generator.valueToCode(block, 'BLUE', Order.NONE) || 0; + const functionName = generator.provideFunction_('colour_rgb', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($r, $g, $b) { $r = round(max(min($r, 100), 0) * 2.55); $g = round(max(min($g, 100), 0) * 2.55); $b = round(max(min($b, 100), 0) * 2.55); @@ -52,15 +52,15 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($r, $g, $b) { return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['colour_blend'] = function(block) { +phpGenerator.forBlock['colour_blend'] = function(block, generator) { // Blend two colours together. const c1 = - phpGenerator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; + generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; const c2 = - phpGenerator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; - const ratio = phpGenerator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; - const functionName = phpGenerator.provideFunction_('colour_blend', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($c1, $c2, $ratio) { + generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; + const ratio = generator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; + const functionName = generator.provideFunction_('colour_blend', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($c1, $c2, $ratio) { $ratio = max(min($ratio, 1), 0); $r1 = hexdec(substr($c1, 1, 2)); $g1 = hexdec(substr($c1, 3, 2)); diff --git a/generators/php/lists.js b/generators/php/lists.js index f1deb5d1f..de7172ad0 100644 --- a/generators/php/lists.js +++ b/generators/php/lists.js @@ -20,31 +20,31 @@ */ import * as goog from '../../closure/goog/goog.js'; -goog.declareModuleId('Blockly.phpGenerator.lists'); +goog.declareModuleId('Blockly.generator.lists'); import * as stringUtils from '../../core/utils/string.js'; import {NameType} from '../../core/names.js'; import {phpGenerator, Order} from '../php.js'; -phpGenerator.forBlock['lists_create_empty'] = function(block) { +phpGenerator.forBlock['lists_create_empty'] = function(block, generator) { // Create an empty list. return ['array()', Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['lists_create_with'] = function(block) { +phpGenerator.forBlock['lists_create_with'] = function(block, generator) { // Create a list with any number of elements of any type. let code = new Array(block.itemCount_); for (let i = 0; i < block.itemCount_; i++) { - code[i] = phpGenerator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; + code[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; } code = 'array(' + code.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['lists_repeat'] = function(block) { +phpGenerator.forBlock['lists_repeat'] = function(block, generator) { // Create a list with one element repeated. - const functionName = phpGenerator.provideFunction_('lists_repeat', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { + const functionName = generator.provideFunction_('lists_repeat', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { $array = array(); for ($index = 0; $index < $count; $index++) { $array[] = $value; @@ -52,16 +52,16 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { return $array; } `); - const element = phpGenerator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; - const repeatCount = phpGenerator.valueToCode(block, 'NUM', Order.NONE) || '0'; + const element = generator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; + const repeatCount = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; const code = functionName + '(' + element + ', ' + repeatCount + ')'; return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['lists_length'] = function(block) { +phpGenerator.forBlock['lists_length'] = function(block, generator) { // String or array length. - const functionName = phpGenerator.provideFunction_('length', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($value) { + const functionName = generator.provideFunction_('length', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { if (is_string($value)) { return strlen($value); } else { @@ -69,23 +69,23 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($value) { } } `); - const list = phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || "''"; + const list = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return [functionName + '(' + list + ')', Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['lists_isEmpty'] = function(block) { +phpGenerator.forBlock['lists_isEmpty'] = function(block, generator) { // Is the string null or array empty? const argument0 = - phpGenerator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || 'array()'; return ['empty(' + argument0 + ')', Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['lists_indexOf'] = function(block) { +phpGenerator.forBlock['lists_indexOf'] = function(block, generator) { // Find an item in the list. - const argument0 = phpGenerator.valueToCode(block, 'FIND', Order.NONE) || "''"; + const argument0 = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const argument1 = - phpGenerator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; let errorIndex = ' -1'; let indexAdjustment = ''; if (block.workspace.options.oneBasedIndex) { @@ -95,8 +95,8 @@ phpGenerator.forBlock['lists_indexOf'] = function(block) { let functionName; if (block.getFieldValue('END') === 'FIRST') { // indexOf - functionName = phpGenerator.provideFunction_('indexOf', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { + functionName = generator.provideFunction_('indexOf', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { for ($index = 0; $index < count($haystack); $index++) { if ($haystack[$index] == $needle) return $index${indexAdjustment}; } @@ -105,8 +105,8 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { `); } else { // lastIndexOf - functionName = phpGenerator.provideFunction_('lastIndexOf', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { + functionName = generator.provideFunction_('lastIndexOf', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { $last = ${errorIndex}; for ($index = 0; $index < count($haystack); $index++) { if ($haystack[$index] == $needle) $last = $index${indexAdjustment}; @@ -120,7 +120,7 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['lists_getIndex'] = function(block) { +phpGenerator.forBlock['lists_getIndex'] = function(block, generator) { // Get element at index. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; @@ -128,52 +128,52 @@ phpGenerator.forBlock['lists_getIndex'] = function(block) { case 'FIRST': if (mode === 'GET') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || 'array()'; const code = list + '[0]'; return [code, Order.MEMBER]; } else if (mode === 'GET_REMOVE') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; const code = 'array_shift(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; return 'array_shift(' + list + ');\n'; } break; case 'LAST': if (mode === 'GET') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; const code = 'end(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'GET_REMOVE') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; const code = 'array_pop(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; return 'array_pop(' + list + ');\n'; } break; case 'FROM_START': { - const at = phpGenerator.getAdjusted(block, 'AT'); + const at = generator.getAdjusted(block, 'AT'); if (mode === 'GET') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || 'array()'; const code = list + '[' + at + ']'; return [code, Order.MEMBER]; } else if (mode === 'GET_REMOVE') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; const code = 'array_splice(' + list + ', ' + at + ', 1)[0]'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; return 'array_splice(' + list + ', ' + at + ', 1);\n'; } break; @@ -181,15 +181,15 @@ phpGenerator.forBlock['lists_getIndex'] = function(block) { case 'FROM_END': if (mode === 'GET') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; - const at = phpGenerator.getAdjusted(block, 'AT', 1, true); + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + const at = generator.getAdjusted(block, 'AT', 1, true); const code = 'array_slice(' + list + ', ' + at + ', 1)[0]'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'GET_REMOVE' || mode === 'REMOVE') { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; const at = - phpGenerator.getAdjusted(block, 'AT', 1, false, Order.SUBTRACTION); + generator.getAdjusted(block, 'AT', 1, false, Order.SUBTRACTION); const code = 'array_splice(' + list + ', count(' + list + ') - ' + at + ', 1)[0]'; if (mode === 'GET_REMOVE') { @@ -201,11 +201,11 @@ phpGenerator.forBlock['lists_getIndex'] = function(block) { break; case 'RANDOM': { const list = - phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; if (mode === 'GET') { const functionName = - phpGenerator.provideFunction_('lists_get_random_item', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($list) { + generator.provideFunction_('lists_get_random_item', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { return $list[rand(0,count($list)-1)]; } `); @@ -213,8 +213,8 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($list) { return [code, Order.FUNCTION_CALL]; } else if (mode === 'GET_REMOVE') { const functionName = - phpGenerator.provideFunction_('lists_get_remove_random_item', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { + generator.provideFunction_('lists_get_remove_random_item', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { $x = rand(0,count($list)-1); unset($list[$x]); return array_values($list); @@ -224,8 +224,8 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { const functionName = - phpGenerator.provideFunction_('lists_remove_random_item', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { + generator.provideFunction_('lists_remove_random_item', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { unset($list[rand(0,count($list)-1)]); } `); @@ -237,13 +237,13 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { throw Error('Unhandled combination (lists_getIndex).'); }; -phpGenerator.forBlock['lists_setIndex'] = function(block) { +phpGenerator.forBlock['lists_setIndex'] = function(block, generator) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; const value = - phpGenerator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; + generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. let cachedList; @@ -252,7 +252,7 @@ phpGenerator.forBlock['lists_setIndex'] = function(block) { return ''; } const listVar = - phpGenerator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); const code = listVar + ' = &' + cachedList + ';\n'; cachedList = listVar; return code; @@ -261,21 +261,21 @@ phpGenerator.forBlock['lists_setIndex'] = function(block) { case 'FIRST': if (mode === 'SET') { const list = - phpGenerator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; return list + '[0] = ' + value + ';\n'; } else if (mode === 'INSERT') { const list = - phpGenerator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; return 'array_unshift(' + list + ', ' + value + ');\n'; } break; case 'LAST': { const list = - phpGenerator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; if (mode === 'SET') { const functionName = - phpGenerator.provideFunction_('lists_set_last_item', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $value) { + generator.provideFunction_('lists_set_last_item', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $value) { $list[count($list) - 1] = $value; } `); @@ -286,34 +286,34 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $value) { break; } case 'FROM_START': { - const at = phpGenerator.getAdjusted(block, 'AT'); + const at = generator.getAdjusted(block, 'AT'); if (mode === 'SET') { const list = - phpGenerator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; return list + '[' + at + '] = ' + value + ';\n'; } else if (mode === 'INSERT') { const list = - phpGenerator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; return 'array_splice(' + list + ', ' + at + ', 0, ' + value + ');\n'; } break; } case 'FROM_END': { const list = - phpGenerator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; - const at = phpGenerator.getAdjusted(block, 'AT', 1); + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + const at = generator.getAdjusted(block, 'AT', 1); if (mode === 'SET') { const functionName = - phpGenerator.provideFunction_('lists_set_from_end', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { + generator.provideFunction_('lists_set_from_end', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { $list[count($list) - $at] = $value; } `); return functionName + '(' + list + ', ' + at + ', ' + value + ');\n'; } else if (mode === 'INSERT') { const functionName = - phpGenerator.provideFunction_('lists_insert_from_end', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { + generator.provideFunction_('lists_insert_from_end', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { return array_splice($list, count($list) - $at, 0, $value); } `); @@ -323,11 +323,11 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { } case 'RANDOM': cachedList = - phpGenerator.valueToCode(block, 'LIST', Order.REFERENCE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.REFERENCE) || 'array()'; let code = cacheList(); const list = cachedList; const xVar = - phpGenerator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); + generator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); code += xVar + ' = rand(0, count(' + list + ')-1);\n'; if (mode === 'SET') { code += list + '[' + xVar + '] = ' + value + ';\n'; @@ -341,9 +341,9 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { throw Error('Unhandled combination (lists_setIndex).'); }; -phpGenerator.forBlock['lists_getSublist'] = function(block) { +phpGenerator.forBlock['lists_getSublist'] = function(block, generator) { // Get sublist. - const list = phpGenerator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + const list = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); let code; @@ -357,11 +357,11 @@ phpGenerator.forBlock['lists_getSublist'] = function(block) { let at1; switch (where1) { case 'FROM_START': - at1 = phpGenerator.getAdjusted(block, 'AT1'); + at1 = generator.getAdjusted(block, 'AT1'); break; case 'FROM_END': at1 = - phpGenerator.getAdjusted(block, 'AT1', 1, false, Order.SUBTRACTION); + generator.getAdjusted(block, 'AT1', 1, false, Order.SUBTRACTION); at1 = 'count(' + list + ') - ' + at1; break; case 'FIRST': @@ -375,7 +375,7 @@ phpGenerator.forBlock['lists_getSublist'] = function(block) { switch (where2) { case 'FROM_START': at2 = - phpGenerator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); + generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); length = at2 + ' - '; if (stringUtils.isNumber(String(at1)) || String(at1).match(/^\(.+\)$/)) { @@ -387,7 +387,7 @@ phpGenerator.forBlock['lists_getSublist'] = function(block) { break; case 'FROM_END': at2 = - phpGenerator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); + generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); length = 'count(' + list + ') - ' + at2 + ' - '; if (stringUtils.isNumber(String(at1)) || String(at1).match(/^\(.+\)$/)) { @@ -410,11 +410,11 @@ phpGenerator.forBlock['lists_getSublist'] = function(block) { } code = 'array_slice(' + list + ', ' + at1 + ', ' + length + ')'; } else { - const at1 = phpGenerator.getAdjusted(block, 'AT1'); - const at2 = phpGenerator.getAdjusted(block, 'AT2'); + const at1 = generator.getAdjusted(block, 'AT1'); + const at2 = generator.getAdjusted(block, 'AT2'); const functionName = - phpGenerator.provideFunction_('lists_get_sublist', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($list, $where1, $at1, $where2, $at2) { + generator.provideFunction_('lists_get_sublist', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $where1, $at1, $where2, $at2) { if ($where1 == 'FROM_END') { $at1 = count($list) - 1 - $at1; } else if ($where1 == 'FIRST') { @@ -441,14 +441,14 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($list, $where1, $at1, $where return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['lists_sort'] = function(block) { +phpGenerator.forBlock['lists_sort'] = function(block, generator) { // Block for sorting a list. const listCode = - phpGenerator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; const direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1; const type = block.getFieldValue('TYPE'); - const functionName = phpGenerator.provideFunction_('lists_sort', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($list, $type, $direction) { + const functionName = generator.provideFunction_('lists_sort', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $type, $direction) { $sortCmpFuncs = array( 'NUMERIC' => 'strnatcasecmp', 'TEXT' => 'strcmp', @@ -468,11 +468,11 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($list, $type, $direction) { return [sortCode, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['lists_split'] = function(block) { +phpGenerator.forBlock['lists_split'] = function(block, generator) { // Block for splitting text into a list, or joining a list into text. - let value_input = phpGenerator.valueToCode(block, 'INPUT', Order.NONE); + let value_input = generator.valueToCode(block, 'INPUT', Order.NONE); const value_delim = - phpGenerator.valueToCode(block, 'DELIM', Order.NONE) || "''"; + generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; const mode = block.getFieldValue('MODE'); let functionName; if (mode === 'SPLIT') { @@ -492,9 +492,9 @@ phpGenerator.forBlock['lists_split'] = function(block) { return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['lists_reverse'] = function(block) { +phpGenerator.forBlock['lists_reverse'] = function(block, generator) { // Block for reversing a list. - const list = phpGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; const code = 'array_reverse(' + list + ')'; return [code, Order.FUNCTION_CALL]; }; diff --git a/generators/php/logic.js b/generators/php/logic.js index 4ecdfe6c3..b2c98b01c 100644 --- a/generators/php/logic.js +++ b/generators/php/logic.js @@ -14,23 +14,23 @@ goog.declareModuleId('Blockly.PHP.logic'); import {phpGenerator, Order} from '../php.js'; -phpGenerator.forBlock['controls_if'] = function(block) { +phpGenerator.forBlock['controls_if'] = function(block, generator) { // If/elseif/else condition. let n = 0; let code = '', branchCode, conditionCode; - if (phpGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - code += phpGenerator.injectId(phpGenerator.STATEMENT_PREFIX, block); + code += generator.injectId(generator.STATEMENT_PREFIX, block); } do { conditionCode = - phpGenerator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; - branchCode = phpGenerator.statementToCode(block, 'DO' + n); - if (phpGenerator.STATEMENT_SUFFIX) { + generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; + branchCode = generator.statementToCode(block, 'DO' + n); + if (generator.STATEMENT_SUFFIX) { branchCode = - phpGenerator.prefixLines( - phpGenerator.injectId(phpGenerator.STATEMENT_SUFFIX, block), - phpGenerator.INDENT) + + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT) + branchCode; } code += (n > 0 ? ' else ' : '') + 'if (' + conditionCode + ') {\n' + @@ -38,13 +38,13 @@ phpGenerator.forBlock['controls_if'] = function(block) { n++; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE') || phpGenerator.STATEMENT_SUFFIX) { - branchCode = phpGenerator.statementToCode(block, 'ELSE'); - if (phpGenerator.STATEMENT_SUFFIX) { + if (block.getInput('ELSE') || generator.STATEMENT_SUFFIX) { + branchCode = generator.statementToCode(block, 'ELSE'); + if (generator.STATEMENT_SUFFIX) { branchCode = - phpGenerator.prefixLines( - phpGenerator.injectId(phpGenerator.STATEMENT_SUFFIX, block), - phpGenerator.INDENT) + + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT) + branchCode; } code += ' else {\n' + branchCode + '}'; @@ -54,26 +54,26 @@ phpGenerator.forBlock['controls_if'] = function(block) { phpGenerator.forBlock['controls_ifelse'] = phpGenerator.forBlock['controls_if']; -phpGenerator.forBlock['logic_compare'] = function(block) { +phpGenerator.forBlock['logic_compare'] = function(block, generator) { // Comparison operator. const OPERATORS = {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; const operator = OPERATORS[block.getFieldValue('OP')]; const order = (operator === '==' || operator === '!=') ? Order.EQUALITY : Order.RELATIONAL; - const argument0 = phpGenerator.valueToCode(block, 'A', order) || '0'; - const argument1 = phpGenerator.valueToCode(block, 'B', order) || '0'; + const argument0 = generator.valueToCode(block, 'A', order) || '0'; + const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; -phpGenerator.forBlock['logic_operation'] = function(block) { +phpGenerator.forBlock['logic_operation'] = function(block, generator) { // Operations 'and', 'or'. const operator = (block.getFieldValue('OP') === 'AND') ? '&&' : '||'; const order = (operator === '&&') ? Order.LOGICAL_AND : Order.LOGICAL_OR; - let argument0 = phpGenerator.valueToCode(block, 'A', order); - let argument1 = phpGenerator.valueToCode(block, 'B', order); + let argument0 = generator.valueToCode(block, 'A', order); + let argument1 = generator.valueToCode(block, 'B', order); if (!argument0 && !argument1) { // If there are no arguments, then the return value is false. argument0 = 'false'; @@ -92,33 +92,33 @@ phpGenerator.forBlock['logic_operation'] = function(block) { return [code, order]; }; -phpGenerator.forBlock['logic_negate'] = function(block) { +phpGenerator.forBlock['logic_negate'] = function(block, generator) { // Negation. const order = Order.LOGICAL_NOT; - const argument0 = phpGenerator.valueToCode(block, 'BOOL', order) || 'true'; + const argument0 = generator.valueToCode(block, 'BOOL', order) || 'true'; const code = '!' + argument0; return [code, order]; }; -phpGenerator.forBlock['logic_boolean'] = function(block) { +phpGenerator.forBlock['logic_boolean'] = function(block, generator) { // Boolean values true and false. const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'true' : 'false'; return [code, Order.ATOMIC]; }; -phpGenerator.forBlock['logic_null'] = function(block) { +phpGenerator.forBlock['logic_null'] = function(block, generator) { // Null data type. return ['null', Order.ATOMIC]; }; -phpGenerator.forBlock['logic_ternary'] = function(block) { +phpGenerator.forBlock['logic_ternary'] = function(block, generator) { // Ternary operator. const value_if = - phpGenerator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; + generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; const value_then = - phpGenerator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; + generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; const value_else = - phpGenerator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'null'; + generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'null'; const code = value_if + ' ? ' + value_then + ' : ' + value_else; return [code, Order.CONDITIONAL]; }; diff --git a/generators/php/loops.js b/generators/php/loops.js index 4448e7989..ad4577ec3 100644 --- a/generators/php/loops.js +++ b/generators/php/loops.js @@ -16,7 +16,7 @@ import {NameType} from '../../core/names.js'; import {phpGenerator, Order} from '../php.js'; -phpGenerator.forBlock['controls_repeat_ext'] = function(block) { +phpGenerator.forBlock['controls_repeat_ext'] = function(block, generator) { // Repeat n times. let repeats; if (block.getField('TIMES')) { @@ -24,17 +24,17 @@ phpGenerator.forBlock['controls_repeat_ext'] = function(block) { repeats = String(Number(block.getFieldValue('TIMES'))); } else { // External number. - repeats = phpGenerator.valueToCode(block, 'TIMES', Order.ASSIGNMENT) || '0'; + repeats = generator.valueToCode(block, 'TIMES', Order.ASSIGNMENT) || '0'; } - let branch = phpGenerator.statementToCode(block, 'DO'); - branch = phpGenerator.addLoopTrap(branch, block); + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); let code = ''; const loopVar = - phpGenerator.nameDB_.getDistinctName('count', NameType.VARIABLE); + generator.nameDB_.getDistinctName('count', NameType.VARIABLE); let endVar = repeats; if (!repeats.match(/^\w+$/) && !stringUtils.isNumber(repeats)) { endVar = - phpGenerator.nameDB_.getDistinctName('repeat_end', NameType.VARIABLE); + generator.nameDB_.getDistinctName('repeat_end', NameType.VARIABLE); code += endVar + ' = ' + repeats + ';\n'; } code += 'for (' + loopVar + ' = 0; ' + loopVar + ' < ' + endVar + '; ' + @@ -45,33 +45,33 @@ phpGenerator.forBlock['controls_repeat_ext'] = function(block) { phpGenerator.forBlock['controls_repeat'] = phpGenerator.forBlock['controls_repeat_ext']; -phpGenerator.forBlock['controls_whileUntil'] = function(block) { +phpGenerator.forBlock['controls_whileUntil'] = function(block, generator) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; let argument0 = - phpGenerator.valueToCode( + generator.valueToCode( block, 'BOOL', until ? Order.LOGICAL_NOT : Order.NONE) || 'false'; - let branch = phpGenerator.statementToCode(block, 'DO'); - branch = phpGenerator.addLoopTrap(branch, block); + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); if (until) { argument0 = '!' + argument0; } return 'while (' + argument0 + ') {\n' + branch + '}\n'; }; -phpGenerator.forBlock['controls_for'] = function(block) { +phpGenerator.forBlock['controls_for'] = function(block, generator) { // For loop. const variable0 = - phpGenerator.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE); + generator.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE); const argument0 = - phpGenerator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; + generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; const argument1 = - phpGenerator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; + generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; const increment = - phpGenerator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; - let branch = phpGenerator.statementToCode(block, 'DO'); - branch = phpGenerator.addLoopTrap(branch, block); + generator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); let code; if (stringUtils.isNumber(argument0) && stringUtils.isNumber(argument1) && stringUtils.isNumber(increment)) { @@ -92,21 +92,21 @@ phpGenerator.forBlock['controls_for'] = function(block) { let startVar = argument0; if (!argument0.match(/^\w+$/) && !stringUtils.isNumber(argument0)) { startVar = - phpGenerator.nameDB_.getDistinctName( + generator.nameDB_.getDistinctName( variable0 + '_start', NameType.VARIABLE); code += startVar + ' = ' + argument0 + ';\n'; } let endVar = argument1; if (!argument1.match(/^\w+$/) && !stringUtils.isNumber(argument1)) { endVar = - phpGenerator.nameDB_.getDistinctName( + generator.nameDB_.getDistinctName( variable0 + '_end', NameType.VARIABLE); code += endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. const incVar = - phpGenerator.nameDB_.getDistinctName( + generator.nameDB_.getDistinctName( variable0 + '_inc', NameType.VARIABLE); code += incVar + ' = '; if (stringUtils.isNumber(increment)) { @@ -115,7 +115,7 @@ phpGenerator.forBlock['controls_for'] = function(block) { code += 'abs(' + increment + ');\n'; } code += 'if (' + startVar + ' > ' + endVar + ') {\n'; - code += phpGenerator.INDENT + incVar + ' = -' + incVar + ';\n'; + code += generator.INDENT + incVar + ' = -' + incVar + ';\n'; code += '}\n'; code += 'for (' + variable0 + ' = ' + startVar + '; ' + incVar + ' >= 0 ? ' + variable0 + ' <= ' + endVar + ' : ' + variable0 + @@ -125,40 +125,40 @@ phpGenerator.forBlock['controls_for'] = function(block) { return code; }; -phpGenerator.forBlock['controls_forEach'] = function(block) { +phpGenerator.forBlock['controls_forEach'] = function(block, generator) { // For each loop. const variable0 = - phpGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); const argument0 = - phpGenerator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; - let branch = phpGenerator.statementToCode(block, 'DO'); - branch = phpGenerator.addLoopTrap(branch, block); + generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block); let code = ''; code += 'foreach (' + argument0 + ' as ' + variable0 + ') {\n' + branch + '}\n'; return code; }; -phpGenerator.forBlock['controls_flow_statements'] = function(block) { +phpGenerator.forBlock['controls_flow_statements'] = function(block, generator) { // Flow statements: continue, break. let xfix = ''; - if (phpGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - xfix += phpGenerator.injectId(phpGenerator.STATEMENT_PREFIX, block); + xfix += generator.injectId(generator.STATEMENT_PREFIX, block); } - if (phpGenerator.STATEMENT_SUFFIX) { + if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. - xfix += phpGenerator.injectId(phpGenerator.STATEMENT_SUFFIX, block); + xfix += generator.injectId(generator.STATEMENT_SUFFIX, block); } - if (phpGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { const loop = block.getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. - xfix += phpGenerator.injectId(phpGenerator.STATEMENT_PREFIX, loop); + xfix += generator.injectId(generator.STATEMENT_PREFIX, loop); } } switch (block.getFieldValue('FLOW')) { diff --git a/generators/php/math.js b/generators/php/math.js index b84571373..8fba46dcf 100644 --- a/generators/php/math.js +++ b/generators/php/math.js @@ -15,7 +15,7 @@ import {NameType} from '../../core/names.js'; import {phpGenerator, Order} from '../php.js'; -phpGenerator.forBlock['math_number'] = function(block) { +phpGenerator.forBlock['math_number'] = function(block, generator) { // Numeric value. let code = Number(block.getFieldValue('NUM')); const order = code >= 0 ? Order.ATOMIC : Order.UNARY_NEGATION; @@ -27,7 +27,7 @@ phpGenerator.forBlock['math_number'] = function(block) { return [code, order]; }; -phpGenerator.forBlock['math_arithmetic'] = function(block) { +phpGenerator.forBlock['math_arithmetic'] = function(block, generator) { // Basic arithmetic operators, and power. const OPERATORS = { 'ADD': [' + ', Order.ADDITION], @@ -39,20 +39,20 @@ phpGenerator.forBlock['math_arithmetic'] = function(block) { const tuple = OPERATORS[block.getFieldValue('OP')]; const operator = tuple[0]; const order = tuple[1]; - const argument0 = phpGenerator.valueToCode(block, 'A', order) || '0'; - const argument1 = phpGenerator.valueToCode(block, 'B', order) || '0'; + const argument0 = generator.valueToCode(block, 'A', order) || '0'; + const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + operator + argument1; return [code, order]; }; -phpGenerator.forBlock['math_single'] = function(block) { +phpGenerator.forBlock['math_single'] = function(block, generator) { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; let arg; if (operator === 'NEG') { // Negation is a special case given its different operator precedence. - arg = phpGenerator.valueToCode(block, 'NUM', Order.UNARY_NEGATION) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.UNARY_NEGATION) || '0'; if (arg[0] === '-') { // --3 is not legal in JS. arg = ' ' + arg; @@ -61,9 +61,9 @@ phpGenerator.forBlock['math_single'] = function(block) { return [code, Order.UNARY_NEGATION]; } if (operator === 'SIN' || operator === 'COS' || operator === 'TAN') { - arg = phpGenerator.valueToCode(block, 'NUM', Order.DIVISION) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.DIVISION) || '0'; } else { - arg = phpGenerator.valueToCode(block, 'NUM', Order.NONE) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; } // First, handle cases which generate values that don't need parentheses // wrapping the code. @@ -126,7 +126,7 @@ phpGenerator.forBlock['math_single'] = function(block) { return [code, Order.DIVISION]; }; -phpGenerator.forBlock['math_constant'] = function(block) { +phpGenerator.forBlock['math_constant'] = function(block, generator) { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. const CONSTANTS = { 'PI': ['M_PI', Order.ATOMIC], @@ -139,7 +139,7 @@ phpGenerator.forBlock['math_constant'] = function(block) { return CONSTANTS[block.getFieldValue('CONSTANT')]; }; -phpGenerator.forBlock['math_number_property'] = function(block) { +phpGenerator.forBlock['math_number_property'] = function(block, generator) { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. const PROPERTIES = { @@ -154,13 +154,13 @@ phpGenerator.forBlock['math_number_property'] = function(block) { const dropdownProperty = block.getFieldValue('PROPERTY'); const [prefix, suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty]; - const numberToCheck = phpGenerator.valueToCode(block, 'NUMBER_TO_CHECK', + const numberToCheck = generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || '0'; let code; if (dropdownProperty === 'PRIME') { // Prime is a special case as it is not a one-liner test. - const functionName = phpGenerator.provideFunction_('math_isPrime', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($n) { + const functionName = generator.provideFunction_('math_isPrime', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($n) { // https://en.wikipedia.org/wiki/Primality_test#Naive_methods if ($n == 2 || $n == 3) { return true; @@ -181,7 +181,7 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($n) { `); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = phpGenerator.valueToCode(block, 'DIVISOR', + const divisor = generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; if (divisor === '0') { return ['false', Order.ATOMIC]; @@ -194,12 +194,12 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($n) { return [code, outputOrder]; }; -phpGenerator.forBlock['math_change'] = function(block) { +phpGenerator.forBlock['math_change'] = function(block, generator) { // Add to a variable in place. const argument0 = - phpGenerator.valueToCode(block, 'DELTA', Order.ADDITION) || '0'; + generator.valueToCode(block, 'DELTA', Order.ADDITION) || '0'; const varName = - phpGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' += ' + argument0 + ';\n'; }; @@ -209,7 +209,7 @@ phpGenerator.forBlock['math_round'] = phpGenerator.forBlock['math_single']; // Trigonometry functions have a single operand. phpGenerator.forBlock['math_trig'] = phpGenerator.forBlock['math_single']; -phpGenerator.forBlock['math_on_list'] = function(block) { +phpGenerator.forBlock['math_on_list'] = function(block, generator) { // Math functions for lists. const func = block.getFieldValue('OP'); let list; @@ -217,41 +217,41 @@ phpGenerator.forBlock['math_on_list'] = function(block) { switch (func) { case 'SUM': list = - phpGenerator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; code = 'array_sum(' + list + ')'; break; case 'MIN': list = - phpGenerator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; code = 'min(' + list + ')'; break; case 'MAX': list = - phpGenerator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; code = 'max(' + list + ')'; break; case 'AVERAGE': { - const functionName = phpGenerator.provideFunction_('math_mean', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($myList) { + const functionName = generator.provideFunction_('math_mean', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($myList) { return array_sum($myList) / count($myList); } `); - list = phpGenerator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + list = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; code = functionName + '(' + list + ')'; break; } case 'MEDIAN': { - const functionName = phpGenerator.provideFunction_('math_median', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($arr) { + const functionName = generator.provideFunction_('math_median', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($arr) { sort($arr,SORT_NUMERIC); return (count($arr) % 2) ? $arr[floor(count($arr) / 2)] : ($arr[floor(count($arr) / 2)] + $arr[floor(count($arr) / 2) - 1]) / 2; } `); - list = phpGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } @@ -259,8 +259,8 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($arr) { // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1]. - const functionName = phpGenerator.provideFunction_('math_modes', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($values) { + const functionName = generator.provideFunction_('math_modes', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($values) { if (empty($values)) return array(); $counts = array_count_values($values); arsort($counts); // Sort counts in descending order @@ -268,14 +268,14 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($values) { return $modes; } `); - list = phpGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'STD_DEV': { const functionName = - phpGenerator.provideFunction_('math_standard_deviation', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($numbers) { + generator.provideFunction_('math_standard_deviation', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($numbers) { $n = count($numbers); if (!$n) return null; $mean = array_sum($numbers) / count($numbers); @@ -283,18 +283,18 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($numbers) { return sqrt(array_sum($devs) / (count($devs) - 1)); } `); - list = phpGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'RANDOM': { - const functionName = phpGenerator.provideFunction_('math_random_list', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($list) { + const functionName = generator.provideFunction_('math_random_list', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { $x = rand(0, count($list)-1); return $list[$x]; } `); - list = phpGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } @@ -304,33 +304,33 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($list) { return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['math_modulo'] = function(block) { +phpGenerator.forBlock['math_modulo'] = function(block, generator) { // Remainder computation. const argument0 = - phpGenerator.valueToCode(block, 'DIVIDEND', Order.MODULUS) || '0'; + generator.valueToCode(block, 'DIVIDEND', Order.MODULUS) || '0'; const argument1 = - phpGenerator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; + generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MODULUS]; }; -phpGenerator.forBlock['math_constrain'] = function(block) { +phpGenerator.forBlock['math_constrain'] = function(block, generator) { // Constrain a number between two limits. - const argument0 = phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || '0'; - const argument1 = phpGenerator.valueToCode(block, 'LOW', Order.NONE) || '0'; + const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'LOW', Order.NONE) || '0'; const argument2 = - phpGenerator.valueToCode(block, 'HIGH', Order.NONE) || 'Infinity'; + generator.valueToCode(block, 'HIGH', Order.NONE) || 'Infinity'; const code = 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['math_random_int'] = function(block) { +phpGenerator.forBlock['math_random_int'] = function(block, generator) { // Random integer between [X] and [Y]. - const argument0 = phpGenerator.valueToCode(block, 'FROM', Order.NONE) || '0'; - const argument1 = phpGenerator.valueToCode(block, 'TO', Order.NONE) || '0'; - const functionName = phpGenerator.provideFunction_('math_random_int', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($a, $b) { + const argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; + const functionName = generator.provideFunction_('math_random_int', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($a, $b) { if ($a > $b) { return rand($b, $a); } @@ -341,15 +341,15 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($a, $b) { return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['math_random_float'] = function(block) { +phpGenerator.forBlock['math_random_float'] = function(block, generator) { // Random fraction between 0 and 1. return ['(float)rand()/(float)getrandmax()', Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['math_atan2'] = function(block) { +phpGenerator.forBlock['math_atan2'] = function(block, generator) { // Arctangent of point (X, Y) in degrees from -180 to 180. - const argument0 = phpGenerator.valueToCode(block, 'X', Order.NONE) || '0'; - const argument1 = phpGenerator.valueToCode(block, 'Y', Order.NONE) || '0'; + const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; return [ 'atan2(' + argument1 + ', ' + argument0 + ') / pi() * 180', Order.DIVISION diff --git a/generators/php/procedures.js b/generators/php/procedures.js index 483fd147f..1c2ed3dbf 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -16,7 +16,7 @@ import {NameType} from '../../core/names.js'; import {phpGenerator, Order} from '../php.js'; -phpGenerator.forBlock['procedures_defreturn'] = function(block) { +phpGenerator.forBlock['procedures_defreturn'] = function(block, generator) { // Define a procedure with a return value. // First, add a 'global' statement for every variable that is not shadowed by // a local parameter. @@ -26,59 +26,59 @@ phpGenerator.forBlock['procedures_defreturn'] = function(block) { for (let i = 0, variable; variable = usedVariables[i]; i++) { const varName = variable.name; if (block.getVars().indexOf(varName) === -1) { - globals.push(phpGenerator.nameDB_.getName(varName, NameType.VARIABLE)); + globals.push(generator.nameDB_.getName(varName, NameType.VARIABLE)); } } // Add developer variables. const devVarList = Variables.allDeveloperVariables(workspace); for (let i = 0; i < devVarList.length; i++) { globals.push( - phpGenerator.nameDB_.getName( + generator.nameDB_.getName( devVarList[i], NameType.DEVELOPER_VARIABLE)); } const globalStr = globals.length ? - phpGenerator.INDENT + 'global ' + globals.join(', ') + ';\n' : ''; + generator.INDENT + 'global ' + globals.join(', ') + ';\n' : ''; const funcName = - phpGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('NAME'), NameType.PROCEDURE); let xfix1 = ''; - if (phpGenerator.STATEMENT_PREFIX) { - xfix1 += phpGenerator.injectId(phpGenerator.STATEMENT_PREFIX, block); + if (generator.STATEMENT_PREFIX) { + xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block); } - if (phpGenerator.STATEMENT_SUFFIX) { - xfix1 += phpGenerator.injectId(phpGenerator.STATEMENT_SUFFIX, block); + if (generator.STATEMENT_SUFFIX) { + xfix1 += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (xfix1) { - xfix1 = phpGenerator.prefixLines(xfix1, phpGenerator.INDENT); + xfix1 = generator.prefixLines(xfix1, generator.INDENT); } let loopTrap = ''; - if (phpGenerator.INFINITE_LOOP_TRAP) { - loopTrap = phpGenerator.prefixLines( - phpGenerator.injectId(phpGenerator.INFINITE_LOOP_TRAP, block), - phpGenerator.INDENT); + if (generator.INFINITE_LOOP_TRAP) { + loopTrap = generator.prefixLines( + generator.injectId(generator.INFINITE_LOOP_TRAP, block), + generator.INDENT); } - const branch = phpGenerator.statementToCode(block, 'STACK'); - let returnValue = phpGenerator.valueToCode(block, 'RETURN', Order.NONE) || ''; + const branch = generator.statementToCode(block, 'STACK'); + let returnValue = generator.valueToCode(block, 'RETURN', Order.NONE) || ''; let xfix2 = ''; if (branch && returnValue) { // After executing the function body, revisit this block for the return. xfix2 = xfix1; } if (returnValue) { - returnValue = phpGenerator.INDENT + 'return ' + returnValue + ';\n'; + returnValue = generator.INDENT + 'return ' + returnValue + ';\n'; } const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = phpGenerator.nameDB_.getName(variables[i], NameType.VARIABLE); + args[i] = generator.nameDB_.getName(variables[i], NameType.VARIABLE); } let code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' + globalStr + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; - code = phpGenerator.scrub_(block, code); + code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - phpGenerator.definitions_['%' + funcName] = code; + generator.definitions_['%' + funcName] = code; return null; }; @@ -87,46 +87,46 @@ phpGenerator.forBlock['procedures_defreturn'] = function(block) { phpGenerator.forBlock['procedures_defnoreturn'] = phpGenerator.forBlock['procedures_defreturn']; -phpGenerator.forBlock['procedures_callreturn'] = function(block) { +phpGenerator.forBlock['procedures_callreturn'] = function(block, generator) { // Call a procedure with a return value. const funcName = - phpGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('NAME'), NameType.PROCEDURE); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = phpGenerator.valueToCode(block, 'ARG' + i, Order.NONE) || 'null'; + args[i] = generator.valueToCode(block, 'ARG' + i, Order.NONE) || 'null'; } const code = funcName + '(' + args.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['procedures_callnoreturn'] = function(block) { +phpGenerator.forBlock['procedures_callnoreturn'] = function(block, generator) { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = phpGenerator.forBlock['procedures_callreturn'](block); + const tuple = generator.forBlock['procedures_callreturn'](block, generator); return tuple[0] + ';\n'; }; -phpGenerator.forBlock['procedures_ifreturn'] = function(block) { +phpGenerator.forBlock['procedures_ifreturn'] = function(block, generator) { // Conditionally return value from a procedure. const condition = - phpGenerator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; let code = 'if (' + condition + ') {\n'; - if (phpGenerator.STATEMENT_SUFFIX) { + if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. code += - phpGenerator.prefixLines( - phpGenerator.injectId(phpGenerator.STATEMENT_SUFFIX, block), - phpGenerator.INDENT); + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT); } if (block.hasReturnValue_) { - const value = phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; - code += phpGenerator.INDENT + 'return ' + value + ';\n'; + const value = generator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; + code += generator.INDENT + 'return ' + value + ';\n'; } else { - code += phpGenerator.INDENT + 'return;\n'; + code += generator.INDENT + 'return;\n'; } code += '}\n'; return code; diff --git a/generators/php/text.js b/generators/php/text.js index 66e06d869..6992dad12 100644 --- a/generators/php/text.js +++ b/generators/php/text.js @@ -15,93 +15,93 @@ import {NameType} from '../../core/names.js'; import {phpGenerator, Order} from '../php.js'; -phpGenerator.forBlock['text'] = function(block) { +phpGenerator.forBlock['text'] = function(block, generator) { // Text value. - const code = phpGenerator.quote_(block.getFieldValue('TEXT')); + const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; }; -phpGenerator.forBlock['text_multiline'] = function(block) { +phpGenerator.forBlock['text_multiline'] = function(block, generator) { // Text value. - const code = phpGenerator.multiline_quote_(block.getFieldValue('TEXT')); + const code = generator.multiline_quote_(block.getFieldValue('TEXT')); const order = code.indexOf('.') !== -1 ? Order.STRING_CONCAT : Order.ATOMIC; return [code, order]; }; -phpGenerator.forBlock['text_join'] = function(block) { +phpGenerator.forBlock['text_join'] = function(block, generator) { // Create a string made up of any number of elements of any type. if (block.itemCount_ === 0) { return ["''", Order.ATOMIC]; } else if (block.itemCount_ === 1) { - const element = phpGenerator.valueToCode(block, 'ADD0', Order.NONE) || "''"; + const element = generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; const code = element; return [code, Order.NONE]; } else if (block.itemCount_ === 2) { const element0 = - phpGenerator.valueToCode(block, 'ADD0', Order.STRING_CONCAT) || "''"; + generator.valueToCode(block, 'ADD0', Order.STRING_CONCAT) || "''"; const element1 = - phpGenerator.valueToCode(block, 'ADD1', Order.STRING_CONCAT) || "''"; + generator.valueToCode(block, 'ADD1', Order.STRING_CONCAT) || "''"; const code = element0 + ' . ' + element1; return [code, Order.STRING_CONCAT]; } else { const elements = new Array(block.itemCount_); for (let i = 0; i < block.itemCount_; i++) { elements[i] = - phpGenerator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; + generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } const code = 'implode(\'\', array(' + elements.join(',') + '))'; return [code, Order.FUNCTION_CALL]; } }; -phpGenerator.forBlock['text_append'] = function(block) { +phpGenerator.forBlock['text_append'] = function(block, generator) { // Append to a variable in place. const varName = - phpGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); const value = - phpGenerator.valueToCode(block, 'TEXT', Order.ASSIGNMENT) || "''"; + generator.valueToCode(block, 'TEXT', Order.ASSIGNMENT) || "''"; return varName + ' .= ' + value + ';\n'; }; -phpGenerator.forBlock['text_length'] = function(block) { +phpGenerator.forBlock['text_length'] = function(block, generator) { // String or array length. - const functionName = phpGenerator.provideFunction_('length', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($value) { + const functionName = generator.provideFunction_('length', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { if (is_string($value)) { return strlen($value); } return count($value); } `); - const text = phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return [functionName + '(' + text + ')', Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['text_isEmpty'] = function(block) { +phpGenerator.forBlock['text_isEmpty'] = function(block, generator) { // Is the string null or array empty? - const text = phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return ['empty(' + text + ')', Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['text_indexOf'] = function(block) { +phpGenerator.forBlock['text_indexOf'] = function(block, generator) { // Search the text for a substring. const operator = block.getFieldValue('END') === 'FIRST' ? 'strpos' : 'strrpos'; - const substring = phpGenerator.valueToCode(block, 'FIND', Order.NONE) || "''"; - const text = phpGenerator.valueToCode(block, 'VALUE', Order.NONE) || "''"; + const substring = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; let errorIndex = ' -1'; let indexAdjustment = ''; if (block.workspace.options.oneBasedIndex) { errorIndex = ' 0'; indexAdjustment = ' + 1'; } - const functionName = phpGenerator.provideFunction_( + const functionName = generator.provideFunction_( block.getFieldValue('END') === 'FIRST' ? 'text_indexOf' : 'text_lastIndexOf', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($text, $search) { +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text, $search) { $pos = ${operator}($text, $search); return $pos === false ? ${errorIndex} : $pos${indexAdjustment}; } @@ -110,11 +110,11 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($text, $search) { return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['text_charAt'] = function(block) { +phpGenerator.forBlock['text_charAt'] = function(block, generator) { // Get letter at index. const where = block.getFieldValue('WHERE') || 'FROM_START'; const textOrder = (where === 'RANDOM') ? Order.NONE : Order.NONE; - const text = phpGenerator.valueToCode(block, 'VALUE', textOrder) || "''"; + const text = generator.valueToCode(block, 'VALUE', textOrder) || "''"; switch (where) { case 'FIRST': { const code = 'substr(' + text + ', 0, 1)'; @@ -125,18 +125,18 @@ phpGenerator.forBlock['text_charAt'] = function(block) { return [code, Order.FUNCTION_CALL]; } case 'FROM_START': { - const at = phpGenerator.getAdjusted(block, 'AT'); + const at = generator.getAdjusted(block, 'AT'); const code = 'substr(' + text + ', ' + at + ', 1)'; return [code, Order.FUNCTION_CALL]; } case 'FROM_END': { - const at = phpGenerator.getAdjusted(block, 'AT', 1, true); + const at = generator.getAdjusted(block, 'AT', 1, true); const code = 'substr(' + text + ', ' + at + ', 1)'; return [code, Order.FUNCTION_CALL]; } case 'RANDOM': { - const functionName = phpGenerator.provideFunction_('text_random_letter', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($text) { + const functionName = generator.provideFunction_('text_random_letter', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text) { return $text[rand(0, strlen($text) - 1)]; } `); @@ -147,19 +147,19 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($text) { throw Error('Unhandled option (text_charAt).'); }; -phpGenerator.forBlock['text_getSubstring'] = function(block) { +phpGenerator.forBlock['text_getSubstring'] = function(block, generator) { // Get substring. const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); - const text = phpGenerator.valueToCode(block, 'STRING', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'STRING', Order.NONE) || "''"; if (where1 === 'FIRST' && where2 === 'LAST') { const code = text; return [code, Order.NONE]; } else { - const at1 = phpGenerator.getAdjusted(block, 'AT1'); - const at2 = phpGenerator.getAdjusted(block, 'AT2'); - const functionName = phpGenerator.provideFunction_('text_get_substring', ` -function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($text, $where1, $at1, $where2, $at2) { + const at1 = generator.getAdjusted(block, 'AT1'); + const at2 = generator.getAdjusted(block, 'AT2'); + const functionName = generator.provideFunction_('text_get_substring', ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text, $where1, $at1, $where2, $at2) { if ($where1 == 'FROM_END') { $at1 = strlen($text) - 1 - $at1; } else if ($where1 == 'FIRST') { @@ -186,9 +186,9 @@ function ${phpGenerator.FUNCTION_NAME_PLACEHOLDER_}($text, $where1, $at1, $where } }; -phpGenerator.forBlock['text_changeCase'] = function(block) { +phpGenerator.forBlock['text_changeCase'] = function(block, generator) { // Change capitalization. - const text = phpGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; let code; if (block.getFieldValue('CASE') === 'UPPERCASE') { code = 'strtoupper(' + text + ')'; @@ -200,29 +200,29 @@ phpGenerator.forBlock['text_changeCase'] = function(block) { return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['text_trim'] = function(block) { +phpGenerator.forBlock['text_trim'] = function(block, generator) { // Trim spaces. const OPERATORS = {'LEFT': 'ltrim', 'RIGHT': 'rtrim', 'BOTH': 'trim'}; const operator = OPERATORS[block.getFieldValue('MODE')]; - const text = phpGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return [operator + '(' + text + ')', Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['text_print'] = function(block) { +phpGenerator.forBlock['text_print'] = function(block, generator) { // Print statement. - const msg = phpGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'print(' + msg + ');\n'; }; -phpGenerator.forBlock['text_prompt_ext'] = function(block) { +phpGenerator.forBlock['text_prompt_ext'] = function(block, generator) { // Prompt function. let msg; if (block.getField('TEXT')) { // Internal message. - msg = phpGenerator.quote_(block.getFieldValue('TEXT')); + msg = generator.quote_(block.getFieldValue('TEXT')); } else { // External message. - msg = phpGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; } let code = 'readline(' + msg + ')'; const toNumber = block.getFieldValue('TYPE') === 'NUMBER'; @@ -234,25 +234,25 @@ phpGenerator.forBlock['text_prompt_ext'] = function(block) { phpGenerator.forBlock['text_prompt'] = phpGenerator.forBlock['text_prompt_ext']; -phpGenerator.forBlock['text_count'] = function(block) { - const text = phpGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; - const sub = phpGenerator.valueToCode(block, 'SUB', Order.NONE) || "''"; +phpGenerator.forBlock['text_count'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; const code = 'strlen(' + sub + ') === 0' + ' ? strlen(' + text + ') + 1' + ' : substr_count(' + text + ', ' + sub + ')'; return [code, Order.CONDITIONAL]; }; -phpGenerator.forBlock['text_replace'] = function(block) { - const text = phpGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; - const from = phpGenerator.valueToCode(block, 'FROM', Order.NONE) || "''"; - const to = phpGenerator.valueToCode(block, 'TO', Order.NONE) || "''"; +phpGenerator.forBlock['text_replace'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; + const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; const code = 'str_replace(' + from + ', ' + to + ', ' + text + ')'; return [code, Order.FUNCTION_CALL]; }; -phpGenerator.forBlock['text_reverse'] = function(block) { - const text = phpGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; +phpGenerator.forBlock['text_reverse'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const code = 'strrev(' + text + ')'; return [code, Order.FUNCTION_CALL]; }; diff --git a/generators/php/variables.js b/generators/php/variables.js index 812c3770d..f1c47d1cd 100644 --- a/generators/php/variables.js +++ b/generators/php/variables.js @@ -15,20 +15,20 @@ import {NameType} from '../../core/names.js'; import {phpGenerator, Order} from '../php.js'; -phpGenerator.forBlock['variables_get'] = function(block) { +phpGenerator.forBlock['variables_get'] = function(block, generator) { // Variable getter. const code = - phpGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return [code, Order.ATOMIC]; }; -phpGenerator.forBlock['variables_set'] = function(block) { +phpGenerator.forBlock['variables_set'] = function(block, generator) { // Variable setter. const argument0 = - phpGenerator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; + generator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; const varName = - phpGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' = ' + argument0 + ';\n'; }; diff --git a/generators/php/variables_dynamic.js b/generators/php/variables_dynamic.js index 01eaf3661..3cfd652ad 100644 --- a/generators/php/variables_dynamic.js +++ b/generators/php/variables_dynamic.js @@ -15,7 +15,7 @@ import {phpGenerator} from '../php.js'; import './variables.js'; -// phpGenerator is dynamically typed. +// generator is dynamically typed. phpGenerator.forBlock['variables_get_dynamic'] = phpGenerator.forBlock['variables_get']; phpGenerator.forBlock['variables_set_dynamic'] = diff --git a/generators/python/colour.js b/generators/python/colour.js index 111df61e1..a1d06a380 100644 --- a/generators/python/colour.js +++ b/generators/python/colour.js @@ -14,39 +14,39 @@ goog.declareModuleId('Blockly.Python.colour'); import {pythonGenerator, Order} from '../python.js'; -pythonGenerator.forBlock['colour_picker'] = function(block) { +pythonGenerator.forBlock['colour_picker'] = function(block, generator) { // Colour picker. - const code = pythonGenerator.quote_(block.getFieldValue('COLOUR')); + const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; }; -pythonGenerator.forBlock['colour_random'] = function(block) { +pythonGenerator.forBlock['colour_random'] = function(block, generator) { // Generate a random colour. - pythonGenerator.definitions_['import_random'] = 'import random'; + generator.definitions_['import_random'] = 'import random'; const code = '\'#%06x\' % random.randint(0, 2**24 - 1)'; return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['colour_rgb'] = function(block) { +pythonGenerator.forBlock['colour_rgb'] = function(block, generator) { // Compose a colour from RGB components expressed as percentages. - const functionName = pythonGenerator.provideFunction_('colour_rgb', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b): + const functionName = generator.provideFunction_('colour_rgb', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b): r = round(min(100, max(0, r)) * 2.55) g = round(min(100, max(0, g)) * 2.55) b = round(min(100, max(0, b)) * 2.55) return '#%02x%02x%02x' % (r, g, b) `); - const r = pythonGenerator.valueToCode(block, 'RED', Order.NONE) || 0; - const g = pythonGenerator.valueToCode(block, 'GREEN', Order.NONE) || 0; - const b = pythonGenerator.valueToCode(block, 'BLUE', Order.NONE) || 0; + const r = generator.valueToCode(block, 'RED', Order.NONE) || 0; + const g = generator.valueToCode(block, 'GREEN', Order.NONE) || 0; + const b = generator.valueToCode(block, 'BLUE', Order.NONE) || 0; const code = functionName + '(' + r + ', ' + g + ', ' + b + ')'; return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['colour_blend'] = function(block) { +pythonGenerator.forBlock['colour_blend'] = function(block, generator) { // Blend two colours together. - const functionName = pythonGenerator.provideFunction_('colour_blend', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio): + const functionName = generator.provideFunction_('colour_blend', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio): r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16) g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16) b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16) @@ -57,12 +57,12 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio): return '#%02x%02x%02x' % (r, g, b) `); const colour1 = - pythonGenerator.valueToCode(block, 'COLOUR1', Order.NONE) + generator.valueToCode(block, 'COLOUR1', Order.NONE) || '\'#000000\''; const colour2 = - pythonGenerator.valueToCode(block, 'COLOUR2', Order.NONE) + generator.valueToCode(block, 'COLOUR2', Order.NONE) || '\'#000000\''; - const ratio = pythonGenerator.valueToCode(block, 'RATIO', Order.NONE) || 0; + const ratio = generator.valueToCode(block, 'RATIO', Order.NONE) || 0; const code = functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; return [code, Order.FUNCTION_CALL]; diff --git a/generators/python/lists.js b/generators/python/lists.js index 2c75862e4..08fb410c5 100644 --- a/generators/python/lists.js +++ b/generators/python/lists.js @@ -16,48 +16,48 @@ import {NameType} from '../../core/names.js'; import {pythonGenerator, Order} from '../python.js'; -pythonGenerator.forBlock['lists_create_empty'] = function(block) { +pythonGenerator.forBlock['lists_create_empty'] = function(block, generator) { // Create an empty list. return ['[]', Order.ATOMIC]; }; -pythonGenerator.forBlock['lists_create_with'] = function(block) { +pythonGenerator.forBlock['lists_create_with'] = function(block, generator) { // Create a list with any number of elements of any type. const elements = new Array(block.itemCount_); for (let i = 0; i < block.itemCount_; i++) { elements[i] = - pythonGenerator.valueToCode(block, 'ADD' + i, Order.NONE) || 'None'; + generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'None'; } const code = '[' + elements.join(', ') + ']'; return [code, Order.ATOMIC]; }; -pythonGenerator.forBlock['lists_repeat'] = function(block) { +pythonGenerator.forBlock['lists_repeat'] = function(block, generator) { // Create a list with one element repeated. - const item = pythonGenerator.valueToCode(block, 'ITEM', Order.NONE) || 'None'; + const item = generator.valueToCode(block, 'ITEM', Order.NONE) || 'None'; const times = - pythonGenerator.valueToCode(block, 'NUM', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'NUM', Order.MULTIPLICATIVE) || '0'; const code = '[' + item + '] * ' + times; return [code, Order.MULTIPLICATIVE]; }; -pythonGenerator.forBlock['lists_length'] = function(block) { +pythonGenerator.forBlock['lists_length'] = function(block, generator) { // String or array length. - const list = pythonGenerator.valueToCode(block, 'VALUE', Order.NONE) || '[]'; + const list = generator.valueToCode(block, 'VALUE', Order.NONE) || '[]'; return ['len(' + list + ')', Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['lists_isEmpty'] = function(block) { +pythonGenerator.forBlock['lists_isEmpty'] = function(block, generator) { // Is the string null or array empty? - const list = pythonGenerator.valueToCode(block, 'VALUE', Order.NONE) || '[]'; + const list = generator.valueToCode(block, 'VALUE', Order.NONE) || '[]'; const code = 'not len(' + list + ')'; return [code, Order.LOGICAL_NOT]; }; -pythonGenerator.forBlock['lists_indexOf'] = function(block) { +pythonGenerator.forBlock['lists_indexOf'] = function(block, generator) { // Find an item in the list. - const item = pythonGenerator.valueToCode(block, 'FIND', Order.NONE) || '[]'; - const list = pythonGenerator.valueToCode(block, 'VALUE', Order.NONE) || "''"; + const item = generator.valueToCode(block, 'FIND', Order.NONE) || '[]'; + const list = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; let errorIndex = ' -1'; let firstIndexAdjustment = ''; let lastIndexAdjustment = ' - 1'; @@ -70,15 +70,15 @@ pythonGenerator.forBlock['lists_indexOf'] = function(block) { let functionName; if (block.getFieldValue('END') === 'FIRST') { - functionName = pythonGenerator.provideFunction_('first_index', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem): + functionName = generator.provideFunction_('first_index', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem): try: index = my_list.index(elem)${firstIndexAdjustment} except: index =${errorIndex} return index `); } else { - functionName = pythonGenerator.provideFunction_('last_index', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem): + functionName = generator.provideFunction_('last_index', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem): try: index = len(my_list) - my_list[::-1].index(elem)${lastIndexAdjustment} except: index =${errorIndex} return index @@ -88,14 +88,14 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem): return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['lists_getIndex'] = function(block) { +pythonGenerator.forBlock['lists_getIndex'] = function(block, generator) { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; const listOrder = (where === 'RANDOM') ? Order.NONE : Order.MEMBER; - const list = pythonGenerator.valueToCode(block, 'VALUE', listOrder) || '[]'; + const list = generator.valueToCode(block, 'VALUE', listOrder) || '[]'; switch (where) { case 'FIRST': @@ -121,7 +121,7 @@ pythonGenerator.forBlock['lists_getIndex'] = function(block) { } break; case 'FROM_START': { - const at = pythonGenerator.getAdjustedInt(block, 'AT'); + const at = generator.getAdjustedInt(block, 'AT'); if (mode === 'GET') { const code = list + '[' + at + ']'; return [code, Order.MEMBER]; @@ -134,7 +134,7 @@ pythonGenerator.forBlock['lists_getIndex'] = function(block) { break; } case 'FROM_END': { - const at = pythonGenerator.getAdjustedInt(block, 'AT', 1, true); + const at = generator.getAdjustedInt(block, 'AT', 1, true); if (mode === 'GET') { const code = list + '[' + at + ']'; return [code, Order.MEMBER]; @@ -147,14 +147,14 @@ pythonGenerator.forBlock['lists_getIndex'] = function(block) { break; } case 'RANDOM': - pythonGenerator.definitions_['import_random'] = 'import random'; + generator.definitions_['import_random'] = 'import random'; if (mode === 'GET') { const code = 'random.choice(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else { const functionName = - pythonGenerator.provideFunction_('lists_remove_random_item', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList): + generator.provideFunction_('lists_remove_random_item', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList): x = int(random.random() * len(myList)) return myList.pop(x) `); @@ -170,13 +170,13 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList): throw Error('Unhandled combination (lists_getIndex).'); }; -pythonGenerator.forBlock['lists_setIndex'] = function(block) { +pythonGenerator.forBlock['lists_setIndex'] = function(block, generator) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. - let list = pythonGenerator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; + let list = generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; - const value = pythonGenerator.valueToCode(block, 'TO', Order.NONE) || 'None'; + const value = generator.valueToCode(block, 'TO', Order.NONE) || 'None'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. function cacheList() { @@ -184,7 +184,7 @@ pythonGenerator.forBlock['lists_setIndex'] = function(block) { return ''; } const listVar = - pythonGenerator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); const code = listVar + ' = ' + list + '\n'; list = listVar; return code; @@ -206,7 +206,7 @@ pythonGenerator.forBlock['lists_setIndex'] = function(block) { } break; case 'FROM_START': { - const at = pythonGenerator.getAdjustedInt(block, 'AT'); + const at = generator.getAdjustedInt(block, 'AT'); if (mode === 'SET') { return list + '[' + at + '] = ' + value + '\n'; } else if (mode === 'INSERT') { @@ -215,7 +215,7 @@ pythonGenerator.forBlock['lists_setIndex'] = function(block) { break; } case 'FROM_END': { - const at = pythonGenerator.getAdjustedInt(block, 'AT', 1, true); + const at = generator.getAdjustedInt(block, 'AT', 1, true); if (mode === 'SET') { return list + '[' + at + '] = ' + value + '\n'; } else if (mode === 'INSERT') { @@ -224,10 +224,10 @@ pythonGenerator.forBlock['lists_setIndex'] = function(block) { break; } case 'RANDOM': { - pythonGenerator.definitions_['import_random'] = 'import random'; + generator.definitions_['import_random'] = 'import random'; let code = cacheList(); const xVar = - pythonGenerator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); + generator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); code += xVar + ' = int(random.random() * len(' + list + '))\n'; if (mode === 'SET') { code += list + '[' + xVar + '] = ' + value + '\n'; @@ -242,21 +242,21 @@ pythonGenerator.forBlock['lists_setIndex'] = function(block) { throw Error('Unhandled combination (lists_setIndex).'); }; -pythonGenerator.forBlock['lists_getSublist'] = function(block) { +pythonGenerator.forBlock['lists_getSublist'] = function(block, generator) { // Get sublist. - const list = pythonGenerator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; + const list = generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); let at1; switch (where1) { case 'FROM_START': - at1 = pythonGenerator.getAdjustedInt(block, 'AT1'); + at1 = generator.getAdjustedInt(block, 'AT1'); if (at1 === 0) { at1 = ''; } break; case 'FROM_END': - at1 = pythonGenerator.getAdjustedInt(block, 'AT1', 1, true); + at1 = generator.getAdjustedInt(block, 'AT1', 1, true); break; case 'FIRST': at1 = ''; @@ -268,14 +268,14 @@ pythonGenerator.forBlock['lists_getSublist'] = function(block) { let at2; switch (where2) { case 'FROM_START': - at2 = pythonGenerator.getAdjustedInt(block, 'AT2', 1); + at2 = generator.getAdjustedInt(block, 'AT2', 1); break; case 'FROM_END': - at2 = pythonGenerator.getAdjustedInt(block, 'AT2', 0, true); + at2 = generator.getAdjustedInt(block, 'AT2', 0, true); // Ensure that if the result calculated is 0 that sub-sequence will // include all elements as expected. if (!stringUtils.isNumber(String(at2))) { - pythonGenerator.definitions_['import_sys'] = 'import sys'; + generator.definitions_['import_sys'] = 'import sys'; at2 += ' or sys.maxsize'; } else if (at2 === 0) { at2 = ''; @@ -291,13 +291,13 @@ pythonGenerator.forBlock['lists_getSublist'] = function(block) { return [code, Order.MEMBER]; }; -pythonGenerator.forBlock['lists_sort'] = function(block) { +pythonGenerator.forBlock['lists_sort'] = function(block, generator) { // Block for sorting a list. - const list = (pythonGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'); + const list = (generator.valueToCode(block, 'LIST', Order.NONE) || '[]'); const type = block.getFieldValue('TYPE'); const reverse = block.getFieldValue('DIRECTION') === '1' ? 'False' : 'True'; - const sortFunctionName = pythonGenerator.provideFunction_('lists_sort', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(my_list, type, reverse): + const sortFunctionName = generator.provideFunction_('lists_sort', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(my_list, type, reverse): def try_float(s): try: return float(s) @@ -318,20 +318,20 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(my_list, type, reverse): return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['lists_split'] = function(block) { +pythonGenerator.forBlock['lists_split'] = function(block, generator) { // Block for splitting text into a list, or joining a list into text. const mode = block.getFieldValue('MODE'); let code; if (mode === 'SPLIT') { const value_input = - pythonGenerator.valueToCode(block, 'INPUT', Order.MEMBER) || "''"; - const value_delim = pythonGenerator.valueToCode(block, 'DELIM', Order.NONE); + generator.valueToCode(block, 'INPUT', Order.MEMBER) || "''"; + const value_delim = generator.valueToCode(block, 'DELIM', Order.NONE); code = value_input + '.split(' + value_delim + ')'; } else if (mode === 'JOIN') { const value_input = - pythonGenerator.valueToCode(block, 'INPUT', Order.NONE) || '[]'; + generator.valueToCode(block, 'INPUT', Order.NONE) || '[]'; const value_delim = - pythonGenerator.valueToCode(block, 'DELIM', Order.MEMBER) || "''"; + generator.valueToCode(block, 'DELIM', Order.MEMBER) || "''"; code = value_delim + '.join(' + value_input + ')'; } else { throw Error('Unknown mode: ' + mode); @@ -339,9 +339,9 @@ pythonGenerator.forBlock['lists_split'] = function(block) { return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['lists_reverse'] = function(block) { +pythonGenerator.forBlock['lists_reverse'] = function(block, generator) { // Block for reversing a list. - const list = pythonGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; const code = 'list(reversed(' + list + '))'; return [code, Order.FUNCTION_CALL]; }; diff --git a/generators/python/logic.js b/generators/python/logic.js index c835af59b..4308d6cb8 100644 --- a/generators/python/logic.js +++ b/generators/python/logic.js @@ -14,40 +14,40 @@ goog.declareModuleId('Blockly.Python.logic'); import {pythonGenerator, Order} from '../python.js'; -pythonGenerator.forBlock['controls_if'] = function(block) { +pythonGenerator.forBlock['controls_if'] = function(block, generator) { // If/elseif/else condition. let n = 0; let code = '', branchCode, conditionCode; - if (pythonGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - code += pythonGenerator.injectId(pythonGenerator.STATEMENT_PREFIX, block); + code += generator.injectId(generator.STATEMENT_PREFIX, block); } do { conditionCode = - pythonGenerator.valueToCode(block, 'IF' + n, Order.NONE) || 'False'; + generator.valueToCode(block, 'IF' + n, Order.NONE) || 'False'; branchCode = - pythonGenerator.statementToCode(block, 'DO' + n) || - pythonGenerator.PASS; - if (pythonGenerator.STATEMENT_SUFFIX) { + generator.statementToCode(block, 'DO' + n) || + generator.PASS; + if (generator.STATEMENT_SUFFIX) { branchCode = - pythonGenerator.prefixLines( - pythonGenerator.injectId(pythonGenerator.STATEMENT_SUFFIX, block), - pythonGenerator.INDENT) + + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT) + branchCode; } code += (n === 0 ? 'if ' : 'elif ') + conditionCode + ':\n' + branchCode; n++; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE') || pythonGenerator.STATEMENT_SUFFIX) { + if (block.getInput('ELSE') || generator.STATEMENT_SUFFIX) { branchCode = - pythonGenerator.statementToCode(block, 'ELSE') || pythonGenerator.PASS; - if (pythonGenerator.STATEMENT_SUFFIX) { + generator.statementToCode(block, 'ELSE') || generator.PASS; + if (generator.STATEMENT_SUFFIX) { branchCode = - pythonGenerator.prefixLines( - pythonGenerator.injectId( - pythonGenerator.STATEMENT_SUFFIX, block), - pythonGenerator.INDENT) + + generator.prefixLines( + generator.injectId( + generator.STATEMENT_SUFFIX, block), + generator.INDENT) + branchCode; } code += 'else:\n' + branchCode; @@ -58,25 +58,25 @@ pythonGenerator.forBlock['controls_if'] = function(block) { pythonGenerator.forBlock['controls_ifelse'] = pythonGenerator.forBlock['controls_if']; -pythonGenerator.forBlock['logic_compare'] = function(block) { +pythonGenerator.forBlock['logic_compare'] = function(block, generator) { // Comparison operator. const OPERATORS = {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; const operator = OPERATORS[block.getFieldValue('OP')]; const order = Order.RELATIONAL; - const argument0 = pythonGenerator.valueToCode(block, 'A', order) || '0'; - const argument1 = pythonGenerator.valueToCode(block, 'B', order) || '0'; + const argument0 = generator.valueToCode(block, 'A', order) || '0'; + const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; -pythonGenerator.forBlock['logic_operation'] = function(block) { +pythonGenerator.forBlock['logic_operation'] = function(block, generator) { // Operations 'and', 'or'. const operator = (block.getFieldValue('OP') === 'AND') ? 'and' : 'or'; const order = (operator === 'and') ? Order.LOGICAL_AND : Order.LOGICAL_OR; - let argument0 = pythonGenerator.valueToCode(block, 'A', order); - let argument1 = pythonGenerator.valueToCode(block, 'B', order); + let argument0 = generator.valueToCode(block, 'A', order); + let argument1 = generator.valueToCode(block, 'B', order); if (!argument0 && !argument1) { // If there are no arguments, then the return value is false. argument0 = 'False'; @@ -95,33 +95,33 @@ pythonGenerator.forBlock['logic_operation'] = function(block) { return [code, order]; }; -pythonGenerator.forBlock['logic_negate'] = function(block) { +pythonGenerator.forBlock['logic_negate'] = function(block, generator) { // Negation. const argument0 = - pythonGenerator.valueToCode(block, 'BOOL', Order.LOGICAL_NOT) || 'True'; + generator.valueToCode(block, 'BOOL', Order.LOGICAL_NOT) || 'True'; const code = 'not ' + argument0; return [code, Order.LOGICAL_NOT]; }; -pythonGenerator.forBlock['logic_boolean'] = function(block) { +pythonGenerator.forBlock['logic_boolean'] = function(block, generator) { // Boolean values true and false. const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'True' : 'False'; return [code, Order.ATOMIC]; }; -pythonGenerator.forBlock['logic_null'] = function(block) { +pythonGenerator.forBlock['logic_null'] = function(block, generator) { // Null data type. return ['None', Order.ATOMIC]; }; -pythonGenerator.forBlock['logic_ternary'] = function(block) { +pythonGenerator.forBlock['logic_ternary'] = function(block, generator) { // Ternary operator. const value_if = - pythonGenerator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'False'; + generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'False'; const value_then = - pythonGenerator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'None'; + generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'None'; const value_else = - pythonGenerator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'None'; + generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'None'; const code = value_then + ' if ' + value_if + ' else ' + value_else; return [code, Order.CONDITIONAL]; }; diff --git a/generators/python/loops.js b/generators/python/loops.js index 997656389..aef33c2f9 100644 --- a/generators/python/loops.js +++ b/generators/python/loops.js @@ -16,7 +16,7 @@ import {NameType} from '../../core/names.js'; import {pythonGenerator, Order} from '../python.js'; -pythonGenerator.forBlock['controls_repeat_ext'] = function(block) { +pythonGenerator.forBlock['controls_repeat_ext'] = function(block, generator) { // Repeat n times. let repeats; if (block.getField('TIMES')) { @@ -24,17 +24,17 @@ pythonGenerator.forBlock['controls_repeat_ext'] = function(block) { repeats = String(parseInt(block.getFieldValue('TIMES'), 10)); } else { // External number. - repeats = pythonGenerator.valueToCode(block, 'TIMES', Order.NONE) || '0'; + repeats = generator.valueToCode(block, 'TIMES', Order.NONE) || '0'; } if (stringUtils.isNumber(repeats)) { repeats = parseInt(repeats, 10); } else { repeats = 'int(' + repeats + ')'; } - let branch = pythonGenerator.statementToCode(block, 'DO'); - branch = pythonGenerator.addLoopTrap(branch, block) || pythonGenerator.PASS; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block) || generator.PASS; const loopVar = - pythonGenerator.nameDB_.getDistinctName('count', NameType.VARIABLE); + generator.nameDB_.getDistinctName('count', NameType.VARIABLE); const code = 'for ' + loopVar + ' in range(' + repeats + '):\n' + branch; return code; }; @@ -42,53 +42,53 @@ pythonGenerator.forBlock['controls_repeat_ext'] = function(block) { pythonGenerator.forBlock['controls_repeat'] = pythonGenerator.forBlock['controls_repeat_ext']; -pythonGenerator.forBlock['controls_whileUntil'] = function(block) { +pythonGenerator.forBlock['controls_whileUntil'] = function(block, generator) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; - let argument0 = pythonGenerator.valueToCode( + let argument0 = generator.valueToCode( block, 'BOOL', until ? Order.LOGICAL_NOT : Order.NONE) || 'False'; - let branch = pythonGenerator.statementToCode(block, 'DO'); - branch = pythonGenerator.addLoopTrap(branch, block) || pythonGenerator.PASS; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block) || generator.PASS; if (until) { argument0 = 'not ' + argument0; } return 'while ' + argument0 + ':\n' + branch; }; -pythonGenerator.forBlock['controls_for'] = function(block) { +pythonGenerator.forBlock['controls_for'] = function(block, generator) { // For loop. const variable0 = - pythonGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); - let argument0 = pythonGenerator.valueToCode(block, 'FROM', Order.NONE) || '0'; - let argument1 = pythonGenerator.valueToCode(block, 'TO', Order.NONE) || '0'; - let increment = pythonGenerator.valueToCode(block, 'BY', Order.NONE) || '1'; - let branch = pythonGenerator.statementToCode(block, 'DO'); - branch = pythonGenerator.addLoopTrap(branch, block) || pythonGenerator.PASS; + let argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; + let argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; + let increment = generator.valueToCode(block, 'BY', Order.NONE) || '1'; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block) || generator.PASS; let code = ''; let range; // Helper functions. const defineUpRange = function() { - return pythonGenerator.provideFunction_('upRange', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step): + return generator.provideFunction_('upRange', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step): while start <= stop: yield start start += abs(step) `); }; const defineDownRange = function() { - return pythonGenerator.provideFunction_('downRange', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step): + return generator.provideFunction_('downRange', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step): while start >= stop: yield start start -= abs(step) `); }; - // Arguments are legal pythonGenerator code (numbers or strings returned by scrub()). + // Arguments are legal generator code (numbers or strings returned by scrub()). const generateUpDownRange = function(start, end, inc) { return '(' + start + ' <= ' + end + ') and ' + defineUpRange() + '(' + start + ', ' + end + ', ' + inc + ') or ' + defineDownRange() + '(' + @@ -139,7 +139,7 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step): arg = Number(arg); } else if (!arg.match(/^\w+$/)) { // Not a variable, it's complicated. - const varName = pythonGenerator.nameDB_.getDistinctName( + const varName = generator.nameDB_.getDistinctName( variable0 + suffix, NameType.VARIABLE); code += varName + ' = ' + arg + '\n'; arg = varName; @@ -166,38 +166,38 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step): return code; }; -pythonGenerator.forBlock['controls_forEach'] = function(block) { +pythonGenerator.forBlock['controls_forEach'] = function(block, generator) { // For each loop. const variable0 = - pythonGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); const argument0 = - pythonGenerator.valueToCode(block, 'LIST', Order.RELATIONAL) || '[]'; - let branch = pythonGenerator.statementToCode(block, 'DO'); - branch = pythonGenerator.addLoopTrap(branch, block) || pythonGenerator.PASS; + generator.valueToCode(block, 'LIST', Order.RELATIONAL) || '[]'; + let branch = generator.statementToCode(block, 'DO'); + branch = generator.addLoopTrap(branch, block) || generator.PASS; const code = 'for ' + variable0 + ' in ' + argument0 + ':\n' + branch; return code; }; -pythonGenerator.forBlock['controls_flow_statements'] = function(block) { +pythonGenerator.forBlock['controls_flow_statements'] = function(block, generator) { // Flow statements: continue, break. let xfix = ''; - if (pythonGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - xfix += pythonGenerator.injectId(pythonGenerator.STATEMENT_PREFIX, block); + xfix += generator.injectId(generator.STATEMENT_PREFIX, block); } - if (pythonGenerator.STATEMENT_SUFFIX) { + if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. - xfix += pythonGenerator.injectId(pythonGenerator.STATEMENT_SUFFIX, block); + xfix += generator.injectId(generator.STATEMENT_SUFFIX, block); } - if (pythonGenerator.STATEMENT_PREFIX) { + if (generator.STATEMENT_PREFIX) { const loop = block.getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. - xfix += pythonGenerator.injectId(pythonGenerator.STATEMENT_PREFIX, loop); + xfix += generator.injectId(generator.STATEMENT_PREFIX, loop); } } switch (block.getFieldValue('FLOW')) { diff --git a/generators/python/math.js b/generators/python/math.js index a56b8108a..cfd61a118 100644 --- a/generators/python/math.js +++ b/generators/python/math.js @@ -18,7 +18,7 @@ import {pythonGenerator, Order} from '../python.js'; // If any new block imports any library, add that library name here. pythonGenerator.addReservedWords('math,random,Number'); -pythonGenerator.forBlock['math_number'] = function(block) { +pythonGenerator.forBlock['math_number'] = function(block, generator) { // Numeric value. let code = Number(block.getFieldValue('NUM')); let order; @@ -34,7 +34,7 @@ pythonGenerator.forBlock['math_number'] = function(block) { return [code, order]; }; -pythonGenerator.forBlock['math_arithmetic'] = function(block) { +pythonGenerator.forBlock['math_arithmetic'] = function(block, generator) { // Basic arithmetic operators, and power. const OPERATORS = { 'ADD': [' + ', Order.ADDITIVE], @@ -46,33 +46,33 @@ pythonGenerator.forBlock['math_arithmetic'] = function(block) { const tuple = OPERATORS[block.getFieldValue('OP')]; const operator = tuple[0]; const order = tuple[1]; - const argument0 = pythonGenerator.valueToCode(block, 'A', order) || '0'; - const argument1 = pythonGenerator.valueToCode(block, 'B', order) || '0'; + const argument0 = generator.valueToCode(block, 'A', order) || '0'; + const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + operator + argument1; return [code, order]; // In case of 'DIVIDE', division between integers returns different results - // in pythonGenerator 2 and 3. However, is not an issue since Blockly does not + // in generator 2 and 3. However, is not an issue since Blockly does not // guarantee identical results in all languages. To do otherwise would // require every operator to be wrapped in a function call. This would kill // legibility of the generated code. }; -pythonGenerator.forBlock['math_single'] = function(block) { +pythonGenerator.forBlock['math_single'] = function(block, generator) { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; let arg; if (operator === 'NEG') { // Negation is a special case given its different operator precedence. - code = pythonGenerator.valueToCode(block, 'NUM', Order.UNARY_SIGN) || '0'; + code = generator.valueToCode(block, 'NUM', Order.UNARY_SIGN) || '0'; return ['-' + code, Order.UNARY_SIGN]; } - pythonGenerator.definitions_['import_math'] = 'import math'; + generator.definitions_['import_math'] = 'import math'; if (operator === 'SIN' || operator === 'COS' || operator === 'TAN') { arg = - pythonGenerator.valueToCode(block, 'NUM', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'NUM', Order.MULTIPLICATIVE) || '0'; } else { - arg = pythonGenerator.valueToCode(block, 'NUM', Order.NONE) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; } // First, handle cases which generate values that don't need parentheses // wrapping the code. @@ -135,7 +135,7 @@ pythonGenerator.forBlock['math_single'] = function(block) { return [code, Order.MULTIPLICATIVE]; }; -pythonGenerator.forBlock['math_constant'] = function(block) { +pythonGenerator.forBlock['math_constant'] = function(block, generator) { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. const CONSTANTS = { 'PI': ['math.pi', Order.MEMBER], @@ -147,12 +147,12 @@ pythonGenerator.forBlock['math_constant'] = function(block) { }; const constant = block.getFieldValue('CONSTANT'); if (constant !== 'INFINITY') { - pythonGenerator.definitions_['import_math'] = 'import math'; + generator.definitions_['import_math'] = 'import math'; } return CONSTANTS[constant]; }; -pythonGenerator.forBlock['math_number_property'] = function(block) { +pythonGenerator.forBlock['math_number_property'] = function(block, generator) { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. const PROPERTIES = { @@ -168,16 +168,16 @@ pythonGenerator.forBlock['math_number_property'] = function(block) { } const dropdownProperty = block.getFieldValue('PROPERTY'); const [suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty]; - const numberToCheck = pythonGenerator.valueToCode(block, 'NUMBER_TO_CHECK', + const numberToCheck = generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || '0'; let code; if (dropdownProperty === 'PRIME') { // Prime is a special case as it is not a one-liner test. - pythonGenerator.definitions_['import_math'] = 'import math'; - pythonGenerator.definitions_['from_numbers_import_Number'] = + generator.definitions_['import_math'] = 'import math'; + generator.definitions_['from_numbers_import_Number'] = 'from numbers import Number'; - const functionName = pythonGenerator.provideFunction_('math_isPrime', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(n): + const functionName = generator.provideFunction_('math_isPrime', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(n): # https://en.wikipedia.org/wiki/Primality_test#Naive_methods # If n is not a number but a string, try parsing it. if not isinstance(n, Number): @@ -198,9 +198,9 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(n): `); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = pythonGenerator.valueToCode(block, 'DIVISOR', + const divisor = generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; - // If 'divisor' is some code that evals to 0, pythonGenerator will raise an error. + // If 'divisor' is some code that evals to 0, generator will raise an error. if (divisor === '0') { return ['False', Order.ATOMIC]; } @@ -211,14 +211,14 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(n): return [code, outputOrder]; }; -pythonGenerator.forBlock['math_change'] = function(block) { +pythonGenerator.forBlock['math_change'] = function(block, generator) { // Add to a variable in place. - pythonGenerator.definitions_['from_numbers_import_Number'] = + generator.definitions_['from_numbers_import_Number'] = 'from numbers import Number'; const argument0 = - pythonGenerator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; + generator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; const varName = - pythonGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' = (' + varName + ' if isinstance(' + varName + ', Number) else 0) + ' + argument0 + '\n'; @@ -231,10 +231,10 @@ pythonGenerator.forBlock['math_round'] = pythonGenerator.forBlock['math_trig'] = pythonGenerator.forBlock['math_single']; -pythonGenerator.forBlock['math_on_list'] = function(block) { +pythonGenerator.forBlock['math_on_list'] = function(block, generator) { // Math functions for lists. const func = block.getFieldValue('OP'); - const list = pythonGenerator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; let code; switch (func) { case 'SUM': @@ -247,12 +247,12 @@ pythonGenerator.forBlock['math_on_list'] = function(block) { code = 'max(' + list + ')'; break; case 'AVERAGE': { - pythonGenerator.definitions_['from_numbers_import_Number'] = + generator.definitions_['from_numbers_import_Number'] = 'from numbers import Number'; // This operation excludes null and values that aren't int or float: // math_mean([null, null, "aString", 1, 9]) -> 5.0 - const functionName = pythonGenerator.provideFunction_('math_mean', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList): + const functionName = generator.provideFunction_('math_mean', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList): localList = [e for e in myList if isinstance(e, Number)] if not localList: return return float(sum(localList)) / len(localList) @@ -261,12 +261,12 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList): break; } case 'MEDIAN': { - pythonGenerator.definitions_['from_numbers_import_Number'] = + generator.definitions_['from_numbers_import_Number'] = 'from numbers import Number'; // This operation excludes null values: // math_median([null, null, 1, 3]) -> 2.0 - const functionName = pythonGenerator.provideFunction_( 'math_median', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList): + const functionName = generator.provideFunction_( 'math_median', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList): localList = sorted([e for e in myList if isinstance(e, Number)]) if not localList: return if len(localList) % 2 == 0: @@ -281,8 +281,8 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(myList): // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1] - const functionName = pythonGenerator.provideFunction_('math_modes', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(some_list): + const functionName = generator.provideFunction_('math_modes', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(some_list): modes = [] # Using a lists of [item, count] to keep count rather than dict # to avoid "unhashable" errors when the counted item is itself a list or dict. @@ -306,10 +306,10 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(some_list): break; } case 'STD_DEV': { - pythonGenerator.definitions_['import_math'] = 'import math'; + generator.definitions_['import_math'] = 'import math'; const functionName = - pythonGenerator.provideFunction_('math_standard_deviation', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(numbers): + generator.provideFunction_('math_standard_deviation', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(numbers): n = len(numbers) if n == 0: return mean = float(sum(numbers)) / n @@ -320,7 +320,7 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(numbers): break; } case 'RANDOM': - pythonGenerator.definitions_['import_random'] = 'import random'; + generator.definitions_['import_random'] = 'import random'; code = 'random.choice(' + list + ')'; break; default: @@ -329,54 +329,54 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(numbers): return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['math_modulo'] = function(block) { +pythonGenerator.forBlock['math_modulo'] = function(block, generator) { // Remainder computation. const argument0 = - pythonGenerator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || + generator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || '0'; const argument1 = - pythonGenerator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || + generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MULTIPLICATIVE]; }; -pythonGenerator.forBlock['math_constrain'] = function(block) { +pythonGenerator.forBlock['math_constrain'] = function(block, generator) { // Constrain a number between two limits. const argument0 = - pythonGenerator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; const argument1 = - pythonGenerator.valueToCode(block, 'LOW', Order.NONE) || '0'; + generator.valueToCode(block, 'LOW', Order.NONE) || '0'; const argument2 = - pythonGenerator.valueToCode(block, 'HIGH', Order.NONE) || + generator.valueToCode(block, 'HIGH', Order.NONE) || 'float(\'inf\')'; const code = 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['math_random_int'] = function(block) { +pythonGenerator.forBlock['math_random_int'] = function(block, generator) { // Random integer between [X] and [Y]. - pythonGenerator.definitions_['import_random'] = 'import random'; + generator.definitions_['import_random'] = 'import random'; const argument0 = - pythonGenerator.valueToCode(block, 'FROM', Order.NONE) || '0'; + generator.valueToCode(block, 'FROM', Order.NONE) || '0'; const argument1 = - pythonGenerator.valueToCode(block, 'TO', Order.NONE) || '0'; + generator.valueToCode(block, 'TO', Order.NONE) || '0'; const code = 'random.randint(' + argument0 + ', ' + argument1 + ')'; return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['math_random_float'] = function(block) { +pythonGenerator.forBlock['math_random_float'] = function(block, generator) { // Random fraction between 0 and 1. - pythonGenerator.definitions_['import_random'] = 'import random'; + generator.definitions_['import_random'] = 'import random'; return ['random.random()', Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['math_atan2'] = function(block) { +pythonGenerator.forBlock['math_atan2'] = function(block, generator) { // Arctangent of point (X, Y) in degrees from -180 to 180. - pythonGenerator.definitions_['import_math'] = 'import math'; - const argument0 = pythonGenerator.valueToCode(block, 'X', Order.NONE) || '0'; - const argument1 = pythonGenerator.valueToCode(block, 'Y', Order.NONE) || '0'; + generator.definitions_['import_math'] = 'import math'; + const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; return [ 'math.atan2(' + argument1 + ', ' + argument0 + ') / math.pi * 180', Order.MULTIPLICATIVE diff --git a/generators/python/procedures.js b/generators/python/procedures.js index 44041df3f..e5c2cca4b 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -16,7 +16,7 @@ import {NameType} from '../../core/names.js'; import {pythonGenerator, Order} from '../python.js'; -pythonGenerator.forBlock['procedures_defreturn'] = function(block) { +pythonGenerator.forBlock['procedures_defreturn'] = function(block, generator) { // Define a procedure with a return value. // First, add a 'global' statement for every variable that is not shadowed by // a local parameter. @@ -26,62 +26,62 @@ pythonGenerator.forBlock['procedures_defreturn'] = function(block) { for (let i = 0, variable; (variable = usedVariables[i]); i++) { const varName = variable.name; if (block.getVars().indexOf(varName) === -1) { - globals.push(pythonGenerator.nameDB_.getName(varName, NameType.VARIABLE)); + globals.push(generator.nameDB_.getName(varName, NameType.VARIABLE)); } } // Add developer variables. const devVarList = Variables.allDeveloperVariables(workspace); for (let i = 0; i < devVarList.length; i++) { globals.push( - pythonGenerator.nameDB_.getName( + generator.nameDB_.getName( devVarList[i], NameType.DEVELOPER_VARIABLE)); } const globalString = globals.length ? - pythonGenerator.INDENT + 'global ' + globals.join(', ') + '\n' : + generator.INDENT + 'global ' + globals.join(', ') + '\n' : ''; const funcName = - pythonGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('NAME'), NameType.PROCEDURE); let xfix1 = ''; - if (pythonGenerator.STATEMENT_PREFIX) { - xfix1 += pythonGenerator.injectId(pythonGenerator.STATEMENT_PREFIX, block); + if (generator.STATEMENT_PREFIX) { + xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block); } - if (pythonGenerator.STATEMENT_SUFFIX) { - xfix1 += pythonGenerator.injectId(pythonGenerator.STATEMENT_SUFFIX, block); + if (generator.STATEMENT_SUFFIX) { + xfix1 += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (xfix1) { - xfix1 = pythonGenerator.prefixLines(xfix1, pythonGenerator.INDENT); + xfix1 = generator.prefixLines(xfix1, generator.INDENT); } let loopTrap = ''; - if (pythonGenerator.INFINITE_LOOP_TRAP) { - loopTrap = pythonGenerator.prefixLines( - pythonGenerator.injectId(pythonGenerator.INFINITE_LOOP_TRAP, block), - pythonGenerator.INDENT); + if (generator.INFINITE_LOOP_TRAP) { + loopTrap = generator.prefixLines( + generator.injectId(generator.INFINITE_LOOP_TRAP, block), + generator.INDENT); } - let branch = pythonGenerator.statementToCode(block, 'STACK'); + let branch = generator.statementToCode(block, 'STACK'); let returnValue = - pythonGenerator.valueToCode(block, 'RETURN', Order.NONE) || ''; + generator.valueToCode(block, 'RETURN', Order.NONE) || ''; let xfix2 = ''; if (branch && returnValue) { // After executing the function body, revisit this block for the return. xfix2 = xfix1; } if (returnValue) { - returnValue = pythonGenerator.INDENT + 'return ' + returnValue + '\n'; + returnValue = generator.INDENT + 'return ' + returnValue + '\n'; } else if (!branch) { - branch = pythonGenerator.PASS; + branch = generator.PASS; } const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = pythonGenerator.nameDB_.getName(variables[i], NameType.VARIABLE); + args[i] = generator.nameDB_.getName(variables[i], NameType.VARIABLE); } let code = 'def ' + funcName + '(' + args.join(', ') + '):\n' + globalString + xfix1 + loopTrap + branch + xfix2 + returnValue; - code = pythonGenerator.scrub_(block, code); + code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - pythonGenerator.definitions_['%' + funcName] = code; + generator.definitions_['%' + funcName] = code; return null; }; @@ -90,47 +90,47 @@ pythonGenerator.forBlock['procedures_defreturn'] = function(block) { pythonGenerator.forBlock['procedures_defnoreturn'] = pythonGenerator.forBlock['procedures_defreturn']; -pythonGenerator.forBlock['procedures_callreturn'] = function(block) { +pythonGenerator.forBlock['procedures_callreturn'] = function(block, generator) { // Call a procedure with a return value. const funcName = - pythonGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('NAME'), NameType.PROCEDURE); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { args[i] = - pythonGenerator.valueToCode(block, 'ARG' + i, Order.NONE) || 'None'; + generator.valueToCode(block, 'ARG' + i, Order.NONE) || 'None'; } const code = funcName + '(' + args.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['procedures_callnoreturn'] = function(block) { +pythonGenerator.forBlock['procedures_callnoreturn'] = function(block, generator) { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = pythonGenerator.forBlock['procedures_callreturn'](block); + const tuple = generator.forBlock['procedures_callreturn'](block, generator); return tuple[0] + '\n'; }; -pythonGenerator.forBlock['procedures_ifreturn'] = function(block) { +pythonGenerator.forBlock['procedures_ifreturn'] = function(block, generator) { // Conditionally return value from a procedure. const condition = - pythonGenerator.valueToCode(block, 'CONDITION', Order.NONE) || 'False'; + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'False'; let code = 'if ' + condition + ':\n'; - if (pythonGenerator.STATEMENT_SUFFIX) { + if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. - code += pythonGenerator.prefixLines( - pythonGenerator.injectId( - pythonGenerator.STATEMENT_SUFFIX, block), pythonGenerator.INDENT); + code += generator.prefixLines( + generator.injectId( + generator.STATEMENT_SUFFIX, block), generator.INDENT); } if (block.hasReturnValue_) { const value = - pythonGenerator.valueToCode(block, 'VALUE', Order.NONE) || 'None'; - code += pythonGenerator.INDENT + 'return ' + value + '\n'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'None'; + code += generator.INDENT + 'return ' + value + '\n'; } else { - code += pythonGenerator.INDENT + 'return\n'; + code += generator.INDENT + 'return\n'; } return code; }; diff --git a/generators/python/text.js b/generators/python/text.js index 67fe2dc1a..7f3621e95 100644 --- a/generators/python/text.js +++ b/generators/python/text.js @@ -16,15 +16,15 @@ import {NameType} from '../../core/names.js'; import {pythonGenerator, Order} from '../python.js'; -pythonGenerator.forBlock['text'] = function(block) { +pythonGenerator.forBlock['text'] = function(block, generator) { // Text value. - const code = pythonGenerator.quote_(block.getFieldValue('TEXT')); + const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; }; -pythonGenerator.forBlock['text_multiline'] = function(block) { +pythonGenerator.forBlock['text_multiline'] = function(block, generator) { // Text value. - const code = pythonGenerator.multiline_quote_(block.getFieldValue('TEXT')); + const code = generator.multiline_quote_(block.getFieldValue('TEXT')); const order = code.indexOf('+') !== -1 ? Order.ADDITIVE : Order.ATOMIC; return [code, order]; @@ -50,7 +50,7 @@ const forceString = function(value) { return ['str(' + value + ')', Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['text_join'] = function(block) { +pythonGenerator.forBlock['text_join'] = function(block, generator) { // Create a string made up of any number of elements of any type. // Should we allow joining by '-' or ',' or any other characters? switch (block.itemCount_) { @@ -58,15 +58,15 @@ pythonGenerator.forBlock['text_join'] = function(block) { return ["''", Order.ATOMIC]; case 1: { const element = - pythonGenerator.valueToCode(block, 'ADD0', Order.NONE) || "''"; + generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; const codeAndOrder = forceString(element); return codeAndOrder; } case 2: { const element0 = - pythonGenerator.valueToCode(block, 'ADD0', Order.NONE) || "''"; + generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; const element1 = - pythonGenerator.valueToCode(block, 'ADD1', Order.NONE) || "''"; + generator.valueToCode(block, 'ADD1', Order.NONE) || "''"; const code = forceString(element0)[0] + ' + ' + forceString(element1)[0]; return [code, Order.ADDITIVE]; } @@ -74,10 +74,10 @@ pythonGenerator.forBlock['text_join'] = function(block) { const elements = []; for (let i = 0; i < block.itemCount_; i++) { elements[i] = - pythonGenerator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; + generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } const tempVar = - pythonGenerator.nameDB_.getDistinctName('x', NameType.VARIABLE); + generator.nameDB_.getDistinctName('x', NameType.VARIABLE); const code = '\'\'.join([str(' + tempVar + ') for ' + tempVar + ' in [' + elements.join(', ') + ']])'; return [code, Order.FUNCTION_CALL]; @@ -85,36 +85,36 @@ pythonGenerator.forBlock['text_join'] = function(block) { } }; -pythonGenerator.forBlock['text_append'] = function(block) { +pythonGenerator.forBlock['text_append'] = function(block, generator) { // Append to a variable in place. const varName = - pythonGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); - const value = pythonGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const value = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return varName + ' = str(' + varName + ') + ' + forceString(value)[0] + '\n'; }; -pythonGenerator.forBlock['text_length'] = function(block) { +pythonGenerator.forBlock['text_length'] = function(block, generator) { // Is the string null or array empty? - const text = pythonGenerator.valueToCode(block, 'VALUE', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return ['len(' + text + ')', Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['text_isEmpty'] = function(block) { +pythonGenerator.forBlock['text_isEmpty'] = function(block, generator) { // Is the string null or array empty? - const text = pythonGenerator.valueToCode(block, 'VALUE', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; const code = 'not len(' + text + ')'; return [code, Order.LOGICAL_NOT]; }; -pythonGenerator.forBlock['text_indexOf'] = function(block) { +pythonGenerator.forBlock['text_indexOf'] = function(block, generator) { // Search the text for a substring. // Should we allow for non-case sensitive??? const operator = block.getFieldValue('END') === 'FIRST' ? 'find' : 'rfind'; const substring = - pythonGenerator.valueToCode(block, 'FIND', Order.NONE) || "''"; + generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const text = - pythonGenerator.valueToCode(block, 'VALUE', Order.MEMBER) || "''"; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || "''"; const code = text + '.' + operator + '(' + substring + ')'; if (block.workspace.options.oneBasedIndex) { return [code + ' + 1', Order.ADDITIVE]; @@ -122,13 +122,13 @@ pythonGenerator.forBlock['text_indexOf'] = function(block) { return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['text_charAt'] = function(block) { +pythonGenerator.forBlock['text_charAt'] = function(block, generator) { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. const where = block.getFieldValue('WHERE') || 'FROM_START'; const textOrder = (where === 'RANDOM') ? Order.NONE : Order.MEMBER; - const text = pythonGenerator.valueToCode(block, 'VALUE', textOrder) || "''"; + const text = generator.valueToCode(block, 'VALUE', textOrder) || "''"; switch (where) { case 'FIRST': { const code = text + '[0]'; @@ -139,20 +139,20 @@ pythonGenerator.forBlock['text_charAt'] = function(block) { return [code, Order.MEMBER]; } case 'FROM_START': { - const at = pythonGenerator.getAdjustedInt(block, 'AT'); + const at = generator.getAdjustedInt(block, 'AT'); const code = text + '[' + at + ']'; return [code, Order.MEMBER]; } case 'FROM_END': { - const at = pythonGenerator.getAdjustedInt(block, 'AT', 1, true); + const at = generator.getAdjustedInt(block, 'AT', 1, true); const code = text + '[' + at + ']'; return [code, Order.MEMBER]; } case 'RANDOM': { - pythonGenerator.definitions_['import_random'] = 'import random'; + generator.definitions_['import_random'] = 'import random'; const functionName = - pythonGenerator.provideFunction_('text_random_letter', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(text): + generator.provideFunction_('text_random_letter', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(text): x = int(random.random() * len(text)) return text[x] `); @@ -163,22 +163,22 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(text): throw Error('Unhandled option (text_charAt).'); }; -pythonGenerator.forBlock['text_getSubstring'] = function(block) { +pythonGenerator.forBlock['text_getSubstring'] = function(block, generator) { // Get substring. const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); const text = - pythonGenerator.valueToCode(block, 'STRING', Order.MEMBER) || "''"; + generator.valueToCode(block, 'STRING', Order.MEMBER) || "''"; let at1; switch (where1) { case 'FROM_START': - at1 = pythonGenerator.getAdjustedInt(block, 'AT1'); + at1 = generator.getAdjustedInt(block, 'AT1'); if (at1 === 0) { at1 = ''; } break; case 'FROM_END': - at1 = pythonGenerator.getAdjustedInt(block, 'AT1', 1, true); + at1 = generator.getAdjustedInt(block, 'AT1', 1, true); break; case 'FIRST': at1 = ''; @@ -190,14 +190,14 @@ pythonGenerator.forBlock['text_getSubstring'] = function(block) { let at2; switch (where2) { case 'FROM_START': - at2 = pythonGenerator.getAdjustedInt(block, 'AT2', 1); + at2 = generator.getAdjustedInt(block, 'AT2', 1); break; case 'FROM_END': - at2 = pythonGenerator.getAdjustedInt(block, 'AT2', 0, true); + at2 = generator.getAdjustedInt(block, 'AT2', 0, true); // Ensure that if the result calculated is 0 that sub-sequence will // include all elements as expected. if (!stringUtils.isNumber(String(at2))) { - pythonGenerator.definitions_['import_sys'] = 'import sys'; + generator.definitions_['import_sys'] = 'import sys'; at2 += ' or sys.maxsize'; } else if (at2 === 0) { at2 = ''; @@ -213,7 +213,7 @@ pythonGenerator.forBlock['text_getSubstring'] = function(block) { return [code, Order.MEMBER]; }; -pythonGenerator.forBlock['text_changeCase'] = function(block) { +pythonGenerator.forBlock['text_changeCase'] = function(block, generator) { // Change capitalization. const OPERATORS = { 'UPPERCASE': '.upper()', @@ -221,12 +221,12 @@ pythonGenerator.forBlock['text_changeCase'] = function(block) { 'TITLECASE': '.title()' }; const operator = OPERATORS[block.getFieldValue('CASE')]; - const text = pythonGenerator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; + const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; const code = text + operator; return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['text_trim'] = function(block) { +pythonGenerator.forBlock['text_trim'] = function(block, generator) { // Trim spaces. const OPERATORS = { 'LEFT': '.lstrip()', @@ -234,21 +234,21 @@ pythonGenerator.forBlock['text_trim'] = function(block) { 'BOTH': '.strip()' }; const operator = OPERATORS[block.getFieldValue('MODE')]; - const text = pythonGenerator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; + const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; const code = text + operator; return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['text_print'] = function(block) { +pythonGenerator.forBlock['text_print'] = function(block, generator) { // Print statement. - const msg = pythonGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'print(' + msg + ')\n'; }; -pythonGenerator.forBlock['text_prompt_ext'] = function(block) { +pythonGenerator.forBlock['text_prompt_ext'] = function(block, generator) { // Prompt function. - const functionName = pythonGenerator.provideFunction_('text_prompt', ` -def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(msg): + const functionName = generator.provideFunction_('text_prompt', ` +def ${generator.FUNCTION_NAME_PLACEHOLDER_}(msg): try: return raw_input(msg) except NameError: @@ -257,10 +257,10 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(msg): let msg; if (block.getField('TEXT')) { // Internal message. - msg = pythonGenerator.quote_(block.getFieldValue('TEXT')); + msg = generator.quote_(block.getFieldValue('TEXT')); } else { // External message. - msg = pythonGenerator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; } let code = functionName + '(' + msg + ')'; const toNumber = block.getFieldValue('TYPE') === 'NUMBER'; @@ -273,23 +273,23 @@ def ${pythonGenerator.FUNCTION_NAME_PLACEHOLDER_}(msg): pythonGenerator.forBlock['text_prompt'] = pythonGenerator.forBlock['text_prompt_ext']; -pythonGenerator.forBlock['text_count'] = function(block) { - const text = pythonGenerator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; - const sub = pythonGenerator.valueToCode(block, 'SUB', Order.NONE) || "''"; +pythonGenerator.forBlock['text_count'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; + const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; const code = text + '.count(' + sub + ')'; return [code, Order.FUNCTION_CALL]; }; -pythonGenerator.forBlock['text_replace'] = function(block) { - const text = pythonGenerator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; - const from = pythonGenerator.valueToCode(block, 'FROM', Order.NONE) || "''"; - const to = pythonGenerator.valueToCode(block, 'TO', Order.NONE) || "''"; +pythonGenerator.forBlock['text_replace'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; + const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; + const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; const code = text + '.replace(' + from + ', ' + to + ')'; return [code, Order.MEMBER]; }; -pythonGenerator.forBlock['text_reverse'] = function(block) { - const text = pythonGenerator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; +pythonGenerator.forBlock['text_reverse'] = function(block, generator) { + const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; const code = text + '[::-1]'; return [code, Order.MEMBER]; }; diff --git a/generators/python/variables.js b/generators/python/variables.js index e49a3deca..872bf3dbb 100644 --- a/generators/python/variables.js +++ b/generators/python/variables.js @@ -15,20 +15,20 @@ import {NameType} from '../../core/names.js'; import {pythonGenerator, Order} from '../python.js'; -pythonGenerator.forBlock['variables_get'] = function(block) { +pythonGenerator.forBlock['variables_get'] = function(block, generator) { // Variable getter. const code = - pythonGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return [code, Order.ATOMIC]; }; -pythonGenerator.forBlock['variables_set'] = function(block) { +pythonGenerator.forBlock['variables_set'] = function(block, generator) { // Variable setter. const argument0 = - pythonGenerator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; const varName = - pythonGenerator.nameDB_.getName( + generator.nameDB_.getName( block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' = ' + argument0 + '\n'; }; diff --git a/generators/python/variables_dynamic.js b/generators/python/variables_dynamic.js index 7b27314be..1925fc5a9 100644 --- a/generators/python/variables_dynamic.js +++ b/generators/python/variables_dynamic.js @@ -15,6 +15,6 @@ import {pythonGenerator} from '../python.js'; import './variables.js'; -// pythonGenerator is dynamically typed. +// generator is dynamically typed. pythonGenerator.forBlock['variables_get_dynamic'] = pythonGenerator.forBlock['variables_get']; pythonGenerator.forBlock['variables_set_dynamic'] = pythonGenerator.forBlock['variables_set'];