From 9fec824aa0b829dc8942d92e33ce82c298d31f44 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Mon, 13 Nov 2023 13:26:50 +0000 Subject: [PATCH 1/9] refactor(generators): Migrate dart_generator.js to TypeScript --- .../{php_generator.js => php_generator.ts} | 209 +++++++++--------- 1 file changed, 109 insertions(+), 100 deletions(-) rename generators/php/{php_generator.js => php_generator.ts} (62%) diff --git a/generators/php/php_generator.js b/generators/php/php_generator.ts similarity index 62% rename from generators/php/php_generator.js rename to generators/php/php_generator.ts index dfe6f854359..b955b902cc5 100644 --- a/generators/php/php_generator.js +++ b/generators/php/php_generator.ts @@ -5,71 +5,67 @@ */ /** - * @fileoverview Helper functions for generating PHP for blocks. - * @suppress {checkTypes|globalThis} + * @file PHP code generator class, including helper methods for + * generating PHP for blocks. */ // Former goog.module ID: Blockly.PHP import * as stringUtils from '../../core/utils/string.js'; -// import type {Block} from '../../core/block.js'; +import type {Block} from '../../core/block.js'; import {CodeGenerator} from '../../core/generator.js'; import {Names} from '../../core/names.js'; -// import type {Workspace} from '../../core/workspace.js'; +import type {Workspace} from '../../core/workspace.js'; import {inputTypes} from '../../core/inputs/input_types.js'; /** * Order of operation ENUMs. * http://php.net/manual/en/language.operators.precedence.php - * @enum {number} */ -export const Order = { - ATOMIC: 0, // 0 "" ... - CLONE: 1, // clone - NEW: 1, // new - MEMBER: 2.1, // [] - FUNCTION_CALL: 2.2, // () - POWER: 3, // ** - INCREMENT: 4, // ++ - DECREMENT: 4, // -- - BITWISE_NOT: 4, // ~ - CAST: 4, // (int) (float) (string) (array) ... - SUPPRESS_ERROR: 4, // @ - INSTANCEOF: 5, // instanceof - LOGICAL_NOT: 6, // ! - UNARY_PLUS: 7.1, // + - UNARY_NEGATION: 7.2, // - - MULTIPLICATION: 8.1, // * - DIVISION: 8.2, // / - MODULUS: 8.3, // % - ADDITION: 9.1, // + - SUBTRACTION: 9.2, // - - STRING_CONCAT: 9.3, // . - BITWISE_SHIFT: 10, // << >> - RELATIONAL: 11, // < <= > >= - EQUALITY: 12, // == != === !== <> <=> - REFERENCE: 13, // & - BITWISE_AND: 13, // & - BITWISE_XOR: 14, // ^ - BITWISE_OR: 15, // | - LOGICAL_AND: 16, // && - LOGICAL_OR: 17, // || - IF_NULL: 18, // ?? - CONDITIONAL: 19, // ?: - ASSIGNMENT: 20, // = += -= *= /= %= <<= >>= ... - LOGICAL_AND_WEAK: 21, // and - LOGICAL_XOR: 22, // xor - LOGICAL_OR_WEAK: 23, // or - NONE: 99, // (...) -}; +export enum Order { + ATOMIC = 0, // 0 "" ... + CLONE = 1, // clone + NEW = 1, // new + MEMBER = 2.1, // [] + FUNCTION_CALL = 2.2, // () + POWER = 3, // ** + INCREMENT = 4, // ++ + DECREMENT = 4, // -- + BITWISE_NOT = 4, // ~ + CAST = 4, // (int) (float) (string) (array) ... + SUPPRESS_ERROR = 4, // @ + INSTANCEOF = 5, // instanceof + LOGICAL_NOT = 6, // ! + UNARY_PLUS = 7.1, // + + UNARY_NEGATION = 7.2, // - + MULTIPLICATION = 8.1, // * + DIVISION = 8.2, // / + MODULUS = 8.3, // % + ADDITION = 9.1, // + + SUBTRACTION = 9.2, // - + STRING_CONCAT = 9.3, // . + BITWISE_SHIFT = 10, // << >> + RELATIONAL = 11, // < <= > >= + EQUALITY = 12, // == != === !== <> <=> + REFERENCE = 13, // & + BITWISE_AND = 13, // & + BITWISE_XOR = 14, // ^ + BITWISE_OR = 15, // | + LOGICAL_AND = 16, // && + LOGICAL_OR = 17, // || + IF_NULL = 18, // ?? + CONDITIONAL = 19, // ?: + ASSIGNMENT = 20, // = += -= *= /= %= <<= >>= ... + LOGICAL_AND_WEAK = 21, // and + LOGICAL_XOR = 22, // xor + LOGICAL_OR_WEAK = 23, // or + NONE = 99, // (...) +} export class PhpGenerator extends CodeGenerator { - /** - * List of outer-inner pairings that do NOT require parentheses. - * @type {!Array>} - */ - ORDER_OVERRIDES = [ + /** List of outer-inner pairings that do NOT require parentheses. */ + ORDER_OVERRIDES: [Order, Order][] = [ // (foo()).bar() -> foo().bar() // (foo())[0] -> foo()[0] [Order.MEMBER, Order.FUNCTION_CALL], @@ -88,8 +84,9 @@ export class PhpGenerator extends CodeGenerator { [Order.LOGICAL_OR, Order.LOGICAL_OR] ]; - constructor(name) { - super(name ?? 'PHP'); + /** @param name Name of the language the generator is for. */ + constructor(name = 'PHP') { + super(name); this.isInitialized = false; // Copy Order values onto instance for backwards compatibility @@ -100,7 +97,16 @@ export class PhpGenerator extends CodeGenerator { // replace data properties with get accessors that call // deprecate.warn().) for (const key in Order) { - this['ORDER_' + key] = Order[key]; + // Must assign Order[key] to a temporary to get the type guard to work; + // see https://github.com/microsoft/TypeScript/issues/10530. + const value = Order[key]; + // Skip reverse-lookup entries in the enum. Due to + // https://github.com/microsoft/TypeScript/issues/55713 this (as + // of TypeScript 5.5.2) actually narrows the type of value to + // never - but that still allows the following assignment to + // succeed. + if (typeof value === 'string') continue; + (this as unknown as Record)['ORDER_' + key] = value; } // List of illegal variable names. This is not intended to be a @@ -134,9 +140,10 @@ export class PhpGenerator extends CodeGenerator { /** * Initialise the database of variable names. - * @param {!Workspace} workspace Workspace to generate code from. + * + * @param workspace Workspace to generate code from. */ - init(workspace) { + init(workspace: Workspace) { super.init(workspace); if (!this.nameDB_) { @@ -154,37 +161,40 @@ export class PhpGenerator extends CodeGenerator { /** * Prepend the generated code with the variable definitions. - * @param {string} code Generated code. - * @return {string} Completed code. + * + * @param code Generated code. + * @returns Completed code. */ - finish(code) { + finish(code: string): string { // Convert the definitions dictionary into a list. const definitions = Object.values(this.definitions_); // Call Blockly.CodeGenerator's finish. code = super.finish(code); this.isInitialized = false; - this.nameDB_.reset(); + this.nameDB_!.reset(); return definitions.join('\n\n') + '\n\n\n' + code; }; /** * Naked values are top-level blocks with outputs that aren't plugged into - * anything. A trailing semicolon is needed to make this legal. - * @param {string} line Line of generated code. - * @return {string} Legal line of code. + * anything. + * + * @param line Line of generated code. + * @returns Legal line of code. */ - scrubNakedValue(line) { + scrubNakedValue(line: string): string { return line + ';\n'; }; /** * Encode a string as a properly escaped PHP string, complete with * quotes. - * @param {string} string Text to encode. - * @return {string} PHP string. + * + * @param string Text to encode. + * @returns PHP string. */ - quote_(string) { + quote_(string: string): string { string = string.replace(/\\/g, '\\\\') .replace(/\n/g, '\\\n') .replace(/'/g, '\\\''); @@ -194,10 +204,10 @@ export class PhpGenerator extends CodeGenerator { /** * Encode a string as a properly escaped multiline PHP string, complete with * quotes. - * @param {string} string Text to encode. - * @return {string} PHP string. + * @param string Text to encode. + * @returns PHP string. */ - multiline_quote_(string) { + multiline_quote_(string: string): string { const lines = string.split(/\n/g).map(this.quote_); // Join with the following, plus a newline: // . "\n" . @@ -209,14 +219,13 @@ export class PhpGenerator extends CodeGenerator { * Common tasks for generating PHP from blocks. * Handles comments for the specified block and any connected value blocks. * Calls any statements following this block. - * @param {!Block} block The current block. - * @param {string} code The PHP code created for this block. - * @param {boolean=} opt_thisOnly True to generate code for only this - * statement. - * @return {string} PHP code with comments and subsequent blocks added. - * @protected + * + * @param block The current block. + * @param code The PHP code created for this block. + * @param thisOnly True to generate code for only this statement. + * @returns PHP code with comments and subsequent blocks added. */ - scrub_(block, code, opt_thisOnly) { + scrub_(block: Block, code: string, thisOnly = false): string { let commentCode = ''; // Only collect comments for blocks that aren't inline. if (!block.outputConnection || !block.outputConnection.targetConnection) { @@ -230,7 +239,7 @@ export class PhpGenerator extends CodeGenerator { // Don't collect comments for nested statements. for (let i = 0; i < block.inputList.length; i++) { if (block.inputList[i].type === inputTypes.VALUE) { - const childBlock = block.inputList[i].connection.targetBlock(); + const childBlock = block.inputList[i].connection!.targetBlock(); if (childBlock) { comment = this.allNestedComments(childBlock); if (comment) { @@ -242,45 +251,45 @@ export class PhpGenerator extends CodeGenerator { } const nextBlock = block.nextConnection && block.nextConnection.targetBlock(); - const nextCode = opt_thisOnly ? '' : this.blockToCode(nextBlock); + const nextCode = thisOnly ? '' : this.blockToCode(nextBlock); return commentCode + code + nextCode; }; /** * Gets a property and adjusts the value while taking into account indexing. - * @param {!Block} block The block. - * @param {string} atId The property ID of the element to get. - * @param {number=} opt_delta Value to add. - * @param {boolean=} opt_negate Whether to negate the value. - * @param {number=} opt_order The highest order acting on this value. - * @return {string|number} + * + * @param block The block. + * @param atId The ID of the input block to get (and adjust) the value of. + * @param delta Value to add. + * @param negate Whether to negate the value. + * @param order The highest order acting on this value. + * @returns The adjusted value. */ - getAdjusted(block, atId, opt_delta, opt_negate, opt_order) { - let delta = opt_delta || 0; - let order = opt_order || this.ORDER_NONE; + getAdjusted(block: Block, atId: string, delta = 0, negate = false, order = Order.NONE): string | number { if (block.workspace.options.oneBasedIndex) { delta--; } let defaultAtIndex = block.workspace.options.oneBasedIndex ? '1' : '0'; - let outerOrder = order; - let innerOrder; + let outerOrder: Order = order; + let innerOrder: Order | undefined; if (delta > 0) { - outerOrder = this.ORDER_ADDITION; - innerOrder = this.ORDER_ADDITION; + outerOrder = Order.ADDITION; + innerOrder = Order.ADDITION; } else if (delta < 0) { - outerOrder = this.ORDER_SUBTRACTION; - innerOrder = this.ORDER_SUBTRACTION; - } else if (opt_negate) { - outerOrder = this.ORDER_UNARY_NEGATION; - innerOrder = this.ORDER_UNARY_NEGATION; + outerOrder = Order.SUBTRACTION; + innerOrder = Order.SUBTRACTION; + } else if (negate) { + outerOrder = Order.UNARY_NEGATION; + innerOrder = Order.UNARY_NEGATION; } + let at = this.valueToCode(block, atId, outerOrder) || defaultAtIndex; if (stringUtils.isNumber(at)) { // If the index is a naked number, adjust it right now. - at = Number(at) + delta; - if (opt_negate) { - at = -at; + at = String(Number(at) + delta); + if (negate) { + at = String(-Number(at)); } } else { // If the index is dynamic, adjust it in code. @@ -289,14 +298,14 @@ export class PhpGenerator extends CodeGenerator { } else if (delta < 0) { at = at + ' - ' + -delta; } - if (opt_negate) { + if (negate) { if (delta) { at = '-(' + at + ')'; } else { at = '-' + at; } } - innerOrder = Math.floor(innerOrder); + innerOrder = innerOrder === undefined ? NaN : Math.floor(innerOrder); order = Math.floor(order); if (innerOrder && order >= innerOrder) { at = '(' + at + ')'; From bae0d63c38869a86087993f727c2b35aaa57c20a Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Mon, 13 Nov 2023 15:47:59 +0000 Subject: [PATCH 2/9] refactor(generators): Simplify getAdjusted Slightly simplify the implementation of getAdjusted, in part to make it more readable. Also improve its JSDoc comment. --- generators/php/php_generator.ts | 59 ++++++++++++++++----------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/generators/php/php_generator.ts b/generators/php/php_generator.ts index b955b902cc5..e7d1bb7460d 100644 --- a/generators/php/php_generator.ts +++ b/generators/php/php_generator.ts @@ -256,7 +256,9 @@ export class PhpGenerator extends CodeGenerator { }; /** - * Gets a property and adjusts the value while taking into account indexing. + * Generate code representing the specified value input, adjusted to take into + * account indexing (zero- or one-based) and optionally by a specified delta + * and/or by negation. * * @param block The block. * @param atId The ID of the input block to get (and adjust) the value of. @@ -270,46 +272,41 @@ export class PhpGenerator extends CodeGenerator { delta--; } let defaultAtIndex = block.workspace.options.oneBasedIndex ? '1' : '0'; - let outerOrder: Order = order; - let innerOrder: Order | undefined; + + let orderForInput = order; if (delta > 0) { - outerOrder = Order.ADDITION; - innerOrder = Order.ADDITION; + orderForInput = Order.ADDITION; } else if (delta < 0) { - outerOrder = Order.SUBTRACTION; - innerOrder = Order.SUBTRACTION; + orderForInput = Order.SUBTRACTION; } else if (negate) { - outerOrder = Order.UNARY_NEGATION; - innerOrder = Order.UNARY_NEGATION; + orderForInput = Order.UNARY_NEGATION; } - let at = this.valueToCode(block, atId, outerOrder) || defaultAtIndex; + let at = this.valueToCode(block, atId, orderForInput) || defaultAtIndex; - if (stringUtils.isNumber(at)) { - // If the index is a naked number, adjust it right now. + // Easy case: no adjustments. + if (delta === 0 && !negate) { + return at; + } + // If the index is a naked number, adjust it right now. + if (stringUtils.isNumber(at)) { at = String(Number(at) + delta); if (negate) { at = String(-Number(at)); } - } else { - // If the index is dynamic, adjust it in code. - if (delta > 0) { - at = at + ' + ' + delta; - } else if (delta < 0) { - at = at + ' - ' + -delta; - } - if (negate) { - if (delta) { - at = '-(' + at + ')'; - } else { - at = '-' + at; - } - } - innerOrder = innerOrder === undefined ? NaN : Math.floor(innerOrder); - order = Math.floor(order); - if (innerOrder && order >= innerOrder) { - at = '(' + at + ')'; - } + return at; + } + // If the index is dynamic, adjust it in code. + if (delta > 0) { + at = `${at} + ${delta}`; + } else if (delta < 0) { + at = `${at} - ${-delta}`; + } + if (negate) { + at = delta ? `-(${at})` : `-${at}`; + } + if (Math.floor(order) >= Math.floor(orderForInput)) { + at = `(${at})`; } return at; }; From 86a2e7271f8a22b24270b73b923ccd24d8b68c95 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Mon, 13 Nov 2023 15:40:27 +0000 Subject: [PATCH 3/9] refactor(generators): Migrate generators/php/* to TypeScript First pass doing very mechanistic migration, not attempting to fix all the resulting type errors. --- generators/php/{colour.js => colour.ts} | 10 +++--- generators/php/{lists.js => lists.ts} | 26 +++++++------- generators/php/{logic.js => logic.ts} | 16 +++++---- generators/php/{loops.js => loops.ts} | 12 ++++--- generators/php/{math.js => math.ts} | 26 +++++++------- .../php/{procedures.js => procedures.ts} | 10 +++--- generators/php/{text.js => text.ts} | 34 ++++++++++--------- generators/php/{variables.js => variables.ts} | 6 ++-- ...iables_dynamic.js => variables_dynamic.ts} | 0 9 files changed, 78 insertions(+), 62 deletions(-) rename generators/php/{colour.js => colour.ts} (85%) rename generators/php/{lists.js => lists.ts} (93%) rename generators/php/{logic.js => logic.ts} (84%) rename generators/php/{loops.js => loops.ts} (92%) rename generators/php/{math.js => math.ts} (90%) rename generators/php/{procedures.js => procedures.ts} (90%) rename generators/php/{text.js => text.ts} (84%) rename generators/php/{variables.js => variables.ts} (70%) rename generators/php/{variables_dynamic.js => variables_dynamic.ts} (100%) diff --git a/generators/php/colour.js b/generators/php/colour.ts similarity index 85% rename from generators/php/colour.js rename to generators/php/colour.ts index e15cc385c38..9fa6625f05d 100644 --- a/generators/php/colour.js +++ b/generators/php/colour.ts @@ -10,16 +10,18 @@ // Former goog.module ID: Blockly.PHP.colour +import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; -export function colour_picker(block, generator) { +export function colour_picker(block: Block, generator: PhpGenerator): [string, Order] { // Colour picker. const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; }; -export function colour_random(block, generator) { +export function colour_random(block: Block, generator: PhpGenerator): [string, Order] { // Generate a random colour. const functionName = generator.provideFunction_('colour_random', ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}() { @@ -30,7 +32,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}() { return [code, Order.FUNCTION_CALL]; }; -export function colour_rgb(block, generator) { +export function colour_rgb(block: Block, generator: PhpGenerator): [string, Order] { // Compose a colour from RGB components expressed as percentages. const red = generator.valueToCode(block, 'RED', Order.NONE) || 0; const green = generator.valueToCode(block, 'GREEN', Order.NONE) || 0; @@ -51,7 +53,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($r, $g, $b) { return [code, Order.FUNCTION_CALL]; }; -export function colour_blend(block, generator) { +export function colour_blend(block: Block, generator: PhpGenerator): [string, Order] { // Blend two colours together. const c1 = generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; diff --git a/generators/php/lists.js b/generators/php/lists.ts similarity index 93% rename from generators/php/lists.js rename to generators/php/lists.ts index d2d5a084200..6cd5487f9ea 100644 --- a/generators/php/lists.js +++ b/generators/php/lists.ts @@ -22,15 +22,17 @@ // Former goog.module ID: Blockly.generator.lists import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; -export function lists_create_empty(block, generator) { +export function lists_create_empty(block: Block, generator: PhpGenerator): [string, Order] { // Create an empty list. return ['array()', Order.FUNCTION_CALL]; }; -export function lists_create_with(block, generator) { +export function lists_create_with(block: Block, generator: PhpGenerator): [string, Order] { // 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++) { @@ -40,7 +42,7 @@ export function lists_create_with(block, generator) { return [code, Order.FUNCTION_CALL]; }; -export function lists_repeat(block, generator) { +export function lists_repeat(block: Block, generator: PhpGenerator): [string, Order] { // Create a list with one element repeated. const functionName = generator.provideFunction_('lists_repeat', ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { @@ -57,7 +59,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { return [code, Order.FUNCTION_CALL]; }; -export function lists_length(block, generator) { +export function lists_length(block: Block, generator: PhpGenerator): [string, Order] { // String or array length. const functionName = generator.provideFunction_('length', ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { @@ -72,7 +74,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { return [functionName + '(' + list + ')', Order.FUNCTION_CALL]; }; -export function lists_isEmpty(block, generator) { +export function lists_isEmpty(block: Block, generator: PhpGenerator): [string, Order] { // Is the string null or array empty? const argument0 = generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) @@ -80,7 +82,7 @@ export function lists_isEmpty(block, generator) { return ['empty(' + argument0 + ')', Order.FUNCTION_CALL]; }; -export function lists_indexOf(block, generator) { +export function lists_indexOf(block: Block, generator: PhpGenerator): [string, Order] { // Find an item in the list. const argument0 = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const argument1 = @@ -119,7 +121,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { return [code, Order.FUNCTION_CALL]; }; -export function lists_getIndex(block, generator) { +export function lists_getIndex(block: Block, generator: PhpGenerator): [string, Order] | string { // Get element at index. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; @@ -236,7 +238,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { throw Error('Unhandled combination (lists_getIndex).'); }; -export function lists_setIndex(block, generator) { +export function lists_setIndex(block: Block, generator: PhpGenerator) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; @@ -340,7 +342,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { throw Error('Unhandled combination (lists_setIndex).'); }; -export function lists_getSublist(block, generator) { +export function lists_getSublist(block: Block, generator: PhpGenerator): [string, Order] { // Get sublist. const list = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; const where1 = block.getFieldValue('WHERE1'); @@ -440,7 +442,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $where1, $at1, $where2, return [code, Order.FUNCTION_CALL]; }; -export function lists_sort(block, generator) { +export function lists_sort(block: Block, generator: PhpGenerator): [string, Order] { // Block for sorting a list. const listCode = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; @@ -467,7 +469,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $type, $direction) { return [sortCode, Order.FUNCTION_CALL]; }; -export function lists_split(block, generator) { +export function lists_split(block: Block, generator: PhpGenerator): [string, Order] { // Block for splitting text into a list, or joining a list into text. let value_input = generator.valueToCode(block, 'INPUT', Order.NONE); const value_delim = @@ -491,7 +493,7 @@ export function lists_split(block, generator) { return [code, Order.FUNCTION_CALL]; }; -export function lists_reverse(block, generator) { +export function lists_reverse(block: Block, generator: PhpGenerator): [string, Order] { // Block for reversing a list. const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; const code = 'array_reverse(' + list + ')'; diff --git a/generators/php/logic.js b/generators/php/logic.ts similarity index 84% rename from generators/php/logic.js rename to generators/php/logic.ts index 0968c1ea40f..3204d23e80f 100644 --- a/generators/php/logic.js +++ b/generators/php/logic.ts @@ -10,10 +10,12 @@ // Former goog.module ID: Blockly.PHP.logic +import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; -export function controls_if(block, generator) { +export function controls_if(block: Block, generator: PhpGenerator) { // If/elseif/else condition. let n = 0; let code = '', branchCode, conditionCode; @@ -53,7 +55,7 @@ export function controls_if(block, generator) { export const controls_ifelse = controls_if; -export function logic_compare(block, generator) { +export function logic_compare(block: Block, generator: PhpGenerator): [string, Order] { // Comparison operator. const OPERATORS = {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; @@ -66,7 +68,7 @@ export function logic_compare(block, generator) { return [code, order]; }; -export function logic_operation(block, generator) { +export function logic_operation(block: Block, generator: PhpGenerator): [string, Order] { // Operations 'and', 'or'. const operator = (block.getFieldValue('OP') === 'AND') ? '&&' : '||'; const order = @@ -91,7 +93,7 @@ export function logic_operation(block, generator) { return [code, order]; }; -export function logic_negate(block, generator) { +export function logic_negate(block: Block, generator: PhpGenerator): [string, Order] { // Negation. const order = Order.LOGICAL_NOT; const argument0 = generator.valueToCode(block, 'BOOL', order) || 'true'; @@ -99,18 +101,18 @@ export function logic_negate(block, generator) { return [code, order]; }; -export function logic_boolean(block, generator) { +export function logic_boolean(block: Block, generator: PhpGenerator): [string, Order] { // Boolean values true and false. const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'true' : 'false'; return [code, Order.ATOMIC]; }; -export function logic_null(block, generator) { +export function logic_null(block: Block, generator: PhpGenerator): [string, Order] { // Null data type. return ['null', Order.ATOMIC]; }; -export function logic_ternary(block, generator) { +export function logic_ternary(block: Block, generator: PhpGenerator): [string, Order] { // Ternary operator. const value_if = generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; diff --git a/generators/php/loops.js b/generators/php/loops.ts similarity index 92% rename from generators/php/loops.js rename to generators/php/loops.ts index 981a4e219cf..f15054ba7e0 100644 --- a/generators/php/loops.js +++ b/generators/php/loops.ts @@ -11,11 +11,13 @@ // Former goog.module ID: Blockly.PHP.loops import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; -export function controls_repeat_ext(block, generator) { +export function controls_repeat_ext(block: Block, generator: PhpGenerator) { // Repeat n times. let repeats; if (block.getField('TIMES')) { @@ -43,7 +45,7 @@ export function controls_repeat_ext(block, generator) { export const controls_repeat = controls_repeat_ext; -export function controls_whileUntil(block, generator) { +export function controls_whileUntil(block: Block, generator: PhpGenerator) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; let argument0 = @@ -58,7 +60,7 @@ export function controls_whileUntil(block, generator) { return 'while (' + argument0 + ') {\n' + branch + '}\n'; }; -export function controls_for(block, generator) { +export function controls_for(block: Block, generator: PhpGenerator) { // For loop. const variable0 = generator.getVariableName(block.getFieldValue('VAR')); @@ -123,7 +125,7 @@ export function controls_for(block, generator) { return code; }; -export function controls_forEach(block, generator) { +export function controls_forEach(block: Block, generator: PhpGenerator) { // For each loop. const variable0 = generator.getVariableName(block.getFieldValue('VAR')); @@ -137,7 +139,7 @@ export function controls_forEach(block, generator) { return code; }; -export function controls_flow_statements(block, generator) { +export function controls_flow_statements(block: Block, generator: PhpGenerator) { // Flow statements: continue, break. let xfix = ''; if (generator.STATEMENT_PREFIX) { diff --git a/generators/php/math.js b/generators/php/math.ts similarity index 90% rename from generators/php/math.js rename to generators/php/math.ts index f1985949ea8..2db997498e9 100644 --- a/generators/php/math.js +++ b/generators/php/math.ts @@ -10,10 +10,12 @@ // Former goog.module ID: Blockly.PHP.math +import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; -export function math_number(block, generator) { +export function math_number(block: Block, generator: PhpGenerator): [string, Order] { // Numeric value. let code = Number(block.getFieldValue('NUM')); const order = code >= 0 ? Order.ATOMIC : Order.UNARY_NEGATION; @@ -25,7 +27,7 @@ export function math_number(block, generator) { return [code, order]; }; -export function math_arithmetic(block, generator) { +export function math_arithmetic(block: Block, generator: PhpGenerator): [string, Order] { // Basic arithmetic operators, and power. const OPERATORS = { 'ADD': [' + ', Order.ADDITION], @@ -43,7 +45,7 @@ export function math_arithmetic(block, generator) { return [code, order]; }; -export function math_single(block, generator) { +export function math_single(block: Block, generator: PhpGenerator): [string, Order] { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; @@ -124,7 +126,7 @@ export function math_single(block, generator) { return [code, Order.DIVISION]; }; -export function math_constant(block, generator) { +export function math_constant(block: Block, generator: PhpGenerator): [string, Order] { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. const CONSTANTS = { 'PI': ['M_PI', Order.ATOMIC], @@ -137,7 +139,7 @@ export function math_constant(block, generator) { return CONSTANTS[block.getFieldValue('CONSTANT')]; }; -export function math_number_property(block, generator) { +export function math_number_property(block: Block, generator: PhpGenerator): [string, Order] { // 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 = { @@ -192,7 +194,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($n) { return [code, outputOrder]; }; -export function math_change(block, generator) { +export function math_change(block: Block, generator: PhpGenerator) { // Add to a variable in place. const argument0 = generator.valueToCode(block, 'DELTA', Order.ADDITION) || '0'; @@ -206,7 +208,7 @@ export const math_round = math_single; // Trigonometry functions have a single operand. export const math_trig = math_single; -export function math_on_list(block, generator) { +export function math_on_list(block: Block, generator: PhpGenerator): [string, Order] { // Math functions for lists. const func = block.getFieldValue('OP'); let list; @@ -301,7 +303,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { return [code, Order.FUNCTION_CALL]; }; -export function math_modulo(block, generator) { +export function math_modulo(block: Block, generator: PhpGenerator): [string, Order] { // Remainder computation. const argument0 = generator.valueToCode(block, 'DIVIDEND', Order.MODULUS) || '0'; @@ -311,7 +313,7 @@ export function math_modulo(block, generator) { return [code, Order.MODULUS]; }; -export function math_constrain(block, generator) { +export function math_constrain(block: Block, generator: PhpGenerator): [string, Order] { // Constrain a number between two limits. const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'LOW', Order.NONE) || '0'; @@ -322,7 +324,7 @@ export function math_constrain(block, generator) { return [code, Order.FUNCTION_CALL]; }; -export function math_random_int(block, generator) { +export function math_random_int(block: Block, generator: PhpGenerator): [string, Order] { // Random integer between [X] and [Y]. const argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; @@ -338,12 +340,12 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($a, $b) { return [code, Order.FUNCTION_CALL]; }; -export function math_random_float(block, generator) { +export function math_random_float(block: Block, generator: PhpGenerator): [string, Order] { // Random fraction between 0 and 1. return ['(float)rand()/(float)getrandmax()', Order.FUNCTION_CALL]; }; -export function math_atan2(block, generator) { +export function math_atan2(block: Block, generator: PhpGenerator): [string, Order] { // Arctangent of point (X, Y) in degrees from -180 to 180. const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; diff --git a/generators/php/procedures.js b/generators/php/procedures.ts similarity index 90% rename from generators/php/procedures.js rename to generators/php/procedures.ts index f261ec919fe..27b5a10f38a 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.ts @@ -11,11 +11,13 @@ // Former goog.module ID: Blockly.PHP.procedures import * as Variables from '../../core/variables.js'; +import type {Block} from '../../core/block.js'; import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; -export function procedures_defreturn(block, generator) { +export function procedures_defreturn(block: Block, generator: PhpGenerator) { // Define a procedure with a return value. // First, add a 'global' statement for every variable that is not shadowed by // a local parameter. @@ -85,7 +87,7 @@ export function procedures_defreturn(block, generator) { // a procedure with a return value. export const procedures_defnoreturn = procedures_defreturn; -export function procedures_callreturn(block, generator) { +export function procedures_callreturn(block: Block, generator: PhpGenerator): [string, Order] { // Call a procedure with a return value. const funcName = generator.getProcedureName(block.getFieldValue('NAME')); @@ -98,7 +100,7 @@ export function procedures_callreturn(block, generator) { return [code, Order.FUNCTION_CALL]; }; -export function procedures_callnoreturn(block, generator) { +export function procedures_callnoreturn(block: Block, generator: PhpGenerator) { // 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. @@ -106,7 +108,7 @@ export function procedures_callnoreturn(block, generator) { return tuple[0] + ';\n'; }; -export function procedures_ifreturn(block, generator) { +export function procedures_ifreturn(block: Block, generator: PhpGenerator) { // Conditionally return value from a procedure. const condition = generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; diff --git a/generators/php/text.js b/generators/php/text.ts similarity index 84% rename from generators/php/text.js rename to generators/php/text.ts index b5941315be2..f3176808b38 100644 --- a/generators/php/text.js +++ b/generators/php/text.ts @@ -10,16 +10,18 @@ // Former goog.module ID: Blockly.PHP.texts +import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; -export function text(block, generator) { +export function text(block: Block, generator: PhpGenerator): [string, Order] { // Text value. const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; }; -export function text_multiline(block, generator) { +export function text_multiline(block: Block, generator: PhpGenerator): [string, Order] { // Text value. const code = generator.multiline_quote_(block.getFieldValue('TEXT')); const order = @@ -27,7 +29,7 @@ export function text_multiline(block, generator) { return [code, order]; }; -export function text_join(block, generator) { +export function text_join(block: Block, generator: PhpGenerator): [string, Order] { // Create a string made up of any number of elements of any type. if (block.itemCount_ === 0) { return ["''", Order.ATOMIC]; @@ -53,7 +55,7 @@ export function text_join(block, generator) { } }; -export function text_append(block, generator) { +export function text_append(block: Block, generator: PhpGenerator) { // Append to a variable in place. const varName = generator.getVariableName(block.getFieldValue('VAR')); @@ -62,7 +64,7 @@ export function text_append(block, generator) { return varName + ' .= ' + value + ';\n'; }; -export function text_length(block, generator) { +export function text_length(block: Block, generator: PhpGenerator): [string, Order] { // String or array length. const functionName = generator.provideFunction_('length', ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { @@ -76,13 +78,13 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { return [functionName + '(' + text + ')', Order.FUNCTION_CALL]; }; -export function text_isEmpty(block, generator) { +export function text_isEmpty(block: Block, generator: PhpGenerator): [string, Order] { // Is the string null or array empty? const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return ['empty(' + text + ')', Order.FUNCTION_CALL]; }; -export function text_indexOf(block, generator) { +export function text_indexOf(block: Block, generator: PhpGenerator): [string, Order] { // Search the text for a substring. const operator = block.getFieldValue('END') === 'FIRST' ? 'strpos' : 'strrpos'; @@ -107,7 +109,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text, $search) { return [code, Order.FUNCTION_CALL]; }; -export function text_charAt(block, generator) { +export function text_charAt(block: Block, generator: PhpGenerator): [string, Order] { // Get letter at index. const where = block.getFieldValue('WHERE') || 'FROM_START'; const textOrder = (where === 'RANDOM') ? Order.NONE : Order.NONE; @@ -144,7 +146,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text) { throw Error('Unhandled option (text_charAt).'); }; -export function text_getSubstring(block, generator) { +export function text_getSubstring(block: Block, generator: PhpGenerator): [string, Order] { // Get substring. const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); @@ -183,7 +185,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text, $where1, $at1, $where2, } }; -export function text_changeCase(block, generator) { +export function text_changeCase(block: Block, generator: PhpGenerator): [string, Order] { // Change capitalization. const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; let code; @@ -197,7 +199,7 @@ export function text_changeCase(block, generator) { return [code, Order.FUNCTION_CALL]; }; -export function text_trim(block, generator) { +export function text_trim(block: Block, generator: PhpGenerator): [string, Order] { // Trim spaces. const OPERATORS = {'LEFT': 'ltrim', 'RIGHT': 'rtrim', 'BOTH': 'trim'}; const operator = OPERATORS[block.getFieldValue('MODE')]; @@ -205,13 +207,13 @@ export function text_trim(block, generator) { return [operator + '(' + text + ')', Order.FUNCTION_CALL]; }; -export function text_print(block, generator) { +export function text_print(block: Block, generator: PhpGenerator) { // Print statement. const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'print(' + msg + ');\n'; }; -export function text_prompt_ext(block, generator) { +export function text_prompt_ext(block: Block, generator: PhpGenerator): [string, Order] { // Prompt function. let msg; if (block.getField('TEXT')) { @@ -231,7 +233,7 @@ export function text_prompt_ext(block, generator) { export const text_prompt = text_prompt_ext; -export function text_count(block, generator) { +export function text_count(block: Block, generator: PhpGenerator): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; const code = 'strlen(' + sub + ') === 0' + @@ -240,7 +242,7 @@ export function text_count(block, generator) { return [code, Order.CONDITIONAL]; }; -export function text_replace(block, generator) { +export function text_replace(block: Block, generator: PhpGenerator): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; @@ -248,7 +250,7 @@ export function text_replace(block, generator) { return [code, Order.FUNCTION_CALL]; }; -export function text_reverse(block, generator) { +export function text_reverse(block: Block, generator: PhpGenerator): [string, Order] { 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.ts similarity index 70% rename from generators/php/variables.js rename to generators/php/variables.ts index 50429fa9b3b..e6f18634646 100644 --- a/generators/php/variables.js +++ b/generators/php/variables.ts @@ -10,17 +10,19 @@ // Former goog.module ID: Blockly.PHP.variables +import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; -export function variables_get(block, generator) { +export function variables_get(block: Block, generator: PhpGenerator): [string, Order] { // Variable getter. const code = generator.getVariableName(block.getFieldValue('VAR')); return [code, Order.ATOMIC]; }; -export function variables_set(block, generator) { +export function variables_set(block: Block, generator: PhpGenerator) { // Variable setter. const argument0 = generator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; diff --git a/generators/php/variables_dynamic.js b/generators/php/variables_dynamic.ts similarity index 100% rename from generators/php/variables_dynamic.js rename to generators/php/variables_dynamic.ts From e2100ebdd9d9707c5db4b88515bef79503ec1f95 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Mon, 13 Nov 2023 16:43:46 +0000 Subject: [PATCH 4/9] fix(generators): Fix type errors in generator functions This consists almost entirely of adding casts, so the code output by tsc should be as similar as possible to the pre-migration .js source files. --- generators/php/lists.ts | 28 +++++++++++++++++++--------- generators/php/logic.ts | 3 ++- generators/php/loops.ts | 15 ++++++++------- generators/php/math.ts | 28 +++++++++++++++------------- generators/php/procedures.ts | 11 +++++++---- generators/php/text.ts | 17 ++++++++++------- 6 files changed, 61 insertions(+), 41 deletions(-) diff --git a/generators/php/lists.ts b/generators/php/lists.ts index 6cd5487f9ea..ae1810dda99 100644 --- a/generators/php/lists.ts +++ b/generators/php/lists.ts @@ -23,6 +23,7 @@ import * as stringUtils from '../../core/utils/string.js'; import type {Block} from '../../core/block.js'; +import type {CreateWithBlock} from '../../blocks/lists.js'; import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; @@ -34,11 +35,12 @@ export function lists_create_empty(block: Block, generator: PhpGenerator): [stri export function lists_create_with(block: Block, generator: PhpGenerator): [string, Order] { // 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] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; + const createWithBlock = block as CreateWithBlock; + const elements = new Array(createWithBlock.itemCount_); + for (let i = 0; i < createWithBlock.itemCount_; i++) { + elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; } - code = 'array(' + code.join(', ') + ')'; + const code = 'array(' + elements.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; }; @@ -247,13 +249,13 @@ export function lists_setIndex(block: Block, generator: PhpGenerator) { 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; + let cachedList: string; function cacheList() { if (cachedList.match(/^\$\w+$/)) { return ''; } const listVar = - generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + generator.nameDB_!.getDistinctName('tmp_list', NameType.VARIABLE); const code = listVar + ' = &' + cachedList + ';\n'; cachedList = listVar; return code; @@ -328,7 +330,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { let code = cacheList(); const list = cachedList; const xVar = - generator.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'; @@ -344,9 +346,17 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { export function lists_getSublist(block: Block, generator: PhpGenerator): [string, Order] { // Get sublist. + // Dictionary of WHEREn field choices and their CamelCase equivalents. + const wherePascalCase = { + 'FIRST': 'First', + 'LAST': 'Last', + 'FROM_START': 'FromStart', + 'FROM_END': 'FromEnd', + }; + type WhereOption = keyof typeof wherePascalCase; const list = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; - const where1 = block.getFieldValue('WHERE1'); - const where2 = block.getFieldValue('WHERE2'); + const where1 = block.getFieldValue('WHERE1') as WhereOption; + const where2 = block.getFieldValue('WHERE2') as WhereOption; let code; if (where1 === 'FIRST' && where2 === 'LAST') { code = list; diff --git a/generators/php/logic.ts b/generators/php/logic.ts index 3204d23e80f..26282f2b653 100644 --- a/generators/php/logic.ts +++ b/generators/php/logic.ts @@ -59,7 +59,8 @@ export function logic_compare(block: Block, generator: PhpGenerator): [string, O // Comparison operator. const OPERATORS = {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; - const operator = OPERATORS[block.getFieldValue('OP')]; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('OP') as OperatorOption]; const order = (operator === '==' || operator === '!=') ? Order.EQUALITY : Order.RELATIONAL; const argument0 = generator.valueToCode(block, 'A', order) || '0'; diff --git a/generators/php/loops.ts b/generators/php/loops.ts index f15054ba7e0..fb0075c4b9b 100644 --- a/generators/php/loops.ts +++ b/generators/php/loops.ts @@ -12,6 +12,7 @@ import * as stringUtils from '../../core/utils/string.js'; import type {Block} from '../../core/block.js'; +import type {ControlFlowInLoopBlock} from '../../blocks/loops.js'; import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; @@ -31,11 +32,11 @@ export function controls_repeat_ext(block: Block, generator: PhpGenerator) { branch = generator.addLoopTrap(branch, block); let code = ''; const loopVar = - generator.nameDB_.getDistinctName('count', NameType.VARIABLE); + generator.nameDB_!.getDistinctName('count', NameType.VARIABLE); let endVar = repeats; if (!repeats.match(/^\w+$/) && !stringUtils.isNumber(repeats)) { endVar = - generator.nameDB_.getDistinctName('repeat_end', NameType.VARIABLE); + generator.nameDB_!.getDistinctName('repeat_end', NameType.VARIABLE); code += endVar + ' = ' + repeats + ';\n'; } code += 'for (' + loopVar + ' = 0; ' + loopVar + ' < ' + endVar + '; ' + @@ -92,25 +93,25 @@ export function controls_for(block: Block, generator: PhpGenerator) { let startVar = argument0; if (!argument0.match(/^\w+$/) && !stringUtils.isNumber(argument0)) { startVar = - generator.nameDB_.getDistinctName( + generator.nameDB_!.getDistinctName( variable0 + '_start', NameType.VARIABLE); code += startVar + ' = ' + argument0 + ';\n'; } let endVar = argument1; if (!argument1.match(/^\w+$/) && !stringUtils.isNumber(argument1)) { endVar = - generator.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 = - generator.nameDB_.getDistinctName( + generator.nameDB_!.getDistinctName( variable0 + '_inc', NameType.VARIABLE); code += incVar + ' = '; if (stringUtils.isNumber(increment)) { - code += Math.abs(increment) + ';\n'; + code += Math.abs(Number(increment)) + ';\n'; } else { code += 'abs(' + increment + ');\n'; } @@ -152,7 +153,7 @@ export function controls_flow_statements(block: Block, generator: PhpGenerator) xfix += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (generator.STATEMENT_PREFIX) { - const loop = block.getSurroundLoop(); + const loop = (block as ControlFlowInLoopBlock).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. diff --git a/generators/php/math.ts b/generators/php/math.ts index 2db997498e9..dceef557fb3 100644 --- a/generators/php/math.ts +++ b/generators/php/math.ts @@ -17,26 +17,26 @@ import type {PhpGenerator} from './php_generator.js'; export function math_number(block: Block, generator: PhpGenerator): [string, Order] { // Numeric value. - let code = Number(block.getFieldValue('NUM')); - const order = code >= 0 ? Order.ATOMIC : Order.UNARY_NEGATION; - if (code === Infinity) { - code = 'INF'; - } else if (code === -Infinity) { - code = '-INF'; + let number = Number(block.getFieldValue('NUM')); + if (number === Infinity) { + return ['INF', Order.ATOMIC]; + } else if (number === -Infinity) { + return ['-INF', Order.UNARY_NEGATION]; } - return [code, order]; + return [String(number), number >= 0 ? Order.ATOMIC : Order.UNARY_NEGATION]; }; export function math_arithmetic(block: Block, generator: PhpGenerator): [string, Order] { // Basic arithmetic operators, and power. - const OPERATORS = { + const OPERATORS: Record = { 'ADD': [' + ', Order.ADDITION], 'MINUS': [' - ', Order.SUBTRACTION], 'MULTIPLY': [' * ', Order.MULTIPLICATION], 'DIVIDE': [' / ', Order.DIVISION], 'POWER': [' ** ', Order.POWER], }; - const tuple = OPERATORS[block.getFieldValue('OP')]; + type OperatorOption = keyof typeof OPERATORS; + const tuple = OPERATORS[block.getFieldValue('OP') as OperatorOption]; const operator = tuple[0]; const order = tuple[1]; const argument0 = generator.valueToCode(block, 'A', order) || '0'; @@ -128,7 +128,7 @@ export function math_single(block: Block, generator: PhpGenerator): [string, Ord export function math_constant(block: Block, generator: PhpGenerator): [string, Order] { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. - const CONSTANTS = { + const CONSTANTS: Record = { 'PI': ['M_PI', Order.ATOMIC], 'E': ['M_E', Order.ATOMIC], 'GOLDEN_RATIO': ['(1 + sqrt(5)) / 2', Order.DIVISION], @@ -136,13 +136,14 @@ export function math_constant(block: Block, generator: PhpGenerator): [string, O 'SQRT1_2': ['M_SQRT1_2', Order.ATOMIC], 'INFINITY': ['INF', Order.ATOMIC], }; - return CONSTANTS[block.getFieldValue('CONSTANT')]; + type ConstantOption = keyof typeof CONSTANTS + return CONSTANTS[block.getFieldValue('CONSTANT') as ConstantOption]; }; export function math_number_property(block: Block, generator: PhpGenerator): [string, Order] { // 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 = { + const PROPERTIES: Record = { 'EVEN': ['', ' % 2 == 0', Order.MODULUS, Order.EQUALITY], 'ODD': ['', ' % 2 == 1', Order.MODULUS, Order.EQUALITY], 'WHOLE': ['is_int(', ')', Order.NONE, Order.FUNCTION_CALL], @@ -151,7 +152,8 @@ export function math_number_property(block: Block, generator: PhpGenerator): [st 'DIVISIBLE_BY': [null, null, Order.MODULUS, Order.EQUALITY], 'PRIME': [null, null, Order.NONE, Order.FUNCTION_CALL], }; - const dropdownProperty = block.getFieldValue('PROPERTY'); + type PropertyOption = keyof typeof PROPERTIES; + const dropdownProperty = block.getFieldValue('PROPERTY') as PropertyOption; const [prefix, suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty]; const numberToCheck = generator.valueToCode(block, 'NUMBER_TO_CHECK', diff --git a/generators/php/procedures.ts b/generators/php/procedures.ts index 27b5a10f38a..e4731ddc805 100644 --- a/generators/php/procedures.ts +++ b/generators/php/procedures.ts @@ -12,6 +12,7 @@ import * as Variables from '../../core/variables.js'; import type {Block} from '../../core/block.js'; +import type {IfReturnBlock} from '../../blocks/procedures.js'; import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; @@ -35,7 +36,7 @@ export function procedures_defreturn(block: Block, generator: PhpGenerator) { const devVarList = Variables.allDeveloperVariables(workspace); for (let i = 0; i < devVarList.length; i++) { globals.push( - generator.nameDB_.getName( + generator.nameDB_!.getName( devVarList[i], NameType.DEVELOPER_VARIABLE)); } const globalStr = @@ -79,7 +80,9 @@ export function procedures_defreturn(block: Block, generator: PhpGenerator) { globalStr + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - generator.definitions_['%' + funcName] = code; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['%' + funcName] = code; return null; }; @@ -104,7 +107,7 @@ export function procedures_callnoreturn(block: Block, generator: PhpGenerator) { // 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 = generator.forBlock['procedures_callreturn'](block, generator); + const tuple = generator.forBlock['procedures_callreturn'](block, generator) as [string, Order]; return tuple[0] + ';\n'; }; @@ -121,7 +124,7 @@ export function procedures_ifreturn(block: Block, generator: PhpGenerator) { generator.injectId(generator.STATEMENT_SUFFIX, block), generator.INDENT); } - if (block.hasReturnValue_) { + if ((block as IfReturnBlock).hasReturnValue_) { const value = generator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; code += generator.INDENT + 'return ' + value + ';\n'; } else { diff --git a/generators/php/text.ts b/generators/php/text.ts index f3176808b38..c1eb9f74aaf 100644 --- a/generators/php/text.ts +++ b/generators/php/text.ts @@ -11,6 +11,7 @@ // Former goog.module ID: Blockly.PHP.texts import type {Block} from '../../core/block.js'; +import type {JoinMutatorBlock} from '../../blocks/text.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; @@ -31,13 +32,14 @@ export function text_multiline(block: Block, generator: PhpGenerator): [string, export function text_join(block: Block, generator: PhpGenerator): [string, Order] { // Create a string made up of any number of elements of any type. - if (block.itemCount_ === 0) { + const joinBlock = block as JoinMutatorBlock; + if (joinBlock.itemCount_ === 0) { return ["''", Order.ATOMIC]; - } else if (block.itemCount_ === 1) { + } else if (joinBlock.itemCount_ === 1) { const element = generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; const code = element; return [code, Order.NONE]; - } else if (block.itemCount_ === 2) { + } else if (joinBlock.itemCount_ === 2) { const element0 = generator.valueToCode(block, 'ADD0', Order.STRING_CONCAT) || "''"; const element1 = @@ -45,8 +47,8 @@ export function text_join(block: Block, generator: PhpGenerator): [string, Order const code = element0 + ' . ' + element1; return [code, Order.STRING_CONCAT]; } else { - const elements = new Array(block.itemCount_); - for (let i = 0; i < block.itemCount_; i++) { + const elements = new Array(joinBlock.itemCount_); + for (let i = 0; i < joinBlock.itemCount_; i++) { elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } @@ -196,13 +198,14 @@ export function text_changeCase(block: Block, generator: PhpGenerator): [string, } else if (block.getFieldValue('CASE') === 'TITLECASE') { code = 'ucwords(strtolower(' + text + '))'; } - return [code, Order.FUNCTION_CALL]; + return [code as string, Order.FUNCTION_CALL]; }; export function text_trim(block: Block, generator: PhpGenerator): [string, Order] { // Trim spaces. const OPERATORS = {'LEFT': 'ltrim', 'RIGHT': 'rtrim', 'BOTH': 'trim'}; - const operator = OPERATORS[block.getFieldValue('MODE')]; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('MODE') as OperatorOption]; const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return [operator + '(' + text + ')', Order.FUNCTION_CALL]; }; From 40ede09bb0ad0ef8947d85f18c31138dd56c41ce Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Mon, 13 Nov 2023 19:20:45 +0000 Subject: [PATCH 5/9] fix(generators): Fix more minor inconsistencies in JS and Python The migration of the JavaScript and Python generators inadvertently introduced some inconsistencies in the code, e.g. putting executable code before the initial comment line that most generator functions begin with. This fixes another instance of this (but n.b. that these inline comments should have been JSDocs and a task has been added to #7600 to convert them). Additionally, I noticed while doing the PHP migration that ORDER_OVERRIDES was not typed as specifically as it could be, in previous migrations, so this is fixed here (along with the formatting of the associated JSDoc, which can fit on one line now.) --- generators/javascript/javascript_generator.ts | 6 ++---- generators/javascript/lists.ts | 2 +- generators/python/python_generator.ts | 6 ++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/generators/javascript/javascript_generator.ts b/generators/javascript/javascript_generator.ts index 547b7daf7d1..8d3b6158d9e 100644 --- a/generators/javascript/javascript_generator.ts +++ b/generators/javascript/javascript_generator.ts @@ -66,10 +66,8 @@ export enum Order { * JavaScript code generator class. */ export class JavascriptGenerator extends CodeGenerator { - /** - * List of outer-inner pairings that do NOT require parentheses. - */ - ORDER_OVERRIDES: number[][] = [ + /** List of outer-inner pairings that do NOT require parentheses. */ + ORDER_OVERRIDES: [Order, Order][] = [ // (foo()).bar -> foo().bar // (foo())[0] -> foo()[0] [Order.FUNCTION_CALL, Order.MEMBER], diff --git a/generators/javascript/lists.ts b/generators/javascript/lists.ts index 6283f1d274b..e3170cc9733 100644 --- a/generators/javascript/lists.ts +++ b/generators/javascript/lists.ts @@ -303,6 +303,7 @@ export function lists_getSublist( block: Block, generator: JavascriptGenerator, ): [string, Order] { + // Get sublist. // Dictionary of WHEREn field choices and their CamelCase equivalents. const wherePascalCase = { 'FIRST': 'First', @@ -311,7 +312,6 @@ export function lists_getSublist( 'FROM_END': 'FromEnd', }; type WhereOption = keyof typeof wherePascalCase; - // Get sublist. const list = generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; const where1 = block.getFieldValue('WHERE1') as WhereOption; const where2 = block.getFieldValue('WHERE2') as WhereOption; diff --git a/generators/python/python_generator.ts b/generators/python/python_generator.ts index 5e5daf9f2e8..f4bef167761 100644 --- a/generators/python/python_generator.ts +++ b/generators/python/python_generator.ts @@ -52,10 +52,8 @@ export enum Order { * PythonScript code generator class. */ export class PythonGenerator extends CodeGenerator { - /** - * List of outer-inner pairings that do NOT require parentheses. - */ - ORDER_OVERRIDES: number[][] = [ + /** List of outer-inner pairings that do NOT require parentheses. */ + ORDER_OVERRIDES: [Order, Order][] = [ // (foo()).bar -> foo().bar // (foo())[0] -> foo()[0] [Order.FUNCTION_CALL, Order.MEMBER], From 5d0ac545eb4231e423d66a308475a1880aad9b68 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Mon, 13 Nov 2023 19:21:33 +0000 Subject: [PATCH 6/9] refactor(generators): Migrate generators/php.js to TypeScript The way the generator functions are added to phpGenerator.forBlock has been modified so that incorrect generator function signatures will cause tsc to generate a type error. --- generators/{php.js => php.ts} | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) rename generators/{php.js => php.ts} (79%) diff --git a/generators/php.js b/generators/php.ts similarity index 79% rename from generators/php.js rename to generators/php.ts index f61daccf7cb..cfddf64ec62 100644 --- a/generators/php.js +++ b/generators/php.ts @@ -32,8 +32,10 @@ export * from './php/php_generator.js'; export const phpGenerator = new PhpGenerator(); // Install per-block-type generator functions: -Object.assign( - phpGenerator.forBlock, - colour, lists, logic, loops, math, procedures, - text, variables, variablesDynamic -); +const generators: typeof phpGenerator.forBlock = { + ...colour, ...lists, ...logic, ...loops, ...math, + ...procedures, ...text, ...variables, ...variablesDynamic +}; +for (const name in generators) { + phpGenerator.forBlock[name] = generators[name]; +} From 5c3afa3d87155e29de711ebddb842b5e85573e6b Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Mon, 13 Nov 2023 19:24:22 +0000 Subject: [PATCH 7/9] chore(generator): Format One block protected with // prettier-ignore to preserve careful comment formatting. Where there are repeated concatenations prettier has made a pretty mess of things, but the correct fix is probably to use template literals instead (rather than just locally disabling prettier). This is one of the items in the to-do list in #7600. --- generators/php.ts | 11 +- generators/php/colour.ts | 56 ++++-- generators/php/lists.ts | 296 ++++++++++++++++++---------- generators/php/logic.ts | 105 ++++++---- generators/php/loops.ts | 135 ++++++++----- generators/php/math.ts | 172 ++++++++++------ generators/php/php_generator.ts | 79 ++++---- generators/php/procedures.ts | 65 +++--- generators/php/text.ts | 181 +++++++++++------ generators/php/variables.ts | 18 +- generators/php/variables_dynamic.ts | 1 - 11 files changed, 719 insertions(+), 400 deletions(-) diff --git a/generators/php.ts b/generators/php.ts index cfddf64ec62..66d8a3d292a 100644 --- a/generators/php.ts +++ b/generators/php.ts @@ -33,8 +33,15 @@ export const phpGenerator = new PhpGenerator(); // Install per-block-type generator functions: const generators: typeof phpGenerator.forBlock = { - ...colour, ...lists, ...logic, ...loops, ...math, - ...procedures, ...text, ...variables, ...variablesDynamic + ...colour, + ...lists, + ...logic, + ...loops, + ...math, + ...procedures, + ...text, + ...variables, + ...variablesDynamic, }; for (const name in generators) { phpGenerator.forBlock[name] = generators[name]; diff --git a/generators/php/colour.ts b/generators/php/colour.ts index 9fa6625f05d..2c4acd74586 100644 --- a/generators/php/colour.ts +++ b/generators/php/colour.ts @@ -14,30 +14,43 @@ import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; - -export function colour_picker(block: Block, generator: PhpGenerator): [string, Order] { +export function colour_picker( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Colour picker. const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; -}; +} -export function colour_random(block: Block, generator: PhpGenerator): [string, Order] { +export function colour_random( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Generate a random colour. - const functionName = generator.provideFunction_('colour_random', ` + const functionName = generator.provideFunction_( + 'colour_random', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}() { return '#' . str_pad(dechex(mt_rand(0, 0xFFFFFF)), 6, '0', STR_PAD_LEFT); } -`); +`, + ); const code = functionName + '()'; return [code, Order.FUNCTION_CALL]; -}; +} -export function colour_rgb(block: Block, generator: PhpGenerator): [string, Order] { +export function colour_rgb( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Compose a colour from RGB components expressed as percentages. 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', ` + 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); @@ -48,19 +61,23 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($r, $g, $b) { $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT); return $hex; } -`); +`, + ); const code = functionName + '(' + red + ', ' + green + ', ' + blue + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function colour_blend(block: Block, generator: PhpGenerator): [string, Order] { +export function colour_blend( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Blend two colours together. - const c1 = - generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; - const c2 = - generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; + const c1 = generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; + const c2 = generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; const ratio = generator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; - const functionName = generator.provideFunction_('colour_blend', ` + 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)); @@ -78,7 +95,8 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($c1, $c2, $ratio) { $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT); return $hex; } -`); +`, + ); const code = functionName + '(' + c1 + ', ' + c2 + ', ' + ratio + ')'; return [code, Order.FUNCTION_CALL]; -}; +} diff --git a/generators/php/lists.ts b/generators/php/lists.ts index ae1810dda99..32347ae2aeb 100644 --- a/generators/php/lists.ts +++ b/generators/php/lists.ts @@ -28,12 +28,18 @@ import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; -export function lists_create_empty(block: Block, generator: PhpGenerator): [string, Order] { +export function lists_create_empty( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Create an empty list. return ['array()', Order.FUNCTION_CALL]; -}; +} -export function lists_create_with(block: Block, generator: PhpGenerator): [string, Order] { +export function lists_create_with( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Create a list with any number of elements of any type. const createWithBlock = block as CreateWithBlock; const elements = new Array(createWithBlock.itemCount_); @@ -42,11 +48,16 @@ export function lists_create_with(block: Block, generator: PhpGenerator): [strin } const code = 'array(' + elements.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_repeat(block: Block, generator: PhpGenerator): [string, Order] { +export function lists_repeat( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Create a list with one element repeated. - const functionName = generator.provideFunction_('lists_repeat', ` + const functionName = generator.provideFunction_( + 'lists_repeat', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { $array = array(); for ($index = 0; $index < $count; $index++) { @@ -54,16 +65,22 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { } return $array; } -`); +`, + ); 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]; -}; +} -export function lists_length(block: Block, generator: PhpGenerator): [string, Order] { +export function lists_length( + block: Block, + generator: PhpGenerator, +): [string, Order] { // String or array length. - const functionName = generator.provideFunction_('length', ` + const functionName = generator.provideFunction_( + 'length', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { if (is_string($value)) { return strlen($value); @@ -71,24 +88,29 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { return count($value); } } -`); +`, + ); const list = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return [functionName + '(' + list + ')', Order.FUNCTION_CALL]; -}; +} -export function lists_isEmpty(block: Block, generator: PhpGenerator): [string, Order] { +export function lists_isEmpty( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Is the string null or array empty? const argument0 = - generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) - || 'array()'; + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || 'array()'; return ['empty(' + argument0 + ')', Order.FUNCTION_CALL]; -}; +} -export function lists_indexOf(block: Block, generator: PhpGenerator): [string, Order] { +export function lists_indexOf( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Find an item in the list. const argument0 = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; - const argument1 = - generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; + const argument1 = generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; let errorIndex = ' -1'; let indexAdjustment = ''; if (block.workspace.options.oneBasedIndex) { @@ -98,17 +120,22 @@ export function lists_indexOf(block: Block, generator: PhpGenerator): [string, O let functionName; if (block.getFieldValue('END') === 'FIRST') { // indexOf - functionName = generator.provideFunction_('indexOf', ` + 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}; } return ${errorIndex}; } -`); +`, + ); } else { // lastIndexOf - functionName = generator.provideFunction_('lastIndexOf', ` + functionName = generator.provideFunction_( + 'lastIndexOf', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { $last = ${errorIndex}; for ($index = 0; $index < count($haystack); $index++) { @@ -116,14 +143,18 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { } return $last; } -`); +`, + ); } const code = functionName + '(' + argument1 + ', ' + argument0 + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_getIndex(block: Block, generator: PhpGenerator): [string, Order] | string { +export function lists_getIndex( + block: Block, + generator: PhpGenerator, +): [string, Order] | string { // Get element at index. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; @@ -131,34 +162,34 @@ export function lists_getIndex(block: Block, generator: PhpGenerator): [string, case 'FIRST': if (mode === 'GET') { const list = - generator.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 = - generator.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 = - generator.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 = - generator.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 = - generator.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 = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; return 'array_pop(' + list + ');\n'; } break; @@ -166,17 +197,17 @@ export function lists_getIndex(block: Block, generator: PhpGenerator): [string, const at = generator.getAdjusted(block, 'AT'); if (mode === 'GET') { const list = - generator.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 = - generator.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 = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; return 'array_splice(' + list + ', ' + at + ', 1);\n'; } break; @@ -184,17 +215,22 @@ export function lists_getIndex(block: Block, generator: PhpGenerator): [string, case 'FROM_END': if (mode === 'GET') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + 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 = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; - const at = - generator.getAdjusted(block, 'AT', 1, false, Order.SUBTRACTION); - const code = 'array_splice(' + list + ', count(' + list + ') - ' + at + - ', 1)[0]'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + const at = generator.getAdjusted( + block, + 'AT', + 1, + false, + Order.SUBTRACTION, + ); + const code = + 'array_splice(' + list + ', count(' + list + ') - ' + at + ', 1)[0]'; if (mode === 'GET_REMOVE') { return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { @@ -204,49 +240,54 @@ export function lists_getIndex(block: Block, generator: PhpGenerator): [string, break; case 'RANDOM': { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; if (mode === 'GET') { - const functionName = - generator.provideFunction_('lists_get_random_item', ` + const functionName = generator.provideFunction_( + 'lists_get_random_item', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { return $list[rand(0,count($list)-1)]; } -`); +`, + ); const code = functionName + '(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'GET_REMOVE') { - const functionName = - generator.provideFunction_('lists_get_remove_random_item', ` + const functionName = 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); } -`); +`, + ); const code = functionName + '(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { - const functionName = - generator.provideFunction_('lists_remove_random_item', ` + const functionName = generator.provideFunction_( + 'lists_remove_random_item', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { unset($list[rand(0,count($list)-1)]); } -`); +`, + ); return functionName + '(' + list + ');\n'; } break; } } throw Error('Unhandled combination (lists_getIndex).'); -}; +} export function lists_setIndex(block: Block, generator: PhpGenerator) { // 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 = - generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; + const value = 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: string; @@ -254,8 +295,10 @@ export function lists_setIndex(block: Block, generator: PhpGenerator) { if (cachedList.match(/^\$\w+$/)) { return ''; } - const listVar = - generator.nameDB_!.getDistinctName('tmp_list', NameType.VARIABLE); + const listVar = generator.nameDB_!.getDistinctName( + 'tmp_list', + NameType.VARIABLE, + ); const code = listVar + ' = &' + cachedList + ';\n'; cachedList = listVar; return code; @@ -264,24 +307,26 @@ export function lists_setIndex(block: Block, generator: PhpGenerator) { case 'FIRST': if (mode === 'SET') { const list = - generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; return list + '[0] = ' + value + ';\n'; } else if (mode === 'INSERT') { const list = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; return 'array_unshift(' + list + ', ' + value + ');\n'; } break; case 'LAST': { const list = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; if (mode === 'SET') { - const functionName = - generator.provideFunction_('lists_set_last_item', ` + const functionName = generator.provideFunction_( + 'lists_set_last_item', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $value) { $list[count($list) - 1] = $value; } -`); +`, + ); return functionName + '(' + list + ', ' + value + ');\n'; } else if (mode === 'INSERT') { return 'array_push(' + list + ', ' + value + ');\n'; @@ -292,45 +337,51 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $value) { const at = generator.getAdjusted(block, 'AT'); if (mode === 'SET') { const list = - generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; return list + '[' + at + '] = ' + value + ';\n'; } else if (mode === 'INSERT') { const list = - generator.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 = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; const at = generator.getAdjusted(block, 'AT', 1); if (mode === 'SET') { - const functionName = - generator.provideFunction_('lists_set_from_end', ` + const functionName = 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 = - generator.provideFunction_('lists_insert_from_end', ` + const functionName = generator.provideFunction_( + 'lists_insert_from_end', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { return array_splice($list, count($list) - $at, 0, $value); } -`); +`, + ); return functionName + '(' + list + ', ' + at + ', ' + value + ');\n'; } break; } case 'RANDOM': cachedList = - generator.valueToCode(block, 'LIST', Order.REFERENCE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.REFERENCE) || 'array()'; let code = cacheList(); const list = cachedList; - const xVar = - generator.nameDB_!.getDistinctName('tmp_x', NameType.VARIABLE); + const xVar = generator.nameDB_!.getDistinctName( + 'tmp_x', + NameType.VARIABLE, + ); code += xVar + ' = rand(0, count(' + list + ')-1);\n'; if (mode === 'SET') { code += list + '[' + xVar + '] = ' + value + ';\n'; @@ -342,9 +393,12 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { break; } throw Error('Unhandled combination (lists_setIndex).'); -}; +} -export function lists_getSublist(block: Block, generator: PhpGenerator): [string, Order] { +export function lists_getSublist( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Get sublist. // Dictionary of WHEREn field choices and their CamelCase equivalents. const wherePascalCase = { @@ -361,8 +415,9 @@ export function lists_getSublist(block: Block, generator: PhpGenerator): [string if (where1 === 'FIRST' && where2 === 'LAST') { code = list; } else if ( - list.match(/^\$\w+$/) || - (where1 !== 'FROM_END' && where2 === 'FROM_START')) { + list.match(/^\$\w+$/) || + (where1 !== 'FROM_END' && where2 === 'FROM_START') + ) { // If the list is a simple value or doesn't require a call for length, don't // generate a helper function. let at1; @@ -371,8 +426,7 @@ export function lists_getSublist(block: Block, generator: PhpGenerator): [string at1 = generator.getAdjusted(block, 'AT1'); break; case 'FROM_END': - at1 = - generator.getAdjusted(block, 'AT1', 1, false, Order.SUBTRACTION); + at1 = generator.getAdjusted(block, 'AT1', 1, false, Order.SUBTRACTION); at1 = 'count(' + list + ') - ' + at1; break; case 'FIRST': @@ -385,11 +439,12 @@ export function lists_getSublist(block: Block, generator: PhpGenerator): [string let length; switch (where2) { case 'FROM_START': - at2 = - generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); + at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); length = at2 + ' - '; - if (stringUtils.isNumber(String(at1)) || - String(at1).match(/^\(.+\)$/)) { + if ( + stringUtils.isNumber(String(at1)) || + String(at1).match(/^\(.+\)$/) + ) { length += at1; } else { length += '(' + at1 + ')'; @@ -397,11 +452,12 @@ export function lists_getSublist(block: Block, generator: PhpGenerator): [string length += ' + 1'; break; case 'FROM_END': - at2 = - generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); + at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); length = 'count(' + list + ') - ' + at2 + ' - '; - if (stringUtils.isNumber(String(at1)) || - String(at1).match(/^\(.+\)$/)) { + if ( + stringUtils.isNumber(String(at1)) || + String(at1).match(/^\(.+\)$/) + ) { length += at1; } else { length += '(' + at1 + ')'; @@ -409,8 +465,10 @@ export function lists_getSublist(block: Block, generator: PhpGenerator): [string break; case 'LAST': length = 'count(' + list + ') - '; - if (stringUtils.isNumber(String(at1)) || - String(at1).match(/^\(.+\)$/)) { + if ( + stringUtils.isNumber(String(at1)) || + String(at1).match(/^\(.+\)$/) + ) { length += at1; } else { length += '(' + at1 + ')'; @@ -423,8 +481,9 @@ export function lists_getSublist(block: Block, generator: PhpGenerator): [string } else { const at1 = generator.getAdjusted(block, 'AT1'); const at2 = generator.getAdjusted(block, 'AT2'); - const functionName = - generator.provideFunction_('lists_get_sublist', ` + const functionName = generator.provideFunction_( + 'lists_get_sublist', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $where1, $at1, $where2, $at2) { if ($where1 == 'FROM_END') { $at1 = count($list) - 1 - $at1; @@ -445,20 +504,37 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $where1, $at1, $where2, } return array_slice($list, $at1, $length); } -`); - code = functionName + '(' + list + ', \'' + where1 + '\', ' + at1 + ', \'' + - where2 + '\', ' + at2 + ')'; +`, + ); + code = + functionName + + '(' + + list + + ", '" + + where1 + + "', " + + at1 + + ", '" + + where2 + + "', " + + at2 + + ')'; } return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_sort(block: Block, generator: PhpGenerator): [string, Order] { +export function lists_sort( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Block for sorting a list. const listCode = - generator.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 = generator.provideFunction_('lists_sort', ` + const functionName = generator.provideFunction_( + 'lists_sort', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $type, $direction) { $sortCmpFuncs = array( 'NUMERIC' => 'strnatcasecmp', @@ -473,17 +549,20 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $type, $direction) { } return $list2; } -`); +`, + ); const sortCode = - functionName + '(' + listCode + ', "' + type + '", ' + direction + ')'; + functionName + '(' + listCode + ', "' + type + '", ' + direction + ')'; return [sortCode, Order.FUNCTION_CALL]; -}; +} -export function lists_split(block: Block, generator: PhpGenerator): [string, Order] { +export function lists_split( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Block for splitting text into a list, or joining a list into text. let value_input = generator.valueToCode(block, 'INPUT', Order.NONE); - const value_delim = - generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; + const value_delim = generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; const mode = block.getFieldValue('MODE'); let functionName; if (mode === 'SPLIT') { @@ -501,11 +580,14 @@ export function lists_split(block: Block, generator: PhpGenerator): [string, Ord } const code = functionName + '(' + value_delim + ', ' + value_input + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_reverse(block: Block, generator: PhpGenerator): [string, Order] { +export function lists_reverse( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Block for reversing a list. const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; const code = 'array_reverse(' + list + ')'; return [code, Order.FUNCTION_CALL]; -}; +} diff --git a/generators/php/logic.ts b/generators/php/logic.ts index 26282f2b653..b7c3ad2a64c 100644 --- a/generators/php/logic.ts +++ b/generators/php/logic.ts @@ -14,28 +14,34 @@ import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; - export function controls_if(block: Block, generator: PhpGenerator) { // If/elseif/else condition. let n = 0; - let code = '', branchCode, conditionCode; + let code = '', + branchCode, + conditionCode; if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. code += generator.injectId(generator.STATEMENT_PREFIX, block); } do { conditionCode = - generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; + generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; branchCode = generator.statementToCode(block, 'DO' + n); if (generator.STATEMENT_SUFFIX) { branchCode = - generator.prefixLines( - generator.injectId(generator.STATEMENT_SUFFIX, block), - generator.INDENT) + - branchCode; + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; } - code += (n > 0 ? ' else ' : '') + 'if (' + conditionCode + ') {\n' + - branchCode + '}'; + code += + (n > 0 ? ' else ' : '') + + 'if (' + + conditionCode + + ') {\n' + + branchCode + + '}'; n++; } while (block.getInput('IF' + n)); @@ -43,37 +49,48 @@ export function controls_if(block: Block, generator: PhpGenerator) { branchCode = generator.statementToCode(block, 'ELSE'); if (generator.STATEMENT_SUFFIX) { branchCode = - generator.prefixLines( - generator.injectId(generator.STATEMENT_SUFFIX, block), - generator.INDENT) + - branchCode; + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; } code += ' else {\n' + branchCode + '}'; } return code + '\n'; -}; +} export const controls_ifelse = controls_if; -export function logic_compare(block: Block, generator: PhpGenerator): [string, Order] { +export function logic_compare( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Comparison operator. - const OPERATORS = - {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; + const OPERATORS = { + 'EQ': '==', + 'NEQ': '!=', + 'LT': '<', + 'LTE': '<=', + 'GT': '>', + 'GTE': '>=', + }; type OperatorOption = keyof typeof OPERATORS; const operator = OPERATORS[block.getFieldValue('OP') as OperatorOption]; - const order = (operator === '==' || operator === '!=') ? Order.EQUALITY : - Order.RELATIONAL; + const order = + operator === '==' || operator === '!=' ? Order.EQUALITY : Order.RELATIONAL; const argument0 = generator.valueToCode(block, 'A', order) || '0'; const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; -}; +} -export function logic_operation(block: Block, generator: PhpGenerator): [string, Order] { +export function logic_operation( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Operations 'and', 'or'. - const operator = (block.getFieldValue('OP') === 'AND') ? '&&' : '||'; - const order = - (operator === '&&') ? Order.LOGICAL_AND : Order.LOGICAL_OR; + const operator = block.getFieldValue('OP') === 'AND' ? '&&' : '||'; + const order = operator === '&&' ? Order.LOGICAL_AND : Order.LOGICAL_OR; let argument0 = generator.valueToCode(block, 'A', order); let argument1 = generator.valueToCode(block, 'B', order); if (!argument0 && !argument1) { @@ -82,7 +99,7 @@ export function logic_operation(block: Block, generator: PhpGenerator): [string, argument1 = 'false'; } else { // Single missing arguments have no effect on the return value. - const defaultArgument = (operator === '&&') ? 'true' : 'false'; + const defaultArgument = operator === '&&' ? 'true' : 'false'; if (!argument0) { argument0 = defaultArgument; } @@ -92,35 +109,47 @@ export function logic_operation(block: Block, generator: PhpGenerator): [string, } const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; -}; +} -export function logic_negate(block: Block, generator: PhpGenerator): [string, Order] { +export function logic_negate( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Negation. const order = Order.LOGICAL_NOT; const argument0 = generator.valueToCode(block, 'BOOL', order) || 'true'; const code = '!' + argument0; return [code, order]; -}; +} -export function logic_boolean(block: Block, generator: PhpGenerator): [string, Order] { +export function logic_boolean( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Boolean values true and false. - const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'true' : 'false'; + const code = block.getFieldValue('BOOL') === 'TRUE' ? 'true' : 'false'; return [code, Order.ATOMIC]; -}; +} -export function logic_null(block: Block, generator: PhpGenerator): [string, Order] { +export function logic_null( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Null data type. return ['null', Order.ATOMIC]; -}; +} -export function logic_ternary(block: Block, generator: PhpGenerator): [string, Order] { +export function logic_ternary( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Ternary operator. const value_if = - generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; + generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; const value_then = - generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; + generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; const value_else = - generator.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.ts b/generators/php/loops.ts index fb0075c4b9b..24b3e002c59 100644 --- a/generators/php/loops.ts +++ b/generators/php/loops.ts @@ -17,7 +17,6 @@ import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; - export function controls_repeat_ext(block: Block, generator: PhpGenerator) { // Repeat n times. let repeats; @@ -31,18 +30,32 @@ export function controls_repeat_ext(block: Block, generator: PhpGenerator) { let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); let code = ''; - const loopVar = - generator.nameDB_!.getDistinctName('count', NameType.VARIABLE); + const loopVar = generator.nameDB_!.getDistinctName( + 'count', + NameType.VARIABLE, + ); let endVar = repeats; if (!repeats.match(/^\w+$/) && !stringUtils.isNumber(repeats)) { - endVar = - generator.nameDB_!.getDistinctName('repeat_end', NameType.VARIABLE); + endVar = generator.nameDB_!.getDistinctName( + 'repeat_end', + NameType.VARIABLE, + ); code += endVar + ' = ' + repeats + ';\n'; } - code += 'for (' + loopVar + ' = 0; ' + loopVar + ' < ' + endVar + '; ' + - loopVar + '++) {\n' + branch + '}\n'; + code += + 'for (' + + loopVar + + ' = 0; ' + + loopVar + + ' < ' + + endVar + + '; ' + + loopVar + + '++) {\n' + + branch + + '}\n'; return code; -}; +} export const controls_repeat = controls_repeat_ext; @@ -50,36 +63,47 @@ export function controls_whileUntil(block: Block, generator: PhpGenerator) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; let argument0 = - generator.valueToCode( - block, 'BOOL', until ? Order.LOGICAL_NOT : Order.NONE) || - 'false'; + generator.valueToCode( + block, + 'BOOL', + until ? Order.LOGICAL_NOT : Order.NONE, + ) || 'false'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); if (until) { argument0 = '!' + argument0; } return 'while (' + argument0 + ') {\n' + branch + '}\n'; -}; +} export function controls_for(block: Block, generator: PhpGenerator) { // For loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const argument0 = - generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; - const argument1 = - generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; - const increment = - generator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; + generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; + const argument1 = generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; + const increment = 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)) { + if ( + stringUtils.isNumber(argument0) && + stringUtils.isNumber(argument1) && + stringUtils.isNumber(increment) + ) { // All arguments are simple numbers. const up = Number(argument0) <= Number(argument1); - code = 'for (' + variable0 + ' = ' + argument0 + '; ' + variable0 + - (up ? ' <= ' : ' >= ') + argument1 + '; ' + variable0; + code = + 'for (' + + variable0 + + ' = ' + + argument0 + + '; ' + + variable0 + + (up ? ' <= ' : ' >= ') + + argument1 + + '; ' + + variable0; const step = Math.abs(Number(increment)); if (step === 1) { code += up ? '++' : '--'; @@ -92,23 +116,26 @@ export function controls_for(block: Block, generator: PhpGenerator) { // Cache non-trivial values to variables to prevent repeated look-ups. let startVar = argument0; if (!argument0.match(/^\w+$/) && !stringUtils.isNumber(argument0)) { - startVar = - generator.nameDB_!.getDistinctName( - variable0 + '_start', NameType.VARIABLE); + startVar = generator.nameDB_!.getDistinctName( + variable0 + '_start', + NameType.VARIABLE, + ); code += startVar + ' = ' + argument0 + ';\n'; } let endVar = argument1; if (!argument1.match(/^\w+$/) && !stringUtils.isNumber(argument1)) { - endVar = - generator.nameDB_!.getDistinctName( - variable0 + '_end', NameType.VARIABLE); + endVar = 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 = - generator.nameDB_!.getDistinctName( - variable0 + '_inc', NameType.VARIABLE); + const incVar = generator.nameDB_!.getDistinctName( + variable0 + '_inc', + NameType.VARIABLE, + ); code += incVar + ' = '; if (stringUtils.isNumber(increment)) { code += Math.abs(Number(increment)) + ';\n'; @@ -118,29 +145,49 @@ export function controls_for(block: Block, generator: PhpGenerator) { code += 'if (' + startVar + ' > ' + endVar + ') {\n'; code += generator.INDENT + incVar + ' = -' + incVar + ';\n'; code += '}\n'; - code += 'for (' + variable0 + ' = ' + startVar + '; ' + incVar + - ' >= 0 ? ' + variable0 + ' <= ' + endVar + ' : ' + variable0 + - ' >= ' + endVar + '; ' + variable0 + ' += ' + incVar + ') {\n' + - branch + '}\n'; + code += + 'for (' + + variable0 + + ' = ' + + startVar + + '; ' + + incVar + + ' >= 0 ? ' + + variable0 + + ' <= ' + + endVar + + ' : ' + + variable0 + + ' >= ' + + endVar + + '; ' + + variable0 + + ' += ' + + incVar + + ') {\n' + + branch + + '}\n'; } return code; -}; +} export function controls_forEach(block: Block, generator: PhpGenerator) { // For each loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const argument0 = - generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; + 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'; + 'foreach (' + argument0 + ' as ' + variable0 + ') {\n' + branch + '}\n'; return code; -}; +} -export function controls_flow_statements(block: Block, generator: PhpGenerator) { +export function controls_flow_statements( + block: Block, + generator: PhpGenerator, +) { // Flow statements: continue, break. let xfix = ''; if (generator.STATEMENT_PREFIX) { @@ -168,4 +215,4 @@ export function controls_flow_statements(block: Block, generator: PhpGenerator) return xfix + 'continue;\n'; } throw Error('Unknown flow statement.'); -}; +} diff --git a/generators/php/math.ts b/generators/php/math.ts index dceef557fb3..811c6da8591 100644 --- a/generators/php/math.ts +++ b/generators/php/math.ts @@ -14,8 +14,10 @@ import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; - -export function math_number(block: Block, generator: PhpGenerator): [string, Order] { +export function math_number( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Numeric value. let number = Number(block.getFieldValue('NUM')); if (number === Infinity) { @@ -24,9 +26,12 @@ export function math_number(block: Block, generator: PhpGenerator): [string, Ord return ['-INF', Order.UNARY_NEGATION]; } return [String(number), number >= 0 ? Order.ATOMIC : Order.UNARY_NEGATION]; -}; +} -export function math_arithmetic(block: Block, generator: PhpGenerator): [string, Order] { +export function math_arithmetic( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Basic arithmetic operators, and power. const OPERATORS: Record = { 'ADD': [' + ', Order.ADDITION], @@ -43,9 +48,12 @@ export function math_arithmetic(block: Block, generator: PhpGenerator): [string, const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + operator + argument1; return [code, order]; -}; +} -export function math_single(block: Block, generator: PhpGenerator): [string, Order] { +export function math_single( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; @@ -124,9 +132,12 @@ export function math_single(block: Block, generator: PhpGenerator): [string, Ord throw Error('Unknown math operator: ' + operator); } return [code, Order.DIVISION]; -}; +} -export function math_constant(block: Block, generator: PhpGenerator): [string, Order] { +export function math_constant( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. const CONSTANTS: Record = { 'PI': ['M_PI', Order.ATOMIC], @@ -136,14 +147,20 @@ export function math_constant(block: Block, generator: PhpGenerator): [string, O 'SQRT1_2': ['M_SQRT1_2', Order.ATOMIC], 'INFINITY': ['INF', Order.ATOMIC], }; - type ConstantOption = keyof typeof CONSTANTS + type ConstantOption = keyof typeof CONSTANTS; return CONSTANTS[block.getFieldValue('CONSTANT') as ConstantOption]; -}; +} -export function math_number_property(block: Block, generator: PhpGenerator): [string, Order] { +export function math_number_property( + block: Block, + generator: PhpGenerator, +): [string, Order] { // 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: Record = { + const PROPERTIES: Record< + string, + [string, string, Order, Order] | [null, null, Order, Order] + > = { 'EVEN': ['', ' % 2 == 0', Order.MODULUS, Order.EQUALITY], 'ODD': ['', ' % 2 == 1', Order.MODULUS, Order.EQUALITY], 'WHOLE': ['is_int(', ')', Order.NONE, Order.FUNCTION_CALL], @@ -155,13 +172,15 @@ export function math_number_property(block: Block, generator: PhpGenerator): [st type PropertyOption = keyof typeof PROPERTIES; const dropdownProperty = block.getFieldValue('PROPERTY') as PropertyOption; const [prefix, suffix, inputOrder, outputOrder] = - PROPERTIES[dropdownProperty]; - const numberToCheck = generator.valueToCode(block, 'NUMBER_TO_CHECK', - inputOrder) || '0'; + PROPERTIES[dropdownProperty]; + 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 = generator.provideFunction_('math_isPrime', ` + 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) { @@ -180,37 +199,39 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($n) { } return true; } -`); +`, + ); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = generator.valueToCode(block, 'DIVISOR', - Order.MODULUS) || '0'; + const divisor = + generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; if (divisor === '0') { return ['false', Order.ATOMIC]; - } code = numberToCheck + ' % ' + divisor + ' == 0'; } else { code = prefix + numberToCheck + suffix; } return [code, outputOrder]; -}; +} export function math_change(block: Block, generator: PhpGenerator) { // Add to a variable in place. const argument0 = - generator.valueToCode(block, 'DELTA', Order.ADDITION) || '0'; - const varName = - generator.getVariableName(block.getFieldValue('VAR')); + generator.valueToCode(block, 'DELTA', Order.ADDITION) || '0'; + const varName = generator.getVariableName(block.getFieldValue('VAR')); return varName + ' += ' + argument0 + ';\n'; -}; +} // Rounding functions have a single operand. export const math_round = math_single; // Trigonometry functions have a single operand. export const math_trig = math_single; -export function math_on_list(block: Block, generator: PhpGenerator): [string, Order] { +export function math_on_list( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Math functions for lists. const func = block.getFieldValue('OP'); let list; @@ -218,40 +239,43 @@ export function math_on_list(block: Block, generator: PhpGenerator): [string, Or switch (func) { case 'SUM': list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) - || 'array()'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; code = 'array_sum(' + list + ')'; break; case 'MIN': list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) - || 'array()'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; code = 'min(' + list + ')'; break; case 'MAX': list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) - || 'array()'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; code = 'max(' + list + ')'; break; case 'AVERAGE': { - const functionName = generator.provideFunction_('math_mean', ` + const functionName = generator.provideFunction_( + 'math_mean', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($myList) { return array_sum($myList) / count($myList); } -`); +`, + ); list = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; code = functionName + '(' + list + ')'; break; } case 'MEDIAN': { - const functionName = generator.provideFunction_('math_median', ` + 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 = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; @@ -260,7 +284,9 @@ function ${generator.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 = generator.provideFunction_('math_modes', ` + const functionName = generator.provideFunction_( + 'math_modes', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($values) { if (empty($values)) return array(); $counts = array_count_values($values); @@ -268,14 +294,16 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($values) { $modes = array_keys($counts, current($counts), true); return $modes; } -`); +`, + ); list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'STD_DEV': { - const functionName = - generator.provideFunction_('math_standard_deviation', ` + const functionName = generator.provideFunction_( + 'math_standard_deviation', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($numbers) { $n = count($numbers); if (!$n) return null; @@ -283,18 +311,22 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($numbers) { foreach($numbers as $key => $num) $devs[$key] = pow($num - $mean, 2); return sqrt(array_sum($devs) / (count($devs) - 1)); } -`); +`, + ); list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'RANDOM': { - const functionName = generator.provideFunction_('math_random_list', ` + const functionName = generator.provideFunction_( + 'math_random_list', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { $x = rand(0, count($list)-1); return $list[$x]; } -`); +`, + ); list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; @@ -303,56 +335,74 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { throw Error('Unknown operator: ' + func); } return [code, Order.FUNCTION_CALL]; -}; +} -export function math_modulo(block: Block, generator: PhpGenerator): [string, Order] { +export function math_modulo( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Remainder computation. const argument0 = - generator.valueToCode(block, 'DIVIDEND', Order.MODULUS) || '0'; + generator.valueToCode(block, 'DIVIDEND', Order.MODULUS) || '0'; const argument1 = - generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; + generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MODULUS]; -}; +} -export function math_constrain(block: Block, generator: PhpGenerator): [string, Order] { +export function math_constrain( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Constrain a number between two limits. const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'LOW', Order.NONE) || '0'; const argument2 = - generator.valueToCode(block, 'HIGH', Order.NONE) || 'Infinity'; + generator.valueToCode(block, 'HIGH', Order.NONE) || 'Infinity'; const code = - 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; + 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function math_random_int(block: Block, generator: PhpGenerator): [string, Order] { +export function math_random_int( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Random integer between [X] and [Y]. 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', ` + const functionName = generator.provideFunction_( + 'math_random_int', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($a, $b) { if ($a > $b) { return rand($b, $a); } return rand($a, $b); } -`); +`, + ); const code = functionName + '(' + argument0 + ', ' + argument1 + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function math_random_float(block: Block, generator: PhpGenerator): [string, Order] { +export function math_random_float( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Random fraction between 0 and 1. return ['(float)rand()/(float)getrandmax()', Order.FUNCTION_CALL]; -}; +} -export function math_atan2(block: Block, generator: PhpGenerator): [string, Order] { +export function math_atan2( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Arctangent of point (X, Y) in degrees from -180 to 180. 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 + Order.DIVISION, ]; -}; +} diff --git a/generators/php/php_generator.ts b/generators/php/php_generator.ts index e7d1bb7460d..065e3a67a0d 100644 --- a/generators/php/php_generator.ts +++ b/generators/php/php_generator.ts @@ -18,11 +18,11 @@ import {Names} from '../../core/names.js'; import type {Workspace} from '../../core/workspace.js'; import {inputTypes} from '../../core/inputs/input_types.js'; - /** * Order of operation ENUMs. * http://php.net/manual/en/language.operators.precedence.php */ +// prettier-ignore export enum Order { ATOMIC = 0, // 0 "" ... CLONE = 1, // clone @@ -81,7 +81,7 @@ export class PhpGenerator extends CodeGenerator { // a && (b && c) -> a && b && c [Order.LOGICAL_AND, Order.LOGICAL_AND], // a || (b || c) -> a || b || c - [Order.LOGICAL_OR, Order.LOGICAL_OR] + [Order.LOGICAL_OR, Order.LOGICAL_OR], ]; /** @param name Name of the language the generator is for. */ @@ -116,25 +116,25 @@ export class PhpGenerator extends CodeGenerator { this.addReservedWords( // http://php.net/manual/en/reserved.keywords.php '__halt_compiler,abstract,and,array,as,break,callable,case,catch,class,' + - 'clone,const,continue,declare,default,die,do,echo,else,elseif,empty,' + - 'enddeclare,endfor,endforeach,endif,endswitch,endwhile,eval,exit,' + - 'extends,final,for,foreach,function,global,goto,if,implements,include,' + - 'include_once,instanceof,insteadof,interface,isset,list,namespace,new,' + - 'or,print,private,protected,public,require,require_once,return,static,' + - 'switch,throw,trait,try,unset,use,var,while,xor,' + - // http://php.net/manual/en/reserved.constants.php - 'PHP_VERSION,PHP_MAJOR_VERSION,PHP_MINOR_VERSION,PHP_RELEASE_VERSION,' + - 'PHP_VERSION_ID,PHP_EXTRA_VERSION,PHP_ZTS,PHP_DEBUG,PHP_MAXPATHLEN,' + - 'PHP_OS,PHP_SAPI,PHP_EOL,PHP_INT_MAX,PHP_INT_SIZE,DEFAULT_INCLUDE_PATH,' + - 'PEAR_INSTALL_DIR,PEAR_EXTENSION_DIR,PHP_EXTENSION_DIR,PHP_PREFIX,' + - 'PHP_BINDIR,PHP_BINARY,PHP_MANDIR,PHP_LIBDIR,PHP_DATADIR,' + - 'PHP_SYSCONFDIR,PHP_LOCALSTATEDIR,PHP_CONFIG_FILE_PATH,' + - 'PHP_CONFIG_FILE_SCAN_DIR,PHP_SHLIB_SUFFIX,E_ERROR,E_WARNING,E_PARSE,' + - 'E_NOTICE,E_CORE_ERROR,E_CORE_WARNING,E_COMPILE_ERROR,' + - 'E_COMPILE_WARNING,E_USER_ERROR,E_USER_WARNING,E_USER_NOTICE,' + - 'E_DEPRECATED,E_USER_DEPRECATED,E_ALL,E_STRICT,' + - '__COMPILER_HALT_OFFSET__,TRUE,FALSE,NULL,__CLASS__,__DIR__,__FILE__,' + - '__FUNCTION__,__LINE__,__METHOD__,__NAMESPACE__,__TRAIT__' + 'clone,const,continue,declare,default,die,do,echo,else,elseif,empty,' + + 'enddeclare,endfor,endforeach,endif,endswitch,endwhile,eval,exit,' + + 'extends,final,for,foreach,function,global,goto,if,implements,include,' + + 'include_once,instanceof,insteadof,interface,isset,list,namespace,new,' + + 'or,print,private,protected,public,require,require_once,return,static,' + + 'switch,throw,trait,try,unset,use,var,while,xor,' + + // http://php.net/manual/en/reserved.constants.php + 'PHP_VERSION,PHP_MAJOR_VERSION,PHP_MINOR_VERSION,PHP_RELEASE_VERSION,' + + 'PHP_VERSION_ID,PHP_EXTRA_VERSION,PHP_ZTS,PHP_DEBUG,PHP_MAXPATHLEN,' + + 'PHP_OS,PHP_SAPI,PHP_EOL,PHP_INT_MAX,PHP_INT_SIZE,DEFAULT_INCLUDE_PATH,' + + 'PEAR_INSTALL_DIR,PEAR_EXTENSION_DIR,PHP_EXTENSION_DIR,PHP_PREFIX,' + + 'PHP_BINDIR,PHP_BINARY,PHP_MANDIR,PHP_LIBDIR,PHP_DATADIR,' + + 'PHP_SYSCONFDIR,PHP_LOCALSTATEDIR,PHP_CONFIG_FILE_PATH,' + + 'PHP_CONFIG_FILE_SCAN_DIR,PHP_SHLIB_SUFFIX,E_ERROR,E_WARNING,E_PARSE,' + + 'E_NOTICE,E_CORE_ERROR,E_CORE_WARNING,E_COMPILE_ERROR,' + + 'E_COMPILE_WARNING,E_USER_ERROR,E_USER_WARNING,E_USER_NOTICE,' + + 'E_DEPRECATED,E_USER_DEPRECATED,E_ALL,E_STRICT,' + + '__COMPILER_HALT_OFFSET__,TRUE,FALSE,NULL,__CLASS__,__DIR__,__FILE__,' + + '__FUNCTION__,__LINE__,__METHOD__,__NAMESPACE__,__TRAIT__', ); } @@ -157,7 +157,7 @@ export class PhpGenerator extends CodeGenerator { this.nameDB_.populateProcedures(workspace); this.isInitialized = true; - }; + } /** * Prepend the generated code with the variable definitions. @@ -174,7 +174,7 @@ export class PhpGenerator extends CodeGenerator { this.nameDB_!.reset(); return definitions.join('\n\n') + '\n\n\n' + code; - }; + } /** * Naked values are top-level blocks with outputs that aren't plugged into @@ -185,7 +185,7 @@ export class PhpGenerator extends CodeGenerator { */ scrubNakedValue(line: string): string { return line + ';\n'; - }; + } /** * Encode a string as a properly escaped PHP string, complete with @@ -195,11 +195,12 @@ export class PhpGenerator extends CodeGenerator { * @returns PHP string. */ quote_(string: string): string { - string = string.replace(/\\/g, '\\\\') - .replace(/\n/g, '\\\n') - .replace(/'/g, '\\\''); - return '\'' + string + '\''; - }; + string = string + .replace(/\\/g, '\\\\') + .replace(/\n/g, '\\\n') + .replace(/'/g, "\\'"); + return "'" + string + "'"; + } /** * Encode a string as a properly escaped multiline PHP string, complete with @@ -212,8 +213,8 @@ export class PhpGenerator extends CodeGenerator { // Join with the following, plus a newline: // . "\n" . // Newline escaping only works in double-quoted strings. - return lines.join(' . \"\\n\" .\n'); - }; + return lines.join(' . "\\n" .\n'); + } /** * Common tasks for generating PHP from blocks. @@ -250,10 +251,10 @@ export class PhpGenerator extends CodeGenerator { } } const nextBlock = - block.nextConnection && block.nextConnection.targetBlock(); + block.nextConnection && block.nextConnection.targetBlock(); const nextCode = thisOnly ? '' : this.blockToCode(nextBlock); return commentCode + code + nextCode; - }; + } /** * Generate code representing the specified value input, adjusted to take into @@ -267,7 +268,13 @@ export class PhpGenerator extends CodeGenerator { * @param order The highest order acting on this value. * @returns The adjusted value. */ - getAdjusted(block: Block, atId: string, delta = 0, negate = false, order = Order.NONE): string | number { + getAdjusted( + block: Block, + atId: string, + delta = 0, + negate = false, + order = Order.NONE, + ): string | number { if (block.workspace.options.oneBasedIndex) { delta--; } @@ -289,7 +296,7 @@ export class PhpGenerator extends CodeGenerator { return at; } // If the index is a naked number, adjust it right now. - if (stringUtils.isNumber(at)) { + if (stringUtils.isNumber(at)) { at = String(Number(at) + delta); if (negate) { at = String(-Number(at)); @@ -309,5 +316,5 @@ export class PhpGenerator extends CodeGenerator { at = `(${at})`; } return at; - }; + } } diff --git a/generators/php/procedures.ts b/generators/php/procedures.ts index e4731ddc805..df33cb50f2e 100644 --- a/generators/php/procedures.ts +++ b/generators/php/procedures.ts @@ -17,7 +17,6 @@ import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; - export function procedures_defreturn(block: Block, generator: PhpGenerator) { // Define a procedure with a return value. // First, add a 'global' statement for every variable that is not shadowed by @@ -36,15 +35,14 @@ export function procedures_defreturn(block: Block, generator: PhpGenerator) { const devVarList = Variables.allDeveloperVariables(workspace); for (let i = 0; i < devVarList.length; i++) { globals.push( - generator.nameDB_!.getName( - devVarList[i], NameType.DEVELOPER_VARIABLE)); + generator.nameDB_!.getName(devVarList[i], NameType.DEVELOPER_VARIABLE), + ); } - const globalStr = - globals.length ? - generator.INDENT + 'global ' + globals.join(', ') + ';\n' : ''; + const globalStr = globals.length + ? generator.INDENT + 'global ' + globals.join(', ') + ';\n' + : ''; - const funcName = - generator.getProcedureName(block.getFieldValue('NAME')); + const funcName = generator.getProcedureName(block.getFieldValue('NAME')); let xfix1 = ''; if (generator.STATEMENT_PREFIX) { xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block); @@ -58,8 +56,9 @@ export function procedures_defreturn(block: Block, generator: PhpGenerator) { let loopTrap = ''; if (generator.INFINITE_LOOP_TRAP) { loopTrap = generator.prefixLines( - generator.injectId(generator.INFINITE_LOOP_TRAP, block), - generator.INDENT); + generator.injectId(generator.INFINITE_LOOP_TRAP, block), + generator.INDENT, + ); } const branch = generator.statementToCode(block, 'STACK'); let returnValue = generator.valueToCode(block, 'RETURN', Order.NONE) || ''; @@ -76,24 +75,37 @@ export function procedures_defreturn(block: Block, generator: PhpGenerator) { for (let i = 0; i < variables.length; i++) { args[i] = generator.getVariableName(variables[i]); } - let code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' + - globalStr + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; + let code = + 'function ' + + funcName + + '(' + + args.join(', ') + + ') {\n' + + globalStr + + xfix1 + + loopTrap + + branch + + xfix2 + + returnValue + + '}'; code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. // TODO(#7600): find better approach than casting to any to override // CodeGenerator declaring .definitions protected. (generator as AnyDuringMigration).definitions_['%' + funcName] = code; return null; -}; +} // Defining a procedure without a return value uses the same generator as // a procedure with a return value. export const procedures_defnoreturn = procedures_defreturn; -export function procedures_callreturn(block: Block, generator: PhpGenerator): [string, Order] { +export function procedures_callreturn( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Call a procedure with a return value. - const funcName = - generator.getProcedureName(block.getFieldValue('NAME')); + const funcName = generator.getProcedureName(block.getFieldValue('NAME')); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { @@ -101,28 +113,31 @@ export function procedures_callreturn(block: Block, generator: PhpGenerator): [s } const code = funcName + '(' + args.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; -}; +} export function procedures_callnoreturn(block: Block, generator: PhpGenerator) { // 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 = generator.forBlock['procedures_callreturn'](block, generator) as [string, Order]; + const tuple = generator.forBlock['procedures_callreturn']( + block, + generator, + ) as [string, Order]; return tuple[0] + ';\n'; -}; +} export function procedures_ifreturn(block: Block, generator: PhpGenerator) { // Conditionally return value from a procedure. const condition = - generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; let code = 'if (' + condition + ') {\n'; 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 += - generator.prefixLines( - generator.injectId(generator.STATEMENT_SUFFIX, block), - generator.INDENT); + code += generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ); } if ((block as IfReturnBlock).hasReturnValue_) { const value = generator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; @@ -132,4 +147,4 @@ export function procedures_ifreturn(block: Block, generator: PhpGenerator) { } code += '}\n'; return code; -}; +} diff --git a/generators/php/text.ts b/generators/php/text.ts index c1eb9f74aaf..492e7c072c1 100644 --- a/generators/php/text.ts +++ b/generators/php/text.ts @@ -15,22 +15,26 @@ import type {JoinMutatorBlock} from '../../blocks/text.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; - export function text(block: Block, generator: PhpGenerator): [string, Order] { // Text value. const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; -}; +} -export function text_multiline(block: Block, generator: PhpGenerator): [string, Order] { +export function text_multiline( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Text value. const code = generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = - code.indexOf('.') !== -1 ? Order.STRING_CONCAT : Order.ATOMIC; + const order = code.indexOf('.') !== -1 ? Order.STRING_CONCAT : Order.ATOMIC; return [code, order]; -}; +} -export function text_join(block: Block, generator: PhpGenerator): [string, Order] { +export function text_join( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Create a string made up of any number of elements of any type. const joinBlock = block as JoinMutatorBlock; if (joinBlock.itemCount_ === 0) { @@ -41,55 +45,64 @@ export function text_join(block: Block, generator: PhpGenerator): [string, Order return [code, Order.NONE]; } else if (joinBlock.itemCount_ === 2) { const element0 = - generator.valueToCode(block, 'ADD0', Order.STRING_CONCAT) || "''"; + generator.valueToCode(block, 'ADD0', Order.STRING_CONCAT) || "''"; const element1 = - generator.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(joinBlock.itemCount_); for (let i = 0; i < joinBlock.itemCount_; i++) { - elements[i] = - generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; + elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } - const code = 'implode(\'\', array(' + elements.join(',') + '))'; + const code = "implode('', array(" + elements.join(',') + '))'; return [code, Order.FUNCTION_CALL]; } -}; +} export function text_append(block: Block, generator: PhpGenerator) { // Append to a variable in place. - const varName = - generator.getVariableName(block.getFieldValue('VAR')); - const value = - generator.valueToCode(block, 'TEXT', Order.ASSIGNMENT) || "''"; + const varName = generator.getVariableName(block.getFieldValue('VAR')); + const value = generator.valueToCode(block, 'TEXT', Order.ASSIGNMENT) || "''"; return varName + ' .= ' + value + ';\n'; -}; +} -export function text_length(block: Block, generator: PhpGenerator): [string, Order] { +export function text_length( + block: Block, + generator: PhpGenerator, +): [string, Order] { // String or array length. - const functionName = generator.provideFunction_('length', ` + const functionName = generator.provideFunction_( + 'length', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { if (is_string($value)) { return strlen($value); } return count($value); } -`); +`, + ); const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return [functionName + '(' + text + ')', Order.FUNCTION_CALL]; -}; +} -export function text_isEmpty(block: Block, generator: PhpGenerator): [string, Order] { +export function text_isEmpty( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Is the string null or array empty? const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return ['empty(' + text + ')', Order.FUNCTION_CALL]; -}; +} -export function text_indexOf(block: Block, generator: PhpGenerator): [string, Order] { +export function text_indexOf( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Search the text for a substring. const operator = - block.getFieldValue('END') === 'FIRST' ? 'strpos' : 'strrpos'; + block.getFieldValue('END') === 'FIRST' ? 'strpos' : 'strrpos'; const substring = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; let errorIndex = ' -1'; @@ -99,22 +112,27 @@ export function text_indexOf(block: Block, generator: PhpGenerator): [string, Or indexAdjustment = ' + 1'; } const functionName = generator.provideFunction_( - block.getFieldValue('END') === 'FIRST' ? 'text_indexOf' : - 'text_lastIndexOf', - ` + block.getFieldValue('END') === 'FIRST' + ? 'text_indexOf' + : 'text_lastIndexOf', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text, $search) { $pos = ${operator}($text, $search); return $pos === false ? ${errorIndex} : $pos${indexAdjustment}; } -`); +`, + ); const code = functionName + '(' + text + ', ' + substring + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function text_charAt(block: Block, generator: PhpGenerator): [string, Order] { +export function text_charAt( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Get letter at index. const where = block.getFieldValue('WHERE') || 'FROM_START'; - const textOrder = (where === 'RANDOM') ? Order.NONE : Order.NONE; + const textOrder = where === 'RANDOM' ? Order.NONE : Order.NONE; const text = generator.valueToCode(block, 'VALUE', textOrder) || "''"; switch (where) { case 'FIRST': { @@ -136,19 +154,25 @@ export function text_charAt(block: Block, generator: PhpGenerator): [string, Ord return [code, Order.FUNCTION_CALL]; } case 'RANDOM': { - const functionName = generator.provideFunction_('text_random_letter', ` + const functionName = generator.provideFunction_( + 'text_random_letter', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text) { return $text[rand(0, strlen($text) - 1)]; } -`); +`, + ); const code = functionName + '(' + text + ')'; return [code, Order.FUNCTION_CALL]; } } throw Error('Unhandled option (text_charAt).'); -}; +} -export function text_getSubstring(block: Block, generator: PhpGenerator): [string, Order] { +export function text_getSubstring( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Get substring. const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); @@ -159,7 +183,9 @@ export function text_getSubstring(block: Block, generator: PhpGenerator): [strin } else { const at1 = generator.getAdjusted(block, 'AT1'); const at2 = generator.getAdjusted(block, 'AT2'); - const functionName = generator.provideFunction_('text_get_substring', ` + 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; @@ -180,14 +206,29 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text, $where1, $at1, $where2, } return substr($text, $at1, $length); } -`); - const code = functionName + '(' + text + ', \'' + where1 + '\', ' + at1 + - ', \'' + where2 + '\', ' + at2 + ')'; +`, + ); + const code = + functionName + + '(' + + text + + ", '" + + where1 + + "', " + + at1 + + ", '" + + where2 + + "', " + + at2 + + ')'; return [code, Order.FUNCTION_CALL]; } -}; +} -export function text_changeCase(block: Block, generator: PhpGenerator): [string, Order] { +export function text_changeCase( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Change capitalization. const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; let code; @@ -199,24 +240,30 @@ export function text_changeCase(block: Block, generator: PhpGenerator): [string, code = 'ucwords(strtolower(' + text + '))'; } return [code as string, Order.FUNCTION_CALL]; -}; +} -export function text_trim(block: Block, generator: PhpGenerator): [string, Order] { +export function text_trim( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Trim spaces. const OPERATORS = {'LEFT': 'ltrim', 'RIGHT': 'rtrim', 'BOTH': 'trim'}; type OperatorOption = keyof typeof OPERATORS; const operator = OPERATORS[block.getFieldValue('MODE') as OperatorOption]; const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return [operator + '(' + text + ')', Order.FUNCTION_CALL]; -}; +} export function text_print(block: Block, generator: PhpGenerator) { // Print statement. const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'print(' + msg + ');\n'; -}; +} -export function text_prompt_ext(block: Block, generator: PhpGenerator): [string, Order] { +export function text_prompt_ext( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Prompt function. let msg; if (block.getField('TEXT')) { @@ -232,29 +279,47 @@ export function text_prompt_ext(block: Block, generator: PhpGenerator): [string, code = 'floatval(' + code + ')'; } return [code, Order.FUNCTION_CALL]; -}; +} export const text_prompt = text_prompt_ext; -export function text_count(block: Block, generator: PhpGenerator): [string, Order] { +export function text_count( + block: Block, + generator: PhpGenerator, +): [string, Order] { 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 + ')'; + const code = + 'strlen(' + + sub + + ') === 0' + + ' ? strlen(' + + text + + ') + 1' + + ' : substr_count(' + + text + + ', ' + + sub + + ')'; return [code, Order.CONDITIONAL]; -}; +} -export function text_replace(block: Block, generator: PhpGenerator): [string, Order] { +export function text_replace( + block: Block, + generator: PhpGenerator, +): [string, Order] { 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]; -}; +} -export function text_reverse(block: Block, generator: PhpGenerator): [string, Order] { +export function text_reverse( + block: Block, + generator: PhpGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const code = 'strrev(' + text + ')'; return [code, Order.FUNCTION_CALL]; -}; +} diff --git a/generators/php/variables.ts b/generators/php/variables.ts index e6f18634646..160725df328 100644 --- a/generators/php/variables.ts +++ b/generators/php/variables.ts @@ -14,19 +14,19 @@ import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; import type {PhpGenerator} from './php_generator.js'; - -export function variables_get(block: Block, generator: PhpGenerator): [string, Order] { +export function variables_get( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Variable getter. - const code = - generator.getVariableName(block.getFieldValue('VAR')); + const code = generator.getVariableName(block.getFieldValue('VAR')); return [code, Order.ATOMIC]; -}; +} export function variables_set(block: Block, generator: PhpGenerator) { // Variable setter. const argument0 = - generator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; - const varName = - generator.getVariableName(block.getFieldValue('VAR')); + generator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; + const varName = generator.getVariableName(block.getFieldValue('VAR')); return varName + ' = ' + argument0 + ';\n'; -}; +} diff --git a/generators/php/variables_dynamic.ts b/generators/php/variables_dynamic.ts index 1f4a3c10095..f893a20dc5b 100644 --- a/generators/php/variables_dynamic.ts +++ b/generators/php/variables_dynamic.ts @@ -10,7 +10,6 @@ // Former goog.module ID: Blockly.PHP.variablesDynamic - // generator is dynamically typed. export { variables_get as variables_get_dynamic, From 8686f5d0ccb213059281378d1d0bdb8653df38cc Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Sat, 18 Nov 2023 00:12:56 +0000 Subject: [PATCH 8/9] docs(generators): @fileoverview -> @file With an update to the wording for generators/php.ts. --- generators/php.ts | 6 +++--- generators/php/colour.ts | 2 +- generators/php/lists.ts | 2 +- generators/php/logic.ts | 2 +- generators/php/loops.ts | 2 +- generators/php/math.ts | 2 +- generators/php/procedures.ts | 2 +- generators/php/text.ts | 2 +- generators/php/variables.ts | 2 +- generators/php/variables_dynamic.ts | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/generators/php.ts b/generators/php.ts index 66d8a3d292a..18631ad9a37 100644 --- a/generators/php.ts +++ b/generators/php.ts @@ -5,9 +5,9 @@ */ /** - * @fileoverview Complete helper functions for generating PHP for - * blocks. This is the entrypoint for php_compressed.js. - * @suppress {extraRequire} + * @file Instantiate a PhpGenerator and populate it with the complete + * set of block generator functions for PHP. This is the entrypoint + * for php_compressed.js. */ // Former goog.module ID: Blockly.PHP.all diff --git a/generators/php/colour.ts b/generators/php/colour.ts index 2c4acd74586..eefb7cba774 100644 --- a/generators/php/colour.ts +++ b/generators/php/colour.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating PHP for colour blocks. + * @file Generating PHP for colour blocks. */ // Former goog.module ID: Blockly.PHP.colour diff --git a/generators/php/lists.ts b/generators/php/lists.ts index 32347ae2aeb..1a5322decc7 100644 --- a/generators/php/lists.ts +++ b/generators/php/lists.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating PHP for list blocks. + * @file Generating PHP for list blocks. */ /** diff --git a/generators/php/logic.ts b/generators/php/logic.ts index b7c3ad2a64c..8aaa5c89213 100644 --- a/generators/php/logic.ts +++ b/generators/php/logic.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating PHP for logic blocks. + * @file Generating PHP for logic blocks. */ // Former goog.module ID: Blockly.PHP.logic diff --git a/generators/php/loops.ts b/generators/php/loops.ts index 24b3e002c59..ae87dbb294b 100644 --- a/generators/php/loops.ts +++ b/generators/php/loops.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating PHP for loop blocks. + * @file Generating PHP for loop blocks. */ // Former goog.module ID: Blockly.PHP.loops diff --git a/generators/php/math.ts b/generators/php/math.ts index 811c6da8591..b18127c9316 100644 --- a/generators/php/math.ts +++ b/generators/php/math.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating PHP for math blocks. + * @file Generating PHP for math blocks. */ // Former goog.module ID: Blockly.PHP.math diff --git a/generators/php/procedures.ts b/generators/php/procedures.ts index df33cb50f2e..5d44eb21bae 100644 --- a/generators/php/procedures.ts +++ b/generators/php/procedures.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating PHP for procedure blocks. + * @file Generating PHP for procedure blocks. */ // Former goog.module ID: Blockly.PHP.procedures diff --git a/generators/php/text.ts b/generators/php/text.ts index 492e7c072c1..f2fa69faec3 100644 --- a/generators/php/text.ts +++ b/generators/php/text.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating PHP for text blocks. + * @file Generating PHP for text blocks. */ // Former goog.module ID: Blockly.PHP.texts diff --git a/generators/php/variables.ts b/generators/php/variables.ts index 160725df328..4aacc293b6d 100644 --- a/generators/php/variables.ts +++ b/generators/php/variables.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating PHP for variable blocks. + * @file Generating PHP for variable blocks. */ // Former goog.module ID: Blockly.PHP.variables diff --git a/generators/php/variables_dynamic.ts b/generators/php/variables_dynamic.ts index f893a20dc5b..5ab5ec6cab5 100644 --- a/generators/php/variables_dynamic.ts +++ b/generators/php/variables_dynamic.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating PHP for dynamic variable blocks. + * @file Generating PHP for dynamic variable blocks. */ // Former goog.module ID: Blockly.PHP.variablesDynamic From 4e87ae5e4c93939c15a93ca0800ec68f6ba01d01 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Tue, 21 Nov 2023 23:08:27 +0000 Subject: [PATCH 9/9] fix(generators): Fixes for PR #7647. - Don't declare unused wherePascalCase dictionary. - Don't allow null in OPERATOR dictionary when not needed. - Fix return type (and documentation thereof) of getAdjusted. --- generators/php/lists.ts | 12 ++---------- generators/php/math.ts | 2 +- generators/php/php_generator.ts | 4 ++-- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/generators/php/lists.ts b/generators/php/lists.ts index 1a5322decc7..7ca2639b7f2 100644 --- a/generators/php/lists.ts +++ b/generators/php/lists.ts @@ -400,17 +400,9 @@ export function lists_getSublist( generator: PhpGenerator, ): [string, Order] { // Get sublist. - // Dictionary of WHEREn field choices and their CamelCase equivalents. - const wherePascalCase = { - 'FIRST': 'First', - 'LAST': 'Last', - 'FROM_START': 'FromStart', - 'FROM_END': 'FromEnd', - }; - type WhereOption = keyof typeof wherePascalCase; const list = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; - const where1 = block.getFieldValue('WHERE1') as WhereOption; - const where2 = block.getFieldValue('WHERE2') as WhereOption; + const where1 = block.getFieldValue('WHERE1'); + const where2 = block.getFieldValue('WHERE2'); let code; if (where1 === 'FIRST' && where2 === 'LAST') { code = list; diff --git a/generators/php/math.ts b/generators/php/math.ts index b18127c9316..6218bf4d114 100644 --- a/generators/php/math.ts +++ b/generators/php/math.ts @@ -33,7 +33,7 @@ export function math_arithmetic( generator: PhpGenerator, ): [string, Order] { // Basic arithmetic operators, and power. - const OPERATORS: Record = { + const OPERATORS: Record = { 'ADD': [' + ', Order.ADDITION], 'MINUS': [' - ', Order.SUBTRACTION], 'MULTIPLY': [' * ', Order.MULTIPLICATION], diff --git a/generators/php/php_generator.ts b/generators/php/php_generator.ts index 065e3a67a0d..ecdfb76fd01 100644 --- a/generators/php/php_generator.ts +++ b/generators/php/php_generator.ts @@ -266,7 +266,7 @@ export class PhpGenerator extends CodeGenerator { * @param delta Value to add. * @param negate Whether to negate the value. * @param order The highest order acting on this value. - * @returns The adjusted value. + * @returns The adjusted value or code that evaluates to it. */ getAdjusted( block: Block, @@ -274,7 +274,7 @@ export class PhpGenerator extends CodeGenerator { delta = 0, negate = false, order = Order.NONE, - ): string | number { + ): string { if (block.workspace.options.oneBasedIndex) { delta--; }