diff --git a/packages/blockly/generators/php/lists.ts b/packages/blockly/generators/php/lists.ts index 009d7ccc807..8c12099cb67 100644 --- a/packages/blockly/generators/php/lists.ts +++ b/packages/blockly/generators/php/lists.ts @@ -8,23 +8,11 @@ * @file Generating PHP for list blocks. */ -/** - * Lists in PHP are known to break when non-variables are passed into blocks - * that require a list. PHP, unlike other languages, passes arrays as reference - * value instead of value so we are unable to support it to the extent we can - * for the other languages. - * For example, a ternary operator with two arrays will return the array by - * value and that cannot be passed into any of the built-in array functions for - * PHP (because only variables can be passed by reference). - * ex: end(true ? list1 : list2) - */ - // Former goog.module ID: Blockly.generator.lists import type {CreateWithBlock} from '../../blocks/lists.js'; import type {Block} from '../../core/block.js'; import {NameType} from '../../core/names.js'; -import * as stringUtils from '../../core/utils/string.js'; import type {PhpGenerator} from './php_generator.js'; import {Order} from './php_generator.js'; @@ -32,34 +20,37 @@ export function lists_create_empty( block: Block, generator: PhpGenerator, ): [string, Order] { + generator.provideListObject(); // Create an empty list. - return ['array()', Order.FUNCTION_CALL]; + return ['new ListObject()', Order.NEW]; } export function lists_create_with( block: Block, generator: PhpGenerator, ): [string, Order] { + generator.provideListObject(); // Create a list with any number of elements of any type. 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'; } - const code = 'array(' + elements.join(', ') + ')'; - return [code, Order.FUNCTION_CALL]; + const code = 'new ListObject(array(' + elements.join(', ') + '))'; + return [code, Order.NEW]; } export function lists_repeat( block: Block, generator: PhpGenerator, ): [string, Order] { + generator.provideListObject(); // Create a list with one element repeated. const functionName = generator.provideFunction_( 'lists_repeat', ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { - $array = array(); + $array = new ListObject(); for ($index = 0; $index < $count; $index++) { $array[] = $value; } @@ -73,10 +64,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { return [code, Order.FUNCTION_CALL]; } -export function lists_length( - block: Block, - generator: PhpGenerator, -): [string, Order] { +function provideLengthCheck(generator: PhpGenerator) { // String or array length. const functionName = generator.provideFunction_( 'length', @@ -90,18 +78,33 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { } `, ); + + return functionName; +} + +export function lists_length( + block: Block, + generator: PhpGenerator, +): [string, Order] { const list = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; - return [functionName + '(' + list + ')', Order.FUNCTION_CALL]; + return [ + provideLengthCheck(generator) + '(' + list + ')', + Order.FUNCTION_CALL, + ]; } export function lists_isEmpty( block: Block, generator: PhpGenerator, ): [string, Order] { + generator.provideListObject(); // Is the string null or array empty? const argument0 = - generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || 'array()'; - return ['empty(' + argument0 + ')', Order.FUNCTION_CALL]; + generator.valueToCode(block, 'VALUE', Order.NONE) || '(new ListObject())'; + return [ + provideLengthCheck(generator) + '(' + argument0 + ') == 0', + Order.EQUALITY, + ]; } export function lists_indexOf( @@ -110,7 +113,7 @@ export function lists_indexOf( ): [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.NONE) || '[]'; let errorIndex = ' -1'; let indexAdjustment = ''; if (block.workspace.options.oneBasedIndex) { @@ -155,6 +158,7 @@ export function lists_getIndex( block: Block, generator: PhpGenerator, ): [string, Order] | string { + generator.provideListObject(); // Get element at index. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; @@ -162,75 +166,88 @@ export function lists_getIndex( case 'FIRST': if (mode === 'GET') { const list = - generator.valueToCode(block, 'VALUE', Order.MEMBER) || 'array()'; - const code = list + '[0]'; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || + '(new ListObject())'; + const code = list + '->slice(0, 1)[0]'; return [code, Order.MEMBER]; } else if (mode === 'GET_REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; - const code = 'array_shift(' + list + ')'; + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || + '(new ListObject())'; + const code = list + '->shift()'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; - return 'array_shift(' + list + ');\n'; + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || + '(new ListObject())'; + return list + '->shift();\n'; } break; case 'LAST': if (mode === 'GET') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; - const code = 'end(' + list + ')'; + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || + '(new ListObject())'; + const code = list + '->slice(-1)[0]'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'GET_REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; - const code = 'array_pop(' + list + ')'; + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || + '(new ListObject())'; + const code = list + '->pop()'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; - return 'array_pop(' + list + ');\n'; + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || + '(new ListObject())'; + return list + '->pop();\n'; } break; case 'FROM_START': { const at = generator.getAdjusted(block, 'AT'); if (mode === 'GET') { const list = - generator.valueToCode(block, 'VALUE', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || + '(new ListObject())'; const code = list + '[' + at + ']'; return [code, Order.MEMBER]; } else if (mode === 'GET_REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; - const code = 'array_splice(' + list + ', ' + at + ', 1)[0]'; + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || + '(new ListObject())'; + const code = list + '->splice(' + at + ', 1)[0]'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; - return 'array_splice(' + list + ', ' + at + ', 1);\n'; + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || + '(new ListObject())'; + return list + '->splice(' + at + ', 1);\n'; } break; } case 'FROM_END': if (mode === 'GET') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || + '(new ListObject())'; const at = generator.getAdjusted(block, 'AT', 1, true); - const code = 'array_slice(' + list + ', ' + at + ', 1)[0]'; + const code = list + '->slice(' + 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, + generator.valueToCode(block, 'VALUE', Order.NONE) || + '(new ListObject())'; + const at = generator.getAdjusted(block, 'AT', 1, false, Order.NONE); + + const functionName = generator.provideFunction_( + 'lists_get_remove', + ` +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $at) { + return $list->splice(count($list) - $at, 1)[0]; +} +`, ); - const code = - 'array_splice(' + list + ', count(' + list + ') - ' + at + ', 1)[0]'; + const code = functionName + '(' + list + ', ' + at + ')'; if (mode === 'GET_REMOVE') { return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { @@ -240,7 +257,8 @@ export function lists_getIndex( break; case 'RANDOM': { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || + '(new ListObject())'; if (mode === 'GET') { const functionName = generator.provideFunction_( 'lists_get_random_item', @@ -256,10 +274,9 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { const functionName = generator.provideFunction_( 'lists_get_remove_random_item', ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { $x = rand(0,count($list)-1); - unset($list[$x]); - return array_values($list); + return $list->splice($x, 1)[0]; } `, ); @@ -269,8 +286,9 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { const functionName = generator.provideFunction_( 'lists_remove_random_item', ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { - unset($list[rand(0,count($list)-1)]); +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { + $list->offsetUnset(rand(0,count($list)-1)); + $list->exchangeArray(array_values($list->getArrayCopy())); } `, ); @@ -283,6 +301,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { } export function lists_setIndex(block: Block, generator: PhpGenerator) { + generator.provideListObject(); // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; @@ -299,7 +318,7 @@ export function lists_setIndex(block: Block, generator: PhpGenerator) { 'tmp_list', NameType.VARIABLE, ); - const code = listVar + ' = &' + cachedList + ';\n'; + const code = listVar + ' = ' + cachedList + ';\n'; cachedList = listVar; return code; } @@ -307,29 +326,24 @@ export function lists_setIndex(block: Block, generator: PhpGenerator) { case 'FIRST': if (mode === 'SET') { const list = - generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; - return list + '[0] = ' + value + ';\n'; + generator.valueToCode(block, 'LIST', Order.MEMBER) || + '(new ListObject())'; + return list + '->splice(0, 1, [' + value + ']);\n'; } else if (mode === 'INSERT') { const list = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; - return 'array_unshift(' + list + ', ' + value + ');\n'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || + '(new ListObject())'; + return list + '->unshift(' + value + ');\n'; } break; case 'LAST': { const list = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || + '(new ListObject())'; if (mode === 'SET') { - 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'; + return list + '->splice(-1, 1, [' + value + ']);\n'; } else if (mode === 'INSERT') { - return 'array_push(' + list + ', ' + value + ');\n'; + return list + '->append(' + value + ');\n'; } break; } @@ -337,24 +351,27 @@ 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()'; - return list + '[' + at + '] = ' + value + ';\n'; + generator.valueToCode(block, 'LIST', Order.MEMBER) || + '(new ListObject())'; + return list + '->splice(' + at + ', 1, [' + value + ']);\n'; } else if (mode === 'INSERT') { const list = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; - return 'array_splice(' + list + ', ' + at + ', 0, ' + value + ');\n'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || + '(new ListObject())'; + return list + '->splice(' + at + ', 0, [' + value + ']);\n'; } break; } case 'FROM_END': { const list = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; - const at = generator.getAdjusted(block, 'AT', 1); + generator.valueToCode(block, 'LIST', Order.NONE) || + '(new ListObject())'; + const at = generator.getAdjusted(block, 'AT', 1, false, Order.NONE); if (mode === 'SET') { const functionName = generator.provideFunction_( 'lists_set_from_end', ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $at, $value) { $list[count($list) - $at] = $value; } `, @@ -364,8 +381,8 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { 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); +function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $at, $value) { + return $list->splice(count($list) - $at, 0, [$value]); } `, ); @@ -375,7 +392,8 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { } case 'RANDOM': cachedList = - generator.valueToCode(block, 'LIST', Order.REFERENCE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || + '(new ListObject())'; let code = cacheList(); const list = cachedList; const xVar = generator.nameDB_!.getDistinctName( @@ -387,7 +405,8 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { code += list + '[' + xVar + '] = ' + value + ';\n'; return code; } else if (mode === 'INSERT') { - code += 'array_splice(' + list + ', ' + xVar + ', 0, ' + value + ');\n'; + code += list + '->splice(' + xVar + ', 0, [' + value + ']);\n'; + return code; } break; @@ -399,13 +418,16 @@ export function lists_getSublist( block: Block, generator: PhpGenerator, ): [string, Order] { + generator.provideListObject(); // Get sublist. - const list = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + const list = + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || + '(new ListObject())'; const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); let code; if (where1 === 'FIRST' && where2 === 'LAST') { - code = list; + return ['clone ' + list, Order.CLONE]; } else if ( list.match(/^\$\w+$/) || (where1 !== 'FROM_END' && where2 === 'FROM_START') @@ -415,11 +437,11 @@ export function lists_getSublist( let at1; switch (where1) { case 'FROM_START': - at1 = generator.getAdjusted(block, 'AT1'); + at1 = generator.getAdjusted(block, 'AT1', 0, false, Order.SUBTRACTION); break; case 'FROM_END': at1 = generator.getAdjusted(block, 'AT1', 1, false, Order.SUBTRACTION); - at1 = 'count(' + list + ') - ' + at1; + at1 = '(count(' + list + ') - ' + at1 + ')'; break; case 'FIRST': at1 = '0'; @@ -432,44 +454,19 @@ export function lists_getSublist( switch (where2) { case 'FROM_START': at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); - length = at2 + ' - '; - if ( - stringUtils.isNumber(String(at1)) || - String(at1).match(/^\(.+\)$/) - ) { - length += at1; - } else { - length += '(' + at1 + ')'; - } - length += ' + 1'; + length = at2 + ' - ' + at1 + ' + 1'; break; case 'FROM_END': at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); - length = 'count(' + list + ') - ' + at2 + ' - '; - if ( - stringUtils.isNumber(String(at1)) || - String(at1).match(/^\(.+\)$/) - ) { - length += at1; - } else { - length += '(' + at1 + ')'; - } + length = 'count(' + list + ') - ' + at2 + ' - ' + at1; break; case 'LAST': - length = 'count(' + list + ') - '; - if ( - stringUtils.isNumber(String(at1)) || - String(at1).match(/^\(.+\)$/) - ) { - length += at1; - } else { - length += '(' + at1 + ')'; - } + length = 'count(' + list + ') - ' + at1; break; default: throw Error('Unhandled option (lists_getSublist).'); } - code = 'array_slice(' + list + ', ' + at1 + ', ' + length + ')'; + code = list + '->slice(' + at1 + ', ' + length + ')'; } else { const at1 = generator.getAdjusted(block, 'AT1'); const at2 = generator.getAdjusted(block, 'AT2'); @@ -494,7 +491,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $where1, $at1, $where2, } else { throw new Exception('Unhandled option (lists_get_sublist).'); } - return array_slice($list, $at1, $length); + return $list->slice($at1, $length); } `, ); @@ -519,9 +516,10 @@ export function lists_sort( block: Block, generator: PhpGenerator, ): [string, Order] { + generator.provideListObject(); // Block for sorting a list. const listCode = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || '(new ListObject())'; const direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1; const type = block.getFieldValue('TYPE'); const functionName = generator.provideFunction_( @@ -534,12 +532,12 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $type, $direction) { 'IGNORE_CASE' => 'strcasecmp' ); $sortCmp = $sortCmpFuncs[$type]; - $list2 = $list; + $list2 = $list->getArrayCopy(); usort($list2, $sortCmp); if ($direction == -1) { $list2 = array_reverse($list2); } - return $list2; + return new ListObject($list2); } `, ); @@ -552,34 +550,42 @@ export function lists_split( block: Block, generator: PhpGenerator, ): [string, Order] { + generator.provideListObject(); // 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 mode = block.getFieldValue('MODE'); - let functionName; if (mode === 'SPLIT') { + let value_input = generator.valueToCode(block, 'INPUT', Order.NONE); if (!value_input) { value_input = "''"; } - functionName = 'explode'; + return [ + 'new ListObject(explode(' + value_delim + ', ' + value_input + '))', + Order.NEW, + ]; } else if (mode === 'JOIN') { - if (!value_input) { - value_input = 'array()'; - } - functionName = 'implode'; + let value_input = + generator.valueToCode(block, 'INPUT', Order.FUNCTION_CALL) || + '(new ListObject())'; + value_input = `${value_input}->getArrayCopy()`; + return [ + 'implode(' + value_delim + ', ' + value_input + ')', + Order.FUNCTION_CALL, + ]; } else { throw Error('Unknown mode: ' + mode); } - const code = functionName + '(' + value_delim + ', ' + value_input + ')'; - return [code, Order.FUNCTION_CALL]; } export function lists_reverse( block: Block, generator: PhpGenerator, ): [string, Order] { + generator.provideListObject(); // Block for reversing a list. - const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; - const code = 'array_reverse(' + list + ')'; - return [code, Order.FUNCTION_CALL]; + const list = + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || + '(new ListObject())'; + const code = 'new ListObject(array_reverse(' + list + '->getArrayCopy()))'; + return [code, Order.NEW]; } diff --git a/packages/blockly/generators/php/math.ts b/packages/blockly/generators/php/math.ts index 2026af0641e..ff0178a56bb 100644 --- a/packages/blockly/generators/php/math.ts +++ b/packages/blockly/generators/php/math.ts @@ -161,12 +161,12 @@ export function math_number_property( 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], + 'EVEN': ['fmod(', ', 2) == 0', Order.NONE, Order.EQUALITY], + 'ODD': ['abs(fmod(', ', 2)) == 1', Order.NONE, Order.EQUALITY], + 'WHOLE': ['fmod(', ', 1) == 0', Order.NONE, Order.EQUALITY], 'POSITIVE': ['', ' > 0', Order.RELATIONAL, Order.RELATIONAL], 'NEGATIVE': ['', ' < 0', Order.RELATIONAL, Order.RELATIONAL], - 'DIVISIBLE_BY': [null, null, Order.MODULUS, Order.EQUALITY], + 'DIVISIBLE_BY': [null, null, Order.NONE, Order.EQUALITY], 'PRIME': [null, null, Order.NONE, Order.FUNCTION_CALL], }; type PropertyOption = keyof typeof PROPERTIES; @@ -188,7 +188,7 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($n) { } // False if n is NaN, negative, is 1, or not whole. // And false if n is divisible by 2 or 3. - if (!is_numeric($n) || $n <= 1 || $n % 1 != 0 || $n % 2 == 0 || $n % 3 == 0) { + if (!is_numeric($n) || $n <= 1 || fmod($n, 1) != 0 || fmod($n, 2) == 0 || fmod($n, 3) == 0) { return false; } // Check all the numbers of form 6k +/- 1, up to sqrt(n). @@ -203,12 +203,11 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($n) { ); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = - generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; + const divisor = generator.valueToCode(block, 'DIVISOR', Order.NONE) || '0'; if (divisor === '0') { return ['false', Order.ATOMIC]; } - code = numberToCheck + ' % ' + divisor + ' == 0'; + code = 'fmod(' + numberToCheck + ', ' + divisor + ') == 0'; } else { code = prefix + numberToCheck + suffix; } @@ -232,6 +231,8 @@ export function math_on_list( block: Block, generator: PhpGenerator, ): [string, Order] { + generator.provideListObject(); + // Math functions for lists. const func = block.getFieldValue('OP'); let list; @@ -239,29 +240,34 @@ export function math_on_list( switch (func) { case 'SUM': list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; - code = 'array_sum(' + list + ')'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || + '(new ListObject())'; + code = 'array_sum(' + list + '->getArrayCopy())'; break; case 'MIN': list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; - code = 'min(' + list + ')'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || + '(new ListObject())'; + code = 'min(' + list + '->getArrayCopy())'; break; case 'MAX': list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; - code = 'max(' + list + ')'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || + '(new ListObject())'; + code = 'max(' + list + '->getArrayCopy())'; break; case 'AVERAGE': { const functionName = generator.provideFunction_( 'math_mean', ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($myList) { - return array_sum($myList) / count($myList); + return array_sum($myList->getArrayCopy()) / count($myList); } `, ); - list = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + list = + generator.valueToCode(block, 'LIST', Order.NONE) || + '(new ListObject())'; code = functionName + '(' + list + ')'; break; } @@ -270,13 +276,16 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($myList) { 'math_median', ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($arr) { + $arr = $arr->getArrayCopy(); 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) || '[]'; + list = + generator.valueToCode(block, 'LIST', Order.NONE) || + '(new ListObject())'; code = functionName + '(' + list + ')'; break; } @@ -288,15 +297,17 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($arr) { 'math_modes', ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($values) { - if (empty($values)) return array(); - $counts = array_count_values($values); + if (count($values) == 0) return new ListObject(); + $counts = array_count_values($values->getArrayCopy()); arsort($counts); // Sort counts in descending order $modes = array_keys($counts, current($counts), true); - return $modes; + return new ListObject($modes); } `, ); - list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + list = + generator.valueToCode(block, 'LIST', Order.NONE) || + '(new ListObject())'; code = functionName + '(' + list + ')'; break; } @@ -307,13 +318,15 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($values) { function ${generator.FUNCTION_NAME_PLACEHOLDER_}($numbers) { $n = count($numbers); if (!$n) return null; - $mean = array_sum($numbers) / count($numbers); + $mean = array_sum($numbers->getArrayCopy()) / count($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) || '[]'; + list = + generator.valueToCode(block, 'LIST', Order.NONE) || + '(new ListObject())'; code = functionName + '(' + list + ')'; break; } @@ -327,7 +340,9 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { } `, ); - list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; + list = + generator.valueToCode(block, 'LIST', Order.NONE) || + '(new ListObject())'; code = functionName + '(' + list + ')'; break; } @@ -342,12 +357,10 @@ export function math_modulo( generator: PhpGenerator, ): [string, Order] { // Remainder computation. - const argument0 = - generator.valueToCode(block, 'DIVIDEND', Order.MODULUS) || '0'; - const argument1 = - generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; - const code = argument0 + ' % ' + argument1; - return [code, Order.MODULUS]; + const argument0 = generator.valueToCode(block, 'DIVIDEND', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'DIVISOR', Order.NONE) || '0'; + const code = 'fmod(' + argument0 + ', ' + argument1 + ')'; + return [code, Order.FUNCTION_CALL]; } export function math_constrain( @@ -357,8 +370,7 @@ export function math_constrain( // 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'; + const argument2 = generator.valueToCode(block, 'HIGH', Order.NONE) || 'INF'; const code = 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Order.FUNCTION_CALL]; @@ -391,7 +403,7 @@ export function math_random_float( generator: PhpGenerator, ): [string, Order] { // Random fraction between 0 and 1. - return ['(float)rand()/(float)getrandmax()', Order.FUNCTION_CALL]; + return ['(float)rand()/(float)getrandmax()', Order.DIVISION]; } export function math_atan2( diff --git a/packages/blockly/generators/php/php_generator.ts b/packages/blockly/generators/php/php_generator.ts index 8ac23c057bd..34e473b53b3 100644 --- a/packages/blockly/generators/php/php_generator.ts +++ b/packages/blockly/generators/php/php_generator.ts @@ -25,10 +25,10 @@ import type {Workspace} from '../../core/workspace.js'; // prettier-ignore export enum Order { ATOMIC = 0, // 0 "" ... - CLONE = 1, // clone - NEW = 1, // new - MEMBER = 2.1, // [] - FUNCTION_CALL = 2.2, // () + MEMBER = 1.1, // [] + FUNCTION_CALL = 1.2, // () + CLONE = 2, // clone + NEW = 2, // new POWER = 3, // ** INCREMENT = 4, // ++ DECREMENT = 4, // -- @@ -66,6 +66,10 @@ export enum Order { export class PhpGenerator extends CodeGenerator { /** List of outer-inner pairings that do NOT require parentheses. */ ORDER_OVERRIDES: [Order, Order][] = [ + // (foo())[0] -> foo()[0] + [Order.FUNCTION_CALL, Order.MEMBER], + // (foo())() -> foo()() + [Order.FUNCTION_CALL, Order.FUNCTION_CALL], // (foo()).bar() -> foo().bar() // (foo())[0] -> foo()[0] [Order.MEMBER, Order.FUNCTION_CALL], @@ -84,6 +88,9 @@ export class PhpGenerator extends CodeGenerator { [Order.LOGICAL_OR, Order.LOGICAL_OR], ]; + /** Whether to emit the opening = Math.floor(orderForInput)) { + if (Math.floor(order) <= Math.floor(orderForInput)) { at = `(${at})`; } return at; } + + /** + * Sets whether or not this generator outputs the opening getArrayCopy(); + $result = array_slice($values, $offset, $length); + return new ListObject($result); + } + + public function splice($offset, $length = null, $replacement = []) { + $values = $this->getArrayCopy(); + $result = array_splice($values, $offset, $length, $replacement); + $this->exchangeArray($values); + return new ListObject($result); + } + + public function shift() { + $values = $this->getArrayCopy(); + $result = array_shift($values); + $this->exchangeArray($values); + return $result; + } + + public function unshift(...$newValues) { + $values = $this->getArrayCopy(); + $result = array_unshift($values, ...$newValues); + $this->exchangeArray($values); + return $result; + } + + public function pop() { + $values = $this->getArrayCopy(); + $result = array_pop($values); + $this->exchangeArray($values); + return $result; + } + + public function __toString() + { + return implode(', ', $this->getArrayCopy()); + } +} + `, + ); + } } diff --git a/packages/blockly/generators/php/text.ts b/packages/blockly/generators/php/text.ts index f50c7694602..26a5ec23ad1 100644 --- a/packages/blockly/generators/php/text.ts +++ b/packages/blockly/generators/php/text.ts @@ -57,10 +57,7 @@ export function text_append(block: Block, generator: PhpGenerator) { return varName + ' .= ' + value + ';\n'; } -export function text_length( - block: Block, - generator: PhpGenerator, -): [string, Order] { +function provideLengthCheck(generator: PhpGenerator) { // String or array length. const functionName = generator.provideFunction_( 'length', @@ -68,13 +65,26 @@ export function text_length( function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { if (is_string($value)) { return strlen($value); + } else { + return count($value); } - return count($value); } `, ); + + return functionName; +} + +export function text_length( + block: Block, + generator: PhpGenerator, +): [string, Order] { + // String or array length. const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; - return [functionName + '(' + text + ')', Order.FUNCTION_CALL]; + return [ + provideLengthCheck(generator) + '(' + text + ')', + Order.FUNCTION_CALL, + ]; } export function text_isEmpty( @@ -83,7 +93,10 @@ export function text_isEmpty( ): [string, Order] { // Is the string null or array empty? const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; - return ['empty(' + text + ')', Order.FUNCTION_CALL]; + return [ + provideLengthCheck(generator) + '(' + text + ') == 0', + Order.EQUALITY, + ]; } export function text_indexOf( diff --git a/packages/blockly/tests/generators/golden/generated.php b/packages/blockly/tests/generators/golden/generated.php index d497f1a70c7..f24a410b92a 100644 --- a/packages/blockly/tests/generators/golden/generated.php +++ b/packages/blockly/tests/generators/golden/generated.php @@ -1,3 +1,5 @@ +getArrayCopy(); + } + if ($expected instanceof ArrayObject) { + $expected = $expected->getArrayCopy(); + } // Asserts that a value equals another value. if (!is_array($unittestResults)) { throw new Exception("Orphaned assert: " . $message); @@ -150,11 +158,52 @@ function test_ternary() { assertEquals(false ? 42 : 99, 99, 'if true'); } +class ListObject extends ArrayObject { + public function slice($offset, $length = null) { + $values = $this->getArrayCopy(); + $result = array_slice($values, $offset, $length); + return new ListObject($result); + } + + public function splice($offset, $length = null, $replacement = []) { + $values = $this->getArrayCopy(); + $result = array_splice($values, $offset, $length, $replacement); + $this->exchangeArray($values); + return new ListObject($result); + } + + public function shift() { + $values = $this->getArrayCopy(); + $result = array_shift($values); + $this->exchangeArray($values); + return $result; + } + + public function unshift(...$newValues) { + $values = $this->getArrayCopy(); + $result = array_unshift($values, ...$newValues); + $this->exchangeArray($values); + return $result; + } + + public function pop() { + $values = $this->getArrayCopy(); + $result = array_pop($values); + $this->exchangeArray($values); + return $result; + } + + public function __toString() + { + return implode(', ', $this->getArrayCopy()); + } +} + // Describe this function... function test_foreach() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; $log = ''; - foreach (array('a', 'b', 'c') as $x) { + foreach (new ListObject(array('a', 'b', 'c')) as $x) { $log .= $x; } assertEquals($log, 'abc', 'for loop'); @@ -214,12 +263,12 @@ function test_count_by() { $log .= $x; } assertEquals($log, '8642', 'count down ints'); - $loglist = array(); + $loglist = new ListObject(); for ($x = 1; $x <= 8; $x += 1.5) { - array_push($loglist, $x); + $loglist->append($x); } - assertEquals($loglist, array(1, 2.5, 4, 5.5, 7), 'count with floats'); - $loglist = array(); + assertEquals($loglist, new ListObject(array(1, 2.5, 4, 5.5, 7)), 'count with floats'); + $loglist = new ListObject(); $_x_start = 1 + 0; $_x_end = 8 + 0; $_x_inc = abs(1 - 2); @@ -227,10 +276,10 @@ function test_count_by() { $_x_inc = -$_x_inc; } for ($x = $_x_start; $_x_inc >= 0 ? $x <= $_x_end : $x >= $_x_end; $x += $_x_inc) { - array_push($loglist, $x); + $loglist->append($x); } - assertEquals($loglist, array(1, 2, 3, 4, 5, 6, 7, 8), 'count up non-trivial ints'); - $loglist = array(); + assertEquals($loglist, new ListObject(array(1, 2, 3, 4, 5, 6, 7, 8)), 'count up non-trivial ints'); + $loglist = new ListObject(); $_x_start2 = 8 + 0; $_x_end2 = 1 + 0; $_x_inc2 = 2; @@ -238,10 +287,10 @@ function test_count_by() { $_x_inc2 = -$_x_inc2; } for ($x = $_x_start2; $_x_inc2 >= 0 ? $x <= $_x_end2 : $x >= $_x_end2; $x += $_x_inc2) { - array_push($loglist, $x); + $loglist->append($x); } - assertEquals($loglist, array(8, 6, 4, 2), 'count down non-trivial ints'); - $loglist = array(); + assertEquals($loglist, new ListObject(array(8, 6, 4, 2)), 'count down non-trivial ints'); + $loglist = new ListObject(); $_x_start3 = 5 + 0.5; $_x_end3 = 1 + 0; $_x_inc3 = abs(1 + 0); @@ -249,9 +298,9 @@ function test_count_by() { $_x_inc3 = -$_x_inc3; } for ($x = $_x_start3; $_x_inc3 >= 0 ? $x <= $_x_end3 : $x >= $_x_end3; $x += $_x_inc3) { - array_push($loglist, $x); + $loglist->append($x); } - assertEquals($loglist, array(5.5, 4.5, 3.5, 2.5, 1.5), 'count with floats'); + assertEquals($loglist, new ListObject(array(5.5, 4.5, 3.5, 2.5, 1.5)), 'count with floats'); } // Describe this function... @@ -267,7 +316,7 @@ function test_count_loops() { $log .= $x; } assertEquals($log, '87654321', 'count down'); - $loglist = array(); + $loglist = new ListObject(); $_x_start4 = 1 + 0; $_x_end4 = 4 + 0; $_x_inc4 = 1; @@ -275,10 +324,10 @@ function test_count_loops() { $_x_inc4 = -$_x_inc4; } for ($x = $_x_start4; $_x_inc4 >= 0 ? $x <= $_x_end4 : $x >= $_x_end4; $x += $_x_inc4) { - array_push($loglist, $x); + $loglist->append($x); } - assertEquals($loglist, array(1, 2, 3, 4), 'count up non-trivial'); - $loglist = array(); + assertEquals($loglist, new ListObject(array(1, 2, 3, 4)), 'count up non-trivial'); + $loglist = new ListObject(); $_x_start5 = 3 + 1; $_x_end5 = 1 + 0; $_x_inc5 = 1; @@ -286,9 +335,9 @@ function test_count_loops() { $_x_inc5 = -$_x_inc5; } for ($x = $_x_start5; $_x_inc5 >= 0 ? $x <= $_x_end5 : $x >= $_x_end5; $x += $_x_inc5) { - array_push($loglist, $x); + $loglist->append($x); } - assertEquals($loglist, array(4, 3, 2, 1), 'count down non-trivial'); + assertEquals($loglist, new ListObject(array(4, 3, 2, 1)), 'count down non-trivial'); } // Describe this function... @@ -323,7 +372,7 @@ function test_continue() { } assertEquals($log, '1234678', 'count continue'); $log = ''; - foreach (array('a', 'b', 'c', 'd') as $x) { + foreach (new ListObject(array('a', 'b', 'c', 'd')) as $x) { if ($x == 'c') { continue; } @@ -360,7 +409,7 @@ function test_break() { } assertEquals($log, '1234', 'count break'); $log = ''; - foreach (array('a', 'b', 'c', 'd') as $x) { + foreach (new ListObject(array('a', 'b', 'c', 'd')) as $x) { if ($x == 'c') { break; } @@ -426,7 +475,7 @@ function math_isPrime($n) { } // False if n is NaN, negative, is 1, or not whole. // And false if n is divisible by 2 or 3. - if (!is_numeric($n) || $n <= 1 || $n % 1 != 0 || $n % 2 == 0 || $n % 3 == 0) { + if (!is_numeric($n) || $n <= 1 || fmod($n, 1) != 0 || fmod($n, 2) == 0 || fmod($n, 3) == 0) { return false; } // Check all the numbers of form 6k +/- 1, up to sqrt(n). @@ -441,18 +490,18 @@ function math_isPrime($n) { // Tests the "number property" blocks. function test_number_properties() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - assertEquals(42 % 2 == 0, true, 'even'); - assertEquals(42.1 % 2 == 1, false, 'odd'); + assertEquals(fmod(42, 2) == 0, true, 'even'); + assertEquals(abs(fmod(42.1, 2)) == 1, false, 'odd'); assertEquals(math_isPrime(5), true, 'prime 5'); assertEquals(math_isPrime(5 + 2), true, 'prime 5 + 2 (extra parentheses)'); assertEquals(math_isPrime(25), false, 'prime 25'); assertEquals(math_isPrime(-31.1), false, 'prime negative'); - assertEquals(is_int(M_PI), false, 'whole'); + assertEquals(fmod(M_PI, 1) == 0, false, 'whole'); assertEquals(INF > 0, true, 'positive'); assertEquals(5 + 2 > 0, true, '5 + 2 is positive (extra parentheses)'); assertEquals(-42 < 0, true, 'negative'); assertEquals(3 + 2 < 0, false, '3 + 2 is negative (extra parentheses)'); - assertEquals(42 % 2 == 0, true, 'divisible'); + assertEquals(fmod(42, 2) == 0, true, 'divisible'); assertEquals(!false, true, 'divisible by 0'); } @@ -473,27 +522,28 @@ function test_change() { } function math_mean($myList) { - return array_sum($myList) / count($myList); + return array_sum($myList->getArrayCopy()) / count($myList); } function math_median($arr) { + $arr = $arr->getArrayCopy(); 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; } function math_modes($values) { - if (empty($values)) return array(); - $counts = array_count_values($values); + if (count($values) == 0) return new ListObject(); + $counts = array_count_values($values->getArrayCopy()); arsort($counts); // Sort counts in descending order $modes = array_keys($counts, current($counts), true); - return $modes; + return new ListObject($modes); } function math_standard_deviation($numbers) { $n = count($numbers); if (!$n) return null; - $mean = array_sum($numbers) / count($numbers); + $mean = array_sum($numbers->getArrayCopy()) / count($numbers); foreach($numbers as $key => $num) $devs[$key] = pow($num - $mean, 2); return sqrt(array_sum($devs) / (count($devs) - 1)); } @@ -513,21 +563,21 @@ function indexOf($haystack, $needle) { // Tests the "list operation" blocks. function test_operations_on_list() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - assertEquals(array_sum((array(3, 4, 5))), 12, 'sum'); - assertEquals(min((array(3, 4, 5))), 3, 'min'); - assertEquals(max((array(3, 4, 5))), 5, 'max'); - assertEquals(math_mean(array(3, 4, 5)), 4, 'average'); - assertEquals(math_median(array(3, 4, 5, 1)), 3.5, 'median'); - assertEquals(math_modes(array(3, 4, 3)), array(3), 'modes'); - assertEquals(math_modes(array(3, 4, 3, 1, 4)), array(3, 4), 'modes multiple'); - assertEquals(math_standard_deviation(array(3, 3, 3)), 0, 'standard dev'); - assertEquals(indexOf(array(3, 4, 5), math_random_list(array(3, 4, 5))) > 0, true, 'random'); + assertEquals(array_sum((new ListObject(array(3, 4, 5)))->getArrayCopy()), 12, 'sum'); + assertEquals(min((new ListObject(array(3, 4, 5)))->getArrayCopy()), 3, 'min'); + assertEquals(max((new ListObject(array(3, 4, 5)))->getArrayCopy()), 5, 'max'); + assertEquals(math_mean(new ListObject(array(3, 4, 5))), 4, 'average'); + assertEquals(math_median(new ListObject(array(3, 4, 5, 1))), 3.5, 'median'); + assertEquals(math_modes(new ListObject(array(3, 4, 3))), new ListObject(array(3)), 'modes'); + assertEquals(math_modes(new ListObject(array(3, 4, 3, 1, 4))), new ListObject(array(3, 4)), 'modes multiple'); + assertEquals(math_standard_deviation(new ListObject(array(3, 3, 3))), 0, 'standard dev'); + assertEquals(indexOf(new ListObject(array(3, 4, 5)), math_random_list(new ListObject(array(3, 4, 5)))) > 0, true, 'random'); } // Tests the "mod" block. function test_mod() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - assertEquals(42 % 5, 2, 'mod'); + assertEquals(fmod(42, 5), 2, 'mod'); } // Tests the "constrain" block. @@ -548,7 +598,7 @@ function test_random_integer() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; $rand = math_random_int(5, 10); assertEquals($rand >= 5 && $rand <= 10, true, 'randRange'); - assertEquals(is_int($rand), true, 'randInteger'); + assertEquals(fmod($rand, 1) == 0, true, 'randInteger'); } // Tests the "random fraction" block. @@ -591,20 +641,21 @@ function get_empty() { return ''; } -// Tests the "is empty" block". -function test_empty_text() { - global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - assertEquals(empty('Google'), false, 'not empty'); - assertEquals(empty(''), true, 'empty'); - assertEquals(empty(get_empty()), true, 'empty complex'); - assertEquals(empty(true ? '' : null), true, 'empty order'); -} - function length($value) { if (is_string($value)) { return strlen($value); + } else { + return count($value); } - return count($value); +} + +// Tests the "is empty" block". +function test_empty_text() { + global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; + assertEquals(length('Google') == 0, false, 'not empty'); + assertEquals(length('') == 0, true, 'empty'); + assertEquals(length(get_empty()) == 0, true, 'empty complex'); + assertEquals(length(true ? '' : null) == 0, true, 'empty order'); } // Tests the "length" block. @@ -690,10 +741,10 @@ function test_get_text_simple() { assertEquals(substr($text, -1), 'y', 'get last simple'); assertEquals(text_indexOf($text, text_random_letter($text)) > 0, true, 'get random simple'); assertEquals(substr($text, 2, 1), 'o', 'get # simple'); - assertEquals(substr($text, ((true ? 3 : null) - 1), 1), 'o', 'get # order simple'); + assertEquals(substr($text, (true ? 3 : null) - 1, 1), 'o', 'get # order simple'); assertEquals(substr($text, -3, 1), 'k', 'get #-end simple'); // The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. - assertEquals(substr($text, (-(0 + 3)), 1), 'k', 'get #-end order simple'); + assertEquals(substr($text, -(0 + 3), 1), 'k', 'get #-end order simple'); } // Creates a string for use with the get test. @@ -729,14 +780,14 @@ function test_get_text_complex() { assertEquals(substr(get_Blockly(), 2, 1), 'o', 'get # complex'); check_number_of_calls('get # complex'); $number_of_calls = 0; - assertEquals(substr(true ? get_Blockly() : null, ((true ? 3 : null) - 1), 1), 'o', 'get # order complex'); + assertEquals(substr(true ? get_Blockly() : null, (true ? 3 : null) - 1, 1), 'o', 'get # order complex'); check_number_of_calls('get # order complex'); $number_of_calls = 0; assertEquals(substr(get_Blockly(), -3, 1), 'k', 'get #-end complex'); check_number_of_calls('get #-end complex'); $number_of_calls = 0; // The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. - assertEquals(substr(true ? get_Blockly() : null, (-(0 + 3)), 1), 'k', 'get #-end order complex'); + assertEquals(substr(true ? get_Blockly() : null, -(0 + 3), 1), 'k', 'get #-end order complex'); check_number_of_calls('get #-end order complex'); } @@ -773,10 +824,10 @@ function test_substring_simple() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; $text = '123456789'; assertEquals(text_get_substring($text, 'FROM_START', 1, 'FROM_START', 2), '23', 'substring # simple'); - assertEquals(text_get_substring($text, 'FROM_START', ((true ? 2 : null) - 1), 'FROM_START', ((true ? 3 : null) - 1)), '23', 'substring # simple order'); + assertEquals(text_get_substring($text, 'FROM_START', (true ? 2 : null) - 1, 'FROM_START', (true ? 3 : null) - 1), '23', 'substring # simple order'); assertEquals(text_get_substring($text, 'FROM_END', 2, 'FROM_END', 1), '78', 'substring #-end simple'); // The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. - assertEquals(text_get_substring($text, 'FROM_END', ((0 + 3) - 1), 'FROM_END', ((0 + 2) - 1)), '78', 'substring #-end simple order'); + assertEquals(text_get_substring($text, 'FROM_END', (0 + 3) - 1, 'FROM_END', (0 + 2) - 1), '78', 'substring #-end simple order'); assertEquals($text, $text, 'substring first-last simple'); assertEquals(text_get_substring($text, 'FROM_START', 1, 'FROM_END', 1), '2345678', 'substring # #-end simple'); assertEquals(text_get_substring($text, 'FROM_END', 6, 'FROM_START', 3), '34', 'substring #-end # simple'); @@ -787,7 +838,7 @@ function test_substring_simple() { assertEquals(text_get_substring($text, 'FROM_START', 0, 'FROM_END', 0), '123456789', 'substring all with # #-end simple'); assertEquals(text_get_substring($text, 'FROM_END', 8, 'FROM_START', 8), '123456789', 'substring all with #-end # simple'); // Checks that the whole string is properly retrieved even if the value for start and end is not a simple number. This is especially important in generators where substring uses [x:length - y] for # #-end. - assertEquals(text_get_substring($text, 'FROM_START', ((0 + 1) - 1), 'FROM_END', ((0 + 1) - 1)), '123456789', 'substring all with # #-end math simple'); + assertEquals(text_get_substring($text, 'FROM_START', (0 + 1) - 1, 'FROM_END', (0 + 1) - 1), '123456789', 'substring all with # #-end math simple'); } // Tests the "get substring" block with a function call. @@ -797,14 +848,14 @@ function test_substring_complex() { assertEquals(text_get_substring(get_numbers(), 'FROM_START', 1, 'FROM_START', 2), '23', 'substring # complex'); check_number_of_calls('substring # complex'); $number_of_calls = 0; - assertEquals(text_get_substring(true ? get_numbers() : null, 'FROM_START', ((true ? 2 : null) - 1), 'FROM_START', ((true ? 3 : null) - 1)), '23', 'substring # complex order'); + assertEquals(text_get_substring(true ? get_numbers() : null, 'FROM_START', (true ? 2 : null) - 1, 'FROM_START', (true ? 3 : null) - 1), '23', 'substring # complex order'); check_number_of_calls('substring # complex order'); $number_of_calls = 0; // The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. assertEquals(text_get_substring(get_numbers(), 'FROM_END', 2, 'FROM_END', 1), '78', 'substring #-end complex'); check_number_of_calls('substring #-end complex'); $number_of_calls = 0; - assertEquals(text_get_substring(true ? get_numbers() : null, 'FROM_END', ((0 + 3) - 1), 'FROM_END', ((0 + 2) - 1)), '78', 'substring #-end order order'); + assertEquals(text_get_substring(true ? get_numbers() : null, 'FROM_END', (0 + 3) - 1, 'FROM_END', (0 + 2) - 1), '78', 'substring #-end order order'); check_number_of_calls('substring #-end order order'); $number_of_calls = 0; assertEquals(get_numbers(), $text, 'substring first-last'); @@ -835,7 +886,7 @@ function test_substring_complex() { check_number_of_calls('substring all with #-end # complex'); $number_of_calls = 0; // Checks that the whole string is properly retrieved even if the value for start and end is not a simple number. This is especially important in generators where substring uses [x:length - y] for # #-end. - assertEquals(text_get_substring(get_numbers(), 'FROM_START', ((0 + 1) - 1), 'FROM_END', ((0 + 1) - 1)), '123456789', 'substring all with # #-end math complex'); + assertEquals(text_get_substring(get_numbers(), 'FROM_START', (0 + 1) - 1, 'FROM_END', (0 + 1) - 1), '123456789', 'substring all with # #-end math complex'); check_number_of_calls('substring all with # #-end math complex'); } @@ -908,7 +959,7 @@ function check_number_of_calls2($test_name) { } function lists_repeat($value, $count) { - $array = array(); + $array = new ListObject(); for ($index = 0; $index < $count; $index++) { $array[] = $value; } @@ -918,34 +969,34 @@ function lists_repeat($value, $count) { // Tests the "create list with" and "create empty list" blocks. function test_create_lists() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - assertEquals(array(), array(), 'create empty'); - assertEquals(array(true, 'love'), array(true, 'love'), 'create items'); - assertEquals(lists_repeat('Eject', 3), array('Eject', 'Eject', 'Eject'), 'create repeated'); - assertEquals(lists_repeat('Eject', 0 + 3), array('Eject', 'Eject', 'Eject'), 'create repeated order'); + assertEquals(new ListObject(array()), new ListObject(), 'create empty'); + assertEquals(new ListObject(array(true, 'love')), new ListObject(array(true, 'love')), 'create items'); + assertEquals(lists_repeat('Eject', 3), new ListObject(array('Eject', 'Eject', 'Eject')), 'create repeated'); + assertEquals(lists_repeat('Eject', 0 + 3), new ListObject(array('Eject', 'Eject', 'Eject')), 'create repeated order'); } // Creates an empty list for use with the empty test. function get_empty_list() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - return array(); + return new ListObject(); } // Tests the "is empty" block. function test_lists_empty() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - assertEquals(empty((array(0))), false, 'not empty'); - assertEquals(empty((array())), true, 'empty'); - assertEquals(empty((get_empty_list())), true, 'empty complex'); - assertEquals(empty((true ? array() : null)), true, 'empty order'); + assertEquals(length(new ListObject(array(0))) == 0, false, 'not empty'); + assertEquals(length(new ListObject()) == 0, true, 'empty'); + assertEquals(length(get_empty_list()) == 0, true, 'empty complex'); + assertEquals(length(true ? new ListObject() : null) == 0, true, 'empty order'); } // Tests the "length" block. function test_lists_length() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - assertEquals(length(array()), 0, 'zero length'); - assertEquals(length(array('cat')), 1, 'one length'); - assertEquals(length(array('cat', true, array())), 3, 'three length'); - assertEquals(length(true ? array('cat', true) : null), 2, 'two length order'); + assertEquals(length(new ListObject()), 0, 'zero length'); + assertEquals(length(new ListObject(array('cat'))), 1, 'one length'); + assertEquals(length(new ListObject(array('cat', true, new ListObject()))), 3, 'three length'); + assertEquals(length(true ? new ListObject(array('cat', true)) : null), 2, 'two length order'); } function lastIndexOf($haystack, $needle) { @@ -959,7 +1010,7 @@ function lastIndexOf($haystack, $needle) { // Tests the "find" block with a variable. function test_find_lists_simple() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Alice', 'Eve', 'Bob', 'Eve'); + $list2 = new ListObject(array('Alice', 'Eve', 'Bob', 'Eve')); assertEquals(indexOf($list2, 'Eve'), 2, 'find first simple'); assertEquals(lastIndexOf($list2, 'Eve'), 4, 'find last simple'); assertEquals(indexOf($list2, 'Dave'), 0, 'find none simple'); @@ -969,7 +1020,7 @@ function test_find_lists_simple() { function get_names() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; $number_of_calls += 1; - return array('Alice', 'Eve', 'Bob', 'Eve'); + return new ListObject(array('Alice', 'Eve', 'Bob', 'Eve')); } // Tests the "find" block with a function call. @@ -979,19 +1030,19 @@ function test_find_lists_complex() { assertEquals(indexOf(get_names(), 'Eve'), 2, 'find first complex'); check_number_of_calls('find first complex'); $number_of_calls = 0; - assertEquals(indexOf((true ? get_names() : null), 'Eve'), 2, 'find first order complex'); + assertEquals(indexOf(true ? get_names() : null, 'Eve'), 2, 'find first order complex'); check_number_of_calls('find first order complex'); $number_of_calls = 0; assertEquals(lastIndexOf(get_names(), 'Eve'), 4, 'find last complex'); check_number_of_calls('find last complex'); $number_of_calls = 0; - assertEquals(lastIndexOf((true ? get_names() : null), 'Eve'), 4, 'find last order complex'); + assertEquals(lastIndexOf(true ? get_names() : null, 'Eve'), 4, 'find last order complex'); check_number_of_calls('find last order complex'); $number_of_calls = 0; assertEquals(indexOf(get_names(), 'Dave'), 0, 'find none complex'); check_number_of_calls('find none complex'); $number_of_calls = 0; - assertEquals(indexOf((true ? get_names() : null), 'Dave'), 0, 'find none order complex'); + assertEquals(indexOf(true ? get_names() : null, 'Dave'), 0, 'find none order complex'); check_number_of_calls('find none order complex'); } @@ -1002,52 +1053,52 @@ function lists_get_random_item($list) { // Tests the "get" block with a variable. function test_get_lists_simple() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Kirk', 'Spock', 'McCoy'); - assertEquals($list2[0], 'Kirk', 'get first simple'); - assertEquals(end($list2), 'McCoy', 'get last simple'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + assertEquals($list2->slice(0, 1)[0], 'Kirk', 'get first simple'); + assertEquals($list2->slice(-1)[0], 'McCoy', 'get last simple'); assertEquals(indexOf($list2, lists_get_random_item($list2)) > 0, true, 'get random simple'); assertEquals($list2[1], 'Spock', 'get # simple'); - assertEquals($list2[((true ? 2 : null) - 1)], 'Spock', 'get # order simple'); - assertEquals(array_slice($list2, -3, 1)[0], 'Kirk', 'get #-end simple'); + assertEquals($list2[(true ? 2 : null) - 1], 'Spock', 'get # order simple'); + assertEquals($list2->slice(-3, 1)[0], 'Kirk', 'get #-end simple'); // The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. - assertEquals(array_slice($list2, (-(0 + 3)), 1)[0], 'Kirk', 'get #-end order simple'); + assertEquals($list2->slice(-(0 + 3), 1)[0], 'Kirk', 'get #-end order simple'); } // Tests the "get" block with create list call. function test_get_lists_create_list() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - assertEquals(array('Kirk', 'Spock', 'McCoy')[0], 'Kirk', 'get first create list'); - assertEquals(end(array('Kirk', 'Spock', 'McCoy')), 'McCoy', 'get last simple'); - assertEquals(indexOf(array('Kirk', 'Spock', 'McCoy'), lists_get_random_item(array('Kirk', 'Spock', 'McCoy'))) > 0, true, 'get random simple'); - assertEquals(array('Kirk', 'Spock', 'McCoy')[1], 'Spock', 'get # simple'); - assertEquals(array('Kirk', 'Spock', 'McCoy')[((true ? 2 : null) - 1)], 'Spock', 'get # order simple'); - assertEquals(array_slice(array('Kirk', 'Spock', 'McCoy'), -3, 1)[0], 'Kirk', 'get #-end simple'); + assertEquals((new ListObject(array('Kirk', 'Spock', 'McCoy')))->slice(0, 1)[0], 'Kirk', 'get first create list'); + assertEquals((new ListObject(array('Kirk', 'Spock', 'McCoy')))->slice(-1)[0], 'McCoy', 'get last simple'); + assertEquals(indexOf(new ListObject(array('Kirk', 'Spock', 'McCoy')), lists_get_random_item(new ListObject(array('Kirk', 'Spock', 'McCoy')))) > 0, true, 'get random simple'); + assertEquals((new ListObject(array('Kirk', 'Spock', 'McCoy')))[1], 'Spock', 'get # simple'); + assertEquals((new ListObject(array('Kirk', 'Spock', 'McCoy')))[(true ? 2 : null) - 1], 'Spock', 'get # order simple'); + assertEquals((new ListObject(array('Kirk', 'Spock', 'McCoy')))->slice(-3, 1)[0], 'Kirk', 'get #-end simple'); // The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. - assertEquals(array_slice(array('Kirk', 'Spock', 'McCoy'), (-(0 + 3)), 1)[0], 'Kirk', 'get #-end order simple'); + assertEquals((new ListObject(array('Kirk', 'Spock', 'McCoy')))->slice(-(0 + 3), 1)[0], 'Kirk', 'get #-end order simple'); } // Creates a list for use with the get test. function get_star_wars() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; $number_of_calls += 1; - return array('Kirk', 'Spock', 'McCoy'); + return new ListObject(array('Kirk', 'Spock', 'McCoy')); } // Tests the "get" block with a function call. function test_get_lists_complex() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Kirk', 'Spock', 'McCoy'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); $number_of_calls = 0; - assertEquals(get_star_wars()[0], 'Kirk', 'get first complex'); + assertEquals(get_star_wars()->slice(0, 1)[0], 'Kirk', 'get first complex'); check_number_of_calls('get first complex'); $number_of_calls = 0; - assertEquals((true ? get_star_wars() : null)[0], 'Kirk', 'get first order complex'); + assertEquals((true ? get_star_wars() : null)->slice(0, 1)[0], 'Kirk', 'get first order complex'); check_number_of_calls('get first order complex'); $number_of_calls = 0; - assertEquals(end(get_star_wars()), 'McCoy', 'get last complex'); + assertEquals(get_star_wars()->slice(-1)[0], 'McCoy', 'get last complex'); check_number_of_calls('get last complex'); $number_of_calls = 0; - assertEquals(end(true ? get_star_wars() : null), 'McCoy', 'get last order complex'); + assertEquals((true ? get_star_wars() : null)->slice(-1)[0], 'McCoy', 'get last order complex'); check_number_of_calls('get last order complex'); $number_of_calls = 0; assertEquals(indexOf($list2, lists_get_random_item(get_star_wars())) > 0, true, 'get random complex'); @@ -1059,223 +1110,223 @@ function test_get_lists_complex() { assertEquals(get_star_wars()[1], 'Spock', 'get # complex'); check_number_of_calls('get # complex'); $number_of_calls = 0; - assertEquals((true ? get_star_wars() : null)[((true ? 2 : null) - 1)], 'Spock', 'get # order complex'); + assertEquals((true ? get_star_wars() : null)[(true ? 2 : null) - 1], 'Spock', 'get # order complex'); check_number_of_calls('get # order complex'); $number_of_calls = 0; - assertEquals(array_slice(get_star_wars(), -3, 1)[0], 'Kirk', 'get #-end complex'); + assertEquals(get_star_wars()->slice(-3, 1)[0], 'Kirk', 'get #-end complex'); check_number_of_calls('get #-end complex'); $number_of_calls = 0; // The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. - assertEquals(array_slice(true ? get_star_wars() : null, (-(0 + 3)), 1)[0], 'Kirk', 'get #-end order complex'); + assertEquals((true ? get_star_wars() : null)->slice(-(0 + 3), 1)[0], 'Kirk', 'get #-end order complex'); check_number_of_calls('get #-end order complex'); } -function lists_get_remove_random_item(&$list) { +function lists_get_remove_random_item($list) { $x = rand(0,count($list)-1); - unset($list[$x]); - return array_values($list); + return $list->splice($x, 1)[0]; +} + +function lists_get_remove($list, $at) { + return $list->splice(count($list) - $at, 1)[0]; } // Tests the "get and remove" block. function test_getRemove() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Kirk', 'Spock', 'McCoy'); - assertEquals(array_shift($list2), 'Kirk', 'getremove first'); - assertEquals($list2, array('Spock', 'McCoy'), 'getremove first list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - assertEquals(array_shift(true ? $list2 : null), 'Kirk', 'getremove first order'); - assertEquals($list2, array('Spock', 'McCoy'), 'getremove first order list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - assertEquals(array_pop($list2), 'McCoy', 'getremove last'); - assertEquals($list2, array('Kirk', 'Spock'), 'getremove last list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - assertEquals(array_pop(true ? $list2 : null), 'McCoy', 'getremove last order'); - assertEquals($list2, array('Kirk', 'Spock'), 'getremove last order list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + assertEquals($list2->shift(), 'Kirk', 'getremove first'); + assertEquals($list2, new ListObject(array('Spock', 'McCoy')), 'getremove first list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + assertEquals((true ? $list2 : null)->shift(), 'Kirk', 'getremove first order'); + assertEquals($list2, new ListObject(array('Spock', 'McCoy')), 'getremove first order list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + assertEquals($list2->pop(), 'McCoy', 'getremove last'); + assertEquals($list2, new ListObject(array('Kirk', 'Spock')), 'getremove last list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + assertEquals((true ? $list2 : null)->pop(), 'McCoy', 'getremove last order'); + assertEquals($list2, new ListObject(array('Kirk', 'Spock')), 'getremove last order list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); assertEquals(indexOf($list2, lists_get_remove_random_item($list2)) == 0, true, 'getremove random'); assertEquals(length($list2), 2, 'getremove random list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); assertEquals(indexOf($list2, lists_get_remove_random_item(true ? $list2 : null)) == 0, true, 'getremove random order'); assertEquals(length($list2), 2, 'getremove random order list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - assertEquals(array_splice($list2, 1, 1)[0], 'Spock', 'getremove #'); - assertEquals($list2, array('Kirk', 'McCoy'), 'getremove # list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - assertEquals(array_splice(true ? $list2 : null, ((true ? 2 : null) - 1), 1)[0], 'Spock', 'getremove # order'); - assertEquals($list2, array('Kirk', 'McCoy'), 'getremove # order list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - assertEquals(array_splice($list2, count($list2) - 3, 1)[0], 'Kirk', 'getremove #-end'); - assertEquals($list2, array('Spock', 'McCoy'), 'getremove #-end list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + assertEquals($list2->splice(1, 1)[0], 'Spock', 'getremove #'); + assertEquals($list2, new ListObject(array('Kirk', 'McCoy')), 'getremove # list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + assertEquals((true ? $list2 : null)->splice((true ? 2 : null) - 1, 1)[0], 'Spock', 'getremove # order'); + assertEquals($list2, new ListObject(array('Kirk', 'McCoy')), 'getremove # order list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + assertEquals(lists_get_remove($list2, 3), 'Kirk', 'getremove #-end'); + assertEquals($list2, new ListObject(array('Spock', 'McCoy')), 'getremove #-end list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); // The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. - assertEquals(array_splice(true ? $list2 : null, count(true ? $list2 : null) - (0 + 3), 1)[0], 'Kirk', 'getremove #-end order'); - assertEquals($list2, array('Spock', 'McCoy'), 'getremove #-end order list'); + assertEquals(lists_get_remove(true ? $list2 : null, 0 + 3), 'Kirk', 'getremove #-end order'); + assertEquals($list2, new ListObject(array('Spock', 'McCoy')), 'getremove #-end order list'); } -function lists_remove_random_item(&$list) { - unset($list[rand(0,count($list)-1)]); +function lists_remove_random_item($list) { + $list->offsetUnset(rand(0,count($list)-1)); + $list->exchangeArray(array_values($list->getArrayCopy())); } // Tests the "remove" block. function test_remove() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Kirk', 'Spock', 'McCoy'); - array_shift($list2); - assertEquals($list2, array('Spock', 'McCoy'), 'remove first list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - array_shift(true ? $list2 : null); - assertEquals($list2, array('Spock', 'McCoy'), 'remove first order list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - array_pop($list2); - assertEquals($list2, array('Kirk', 'Spock'), 'remove last list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - array_pop(true ? $list2 : null); - assertEquals($list2, array('Kirk', 'Spock'), 'remove last order list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + $list2->shift(); + assertEquals($list2, new ListObject(array('Spock', 'McCoy')), 'remove first list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + (true ? $list2 : null)->shift(); + assertEquals($list2, new ListObject(array('Spock', 'McCoy')), 'remove first order list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + $list2->pop(); + assertEquals($list2, new ListObject(array('Kirk', 'Spock')), 'remove last list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + (true ? $list2 : null)->pop(); + assertEquals($list2, new ListObject(array('Kirk', 'Spock')), 'remove last order list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); lists_remove_random_item($list2); assertEquals(length($list2), 2, 'remove random list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); lists_remove_random_item(true ? $list2 : null); assertEquals(length($list2), 2, 'remove random order list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - array_splice($list2, 1, 1); - assertEquals($list2, array('Kirk', 'McCoy'), 'remove # list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - array_splice(true ? $list2 : null, ((true ? 2 : null) - 1), 1); - assertEquals($list2, array('Kirk', 'McCoy'), 'remove # order list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); - array_splice($list2, count($list2) - 3, 1)[0]; - assertEquals($list2, array('Spock', 'McCoy'), 'remove #-end list'); - $list2 = array('Kirk', 'Spock', 'McCoy'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + $list2->splice(1, 1); + assertEquals($list2, new ListObject(array('Kirk', 'McCoy')), 'remove # list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + (true ? $list2 : null)->splice((true ? 2 : null) - 1, 1); + assertEquals($list2, new ListObject(array('Kirk', 'McCoy')), 'remove # order list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); + lists_get_remove($list2, 3); + assertEquals($list2, new ListObject(array('Spock', 'McCoy')), 'remove #-end list'); + $list2 = new ListObject(array('Kirk', 'Spock', 'McCoy')); // The order for index for #-end is addition because this will catch // errors in generators where most perform the operation ... - index. - array_splice(true ? $list2 : null, count(true ? $list2 : null) - (0 + 3), 1)[0]; - assertEquals($list2, array('Spock', 'McCoy'), 'remove #-end order list'); -} - -function lists_set_last_item(&$list, $value) { - $list[count($list) - 1] = $value; + lists_get_remove(true ? $list2 : null, 0 + 3); + assertEquals($list2, new ListObject(array('Spock', 'McCoy')), 'remove #-end order list'); } -function lists_set_from_end(&$list, $at, $value) { +function lists_set_from_end($list, $at, $value) { $list[count($list) - $at] = $value; } // Tests the "set" block. function test_set() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Picard', 'Riker', 'Crusher'); - $list2[0] = 'Jean-Luc'; - assertEquals($list2, array('Jean-Luc', 'Riker', 'Crusher'), 'set first list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - (true ? $list2 : null)[0] = 'Jean-Luc'; - assertEquals($list2, array('Jean-Luc', 'Riker', 'Crusher'), 'set first order list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - lists_set_last_item($list2, 'Beverly'); - assertEquals($list2, array('Picard', 'Riker', 'Beverly'), 'set last list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - lists_set_last_item(true ? $list2 : null, 'Beverly'); - assertEquals($list2, array('Picard', 'Riker', 'Beverly'), 'set last order list'); - $list2 = array('Picard', 'Riker', 'Crusher'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + $list2->splice(0, 1, ['Jean-Luc']); + assertEquals($list2, new ListObject(array('Jean-Luc', 'Riker', 'Crusher')), 'set first list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + (true ? $list2 : null)->splice(0, 1, ['Jean-Luc']); + assertEquals($list2, new ListObject(array('Jean-Luc', 'Riker', 'Crusher')), 'set first order list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + $list2->splice(-1, 1, ['Beverly']); + assertEquals($list2, new ListObject(array('Picard', 'Riker', 'Beverly')), 'set last list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + (true ? $list2 : null)->splice(-1, 1, ['Beverly']); + assertEquals($list2, new ListObject(array('Picard', 'Riker', 'Beverly')), 'set last order list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); $tmp_x = rand(0, count($list2)-1); $list2[$tmp_x] = 'Data'; assertEquals(length($list2), 3, 'set random list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - $tmp_list = &(true ? $list2 : null); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + $tmp_list = true ? $list2 : null; $tmp_x2 = rand(0, count($tmp_list)-1); $tmp_list[$tmp_x2] = 'Data'; assertEquals(length($list2), 3, 'set random order list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - $list2[2] = 'Pulaski'; - assertEquals($list2, array('Picard', 'Riker', 'Pulaski'), 'set # list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - (true ? $list2 : null)[((true ? 3 : null) - 1)] = 'Pulaski'; - assertEquals($list2, array('Picard', 'Riker', 'Pulaski'), 'set # order list'); - $list2 = array('Picard', 'Riker', 'Crusher'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + $list2->splice(2, 1, ['Pulaski']); + assertEquals($list2, new ListObject(array('Picard', 'Riker', 'Pulaski')), 'set # list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + (true ? $list2 : null)->splice((true ? 3 : null) - 1, 1, ['Pulaski']); + assertEquals($list2, new ListObject(array('Picard', 'Riker', 'Pulaski')), 'set # order list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); lists_set_from_end($list2, 1, 'Pulaski'); - assertEquals($list2, array('Picard', 'Riker', 'Pulaski'), 'set #-end list'); - $list2 = array('Picard', 'Riker', 'Crusher'); + assertEquals($list2, new ListObject(array('Picard', 'Riker', 'Pulaski')), 'set #-end list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); // The order for index for #-end is addition because this will catch // errors in generators where most perform the operation ... - index. lists_set_from_end(true ? $list2 : null, 0 + 2, 'Pulaski'); - assertEquals($list2, array('Picard', 'Pulaski', 'Crusher'), 'set #-end order list'); + assertEquals($list2, new ListObject(array('Picard', 'Pulaski', 'Crusher')), 'set #-end order list'); } -function lists_insert_from_end(&$list, $at, $value) { - return array_splice($list, count($list) - $at, 0, $value); +function lists_insert_from_end($list, $at, $value) { + return $list->splice(count($list) - $at, 0, [$value]); } // Tests the "insert" block. function test_insert() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Picard', 'Riker', 'Crusher'); - array_unshift($list2, 'Data'); - assertEquals($list2, array('Data', 'Picard', 'Riker', 'Crusher'), 'insert first list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - array_unshift(true ? $list2 : null, 'Data'); - assertEquals($list2, array('Data', 'Picard', 'Riker', 'Crusher'), 'insert first order list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - array_push($list2, 'Data'); - assertEquals($list2, array('Picard', 'Riker', 'Crusher', 'Data'), 'insert last list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - array_push(true ? $list2 : null, 'Data'); - assertEquals($list2, array('Picard', 'Riker', 'Crusher', 'Data'), 'insert last order list'); - $list2 = array('Picard', 'Riker', 'Crusher'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + $list2->unshift('Data'); + assertEquals($list2, new ListObject(array('Data', 'Picard', 'Riker', 'Crusher')), 'insert first list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + (true ? $list2 : null)->unshift('Data'); + assertEquals($list2, new ListObject(array('Data', 'Picard', 'Riker', 'Crusher')), 'insert first order list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + $list2->append('Data'); + assertEquals($list2, new ListObject(array('Picard', 'Riker', 'Crusher', 'Data')), 'insert last list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + (true ? $list2 : null)->append('Data'); + assertEquals($list2, new ListObject(array('Picard', 'Riker', 'Crusher', 'Data')), 'insert last order list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); $tmp_x3 = rand(0, count($list2)-1); - array_splice($list2, $tmp_x3, 0, 'Data'); + $list2->splice($tmp_x3, 0, ['Data']); assertEquals(length($list2), 4, 'insert random list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - $tmp_list2 = &(true ? $list2 : null); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + $tmp_list2 = true ? $list2 : null; $tmp_x4 = rand(0, count($tmp_list2)-1); - array_splice($tmp_list2, $tmp_x4, 0, 'Data'); + $tmp_list2->splice($tmp_x4, 0, ['Data']); assertEquals(length($list2), 4, 'insert random order list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - array_splice($list2, 2, 0, 'Data'); - assertEquals($list2, array('Picard', 'Riker', 'Data', 'Crusher'), 'insert # list'); - $list2 = array('Picard', 'Riker', 'Crusher'); - array_splice(true ? $list2 : null, ((true ? 3 : null) - 1), 0, 'Data'); - assertEquals($list2, array('Picard', 'Riker', 'Data', 'Crusher'), 'insert # order list'); - $list2 = array('Picard', 'Riker', 'Crusher'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + $list2->splice(2, 0, ['Data']); + assertEquals($list2, new ListObject(array('Picard', 'Riker', 'Data', 'Crusher')), 'insert # list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); + (true ? $list2 : null)->splice((true ? 3 : null) - 1, 0, ['Data']); + assertEquals($list2, new ListObject(array('Picard', 'Riker', 'Data', 'Crusher')), 'insert # order list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); lists_insert_from_end($list2, 1, 'Data'); - assertEquals($list2, array('Picard', 'Riker', 'Data', 'Crusher'), 'insert #-end list'); - $list2 = array('Picard', 'Riker', 'Crusher'); + assertEquals($list2, new ListObject(array('Picard', 'Riker', 'Data', 'Crusher')), 'insert #-end list'); + $list2 = new ListObject(array('Picard', 'Riker', 'Crusher')); // The order for index for #-end is addition because this will catch // errors in generators where most perform the operation ... - index. lists_insert_from_end(true ? $list2 : null, 0 + 2, 'Data'); - assertEquals($list2, array('Picard', 'Data', 'Riker', 'Crusher'), 'insert #-end order list'); + assertEquals($list2, new ListObject(array('Picard', 'Data', 'Riker', 'Crusher')), 'insert #-end order list'); } // Tests the "get sub-list" block with a variable. function test_sublist_simple() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Columbia', 'Challenger', 'Discovery', 'Atlantis', 'Endeavour'); - assertEquals(array_slice($list2, 1, 2 - 1 + 1), array('Challenger', 'Discovery'), 'sublist # simple'); - assertEquals(array_slice($list2, ((true ? 2 : null) - 1), ((true ? 3 : null) - 1) - ((true ? 2 : null) - 1) + 1), array('Challenger', 'Discovery'), 'sublist # simple order'); - assertEquals(array_slice($list2, count($list2) - 3, count($list2) - 1 - (count($list2) - 3)), array('Discovery', 'Atlantis'), 'sublist #-end simple'); + $list2 = new ListObject(array('Columbia', 'Challenger', 'Discovery', 'Atlantis', 'Endeavour')); + assertEquals($list2->slice(1, 2 - 1 + 1), new ListObject(array('Challenger', 'Discovery')), 'sublist # simple'); + assertEquals($list2->slice(((true ? 2 : null) - 1), ((true ? 3 : null) - 1) - ((true ? 2 : null) - 1) + 1), new ListObject(array('Challenger', 'Discovery')), 'sublist # simple order'); + assertEquals($list2->slice((count($list2) - 3), count($list2) - 1 - (count($list2) - 3)), new ListObject(array('Discovery', 'Atlantis')), 'sublist #-end simple'); // The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. - assertEquals(array_slice($list2, count($list2) - (0 + 3), count($list2) - ((0 + 2) - 1) - (count($list2) - (0 + 3))), array('Discovery', 'Atlantis'), 'sublist #-end simple order'); - assertEquals($list2, $list2, 'sublist first-last simple'); - $changing_list = array('Columbia', 'Challenger', 'Discovery', 'Atlantis', 'Endeavour'); - $list_copy = $changing_list; + assertEquals($list2->slice((count($list2) - (0 + 3)), count($list2) - ((0 + 2) - 1) - (count($list2) - (0 + 3))), new ListObject(array('Discovery', 'Atlantis')), 'sublist #-end simple order'); + assertEquals(clone $list2, $list2, 'sublist first-last simple'); + $changing_list = new ListObject(array('Columbia', 'Challenger', 'Discovery', 'Atlantis', 'Endeavour')); + $list_copy = clone $changing_list; lists_remove_random_item($changing_list); assertEquals($list_copy, $list2, 'sublist first-last simple copy check'); - assertEquals(array_slice($list2, 1, count($list2) - 1 - 1), array('Challenger', 'Discovery', 'Atlantis'), 'sublist # #-end simple'); - assertEquals(array_slice($list2, count($list2) - 3, 3 - (count($list2) - 3) + 1), array('Discovery', 'Atlantis'), 'sublist #-end # simple'); - assertEquals(array_slice($list2, 0, 3 - 0 + 1), array('Columbia', 'Challenger', 'Discovery', 'Atlantis'), 'sublist first # simple'); - assertEquals(array_slice($list2, 0, count($list2) - 3 - 0), array('Columbia', 'Challenger'), 'sublist first #-end simple'); - assertEquals(array_slice($list2, 3, count($list2) - 3), array('Atlantis', 'Endeavour'), 'sublist # last simple'); - assertEquals(array_slice($list2, count($list2) - 4, count($list2) - (count($list2) - 4)), array('Challenger', 'Discovery', 'Atlantis', 'Endeavour'), 'sublist #-end last simple'); - assertEquals(array_slice($list2, 0, count($list2) - 0 - 0), $list2, 'sublist all with # #-end simple'); - assertEquals(array_slice($list2, count($list2) - 5, 4 - (count($list2) - 5) + 1), $list2, 'sublist all with #-end # simple'); + assertEquals($list2->slice(1, count($list2) - 1 - 1), new ListObject(array('Challenger', 'Discovery', 'Atlantis')), 'sublist # #-end simple'); + assertEquals($list2->slice((count($list2) - 3), 3 - (count($list2) - 3) + 1), new ListObject(array('Discovery', 'Atlantis')), 'sublist #-end # simple'); + assertEquals($list2->slice(0, 3 - 0 + 1), new ListObject(array('Columbia', 'Challenger', 'Discovery', 'Atlantis')), 'sublist first # simple'); + assertEquals($list2->slice(0, count($list2) - 3 - 0), new ListObject(array('Columbia', 'Challenger')), 'sublist first #-end simple'); + assertEquals($list2->slice(3, count($list2) - 3), new ListObject(array('Atlantis', 'Endeavour')), 'sublist # last simple'); + assertEquals($list2->slice((count($list2) - 4), count($list2) - (count($list2) - 4)), new ListObject(array('Challenger', 'Discovery', 'Atlantis', 'Endeavour')), 'sublist #-end last simple'); + assertEquals($list2->slice(0, count($list2) - 0 - 0), $list2, 'sublist all with # #-end simple'); + assertEquals($list2->slice((count($list2) - 5), 4 - (count($list2) - 5) + 1), $list2, 'sublist all with #-end # simple'); // Checks that the whole list is properly retrieved even if the value for start and end is not a simple number. This is especially important in generators where sublist uses [x:length - y] for # #-end. - assertEquals(array_slice($list2, ((0 + 1) - 1), count($list2) - ((0 + 1) - 1) - ((0 + 1) - 1)), $list2, 'sublist all with # #-end math simple'); + assertEquals($list2->slice(((0 + 1) - 1), count($list2) - ((0 + 1) - 1) - ((0 + 1) - 1)), $list2, 'sublist all with # #-end math simple'); } // Creates a list for use with the sublist test. function get_space_shuttles() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; $number_of_calls += 1; - return array('Columbia', 'Challenger', 'Discovery', 'Atlantis', 'Endeavour'); + return new ListObject(array('Columbia', 'Challenger', 'Discovery', 'Atlantis', 'Endeavour')); } function lists_get_sublist($list, $where1, $at1, $where2, $at2) { @@ -1296,45 +1347,45 @@ function lists_get_sublist($list, $where1, $at1, $where2, $at2) { } else { throw new Exception('Unhandled option (lists_get_sublist).'); } - return array_slice($list, $at1, $length); + return $list->slice($at1, $length); } // Tests the "get sub-list" block with a function call. function test_sublist_complex() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; $number_of_calls = 0; - assertEquals(array_slice(get_space_shuttles(), 1, 2 - 1 + 1), array('Challenger', 'Discovery'), 'sublist # start complex'); + assertEquals(get_space_shuttles()->slice(1, 2 - 1 + 1), new ListObject(array('Challenger', 'Discovery')), 'sublist # start complex'); check_number_of_calls('sublist # start complex'); $number_of_calls = 0; - assertEquals(array_slice(true ? get_space_shuttles() : null, ((true ? 2 : null) - 1), ((true ? 3 : null) - 1) - ((true ? 2 : null) - 1) + 1), array('Challenger', 'Discovery'), 'sublist # start order complex'); + assertEquals((true ? get_space_shuttles() : null)->slice(((true ? 2 : null) - 1), ((true ? 3 : null) - 1) - ((true ? 2 : null) - 1) + 1), new ListObject(array('Challenger', 'Discovery')), 'sublist # start order complex'); check_number_of_calls('sublist # start order complex'); $number_of_calls = 0; // The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. - assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_END', 2, 'FROM_END', 1), array('Discovery', 'Atlantis'), 'sublist # end complex'); + assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_END', 2, 'FROM_END', 1), new ListObject(array('Discovery', 'Atlantis')), 'sublist # end complex'); assertEquals($number_of_calls, 1, 'sublist # end complex number of calls'); $number_of_calls = 0; - assertEquals(lists_get_sublist(true ? get_space_shuttles() : null, 'FROM_END', ((0 + 3) - 1), 'FROM_END', ((0 + 2) - 1)), array('Discovery', 'Atlantis'), 'sublist # end order complex'); + assertEquals(lists_get_sublist((true ? get_space_shuttles() : null), 'FROM_END', (0 + 3) - 1, 'FROM_END', (0 + 2) - 1), new ListObject(array('Discovery', 'Atlantis')), 'sublist # end order complex'); check_number_of_calls('sublist # end order complex'); $number_of_calls = 0; - assertEquals(get_space_shuttles(), $list2, 'sublist first-last complex'); + assertEquals(clone get_space_shuttles(), $list2, 'sublist first-last complex'); check_number_of_calls('sublist first-last complex'); $number_of_calls = 0; - assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_START', 1, 'FROM_END', 1), array('Challenger', 'Discovery', 'Atlantis'), 'sublist # #-end complex'); + assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_START', 1, 'FROM_END', 1), new ListObject(array('Challenger', 'Discovery', 'Atlantis')), 'sublist # #-end complex'); check_number_of_calls('sublist # #-end complex'); $number_of_calls = 0; - assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_END', 2, 'FROM_START', 3), array('Discovery', 'Atlantis'), 'sublist #-end # complex'); + assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_END', 2, 'FROM_START', 3), new ListObject(array('Discovery', 'Atlantis')), 'sublist #-end # complex'); check_number_of_calls('sublist #-end # complex'); $number_of_calls = 0; - assertEquals(array_slice(get_space_shuttles(), 0, 3 - 0 + 1), array('Columbia', 'Challenger', 'Discovery', 'Atlantis'), 'sublist first # complex'); + assertEquals(get_space_shuttles()->slice(0, 3 - 0 + 1), new ListObject(array('Columbia', 'Challenger', 'Discovery', 'Atlantis')), 'sublist first # complex'); check_number_of_calls('sublist first # complex'); $number_of_calls = 0; - assertEquals(lists_get_sublist(get_space_shuttles(), 'FIRST', 0, 'FROM_END', 3), array('Columbia', 'Challenger'), 'sublist first #-end complex'); + assertEquals(lists_get_sublist(get_space_shuttles(), 'FIRST', 0, 'FROM_END', 3), new ListObject(array('Columbia', 'Challenger')), 'sublist first #-end complex'); check_number_of_calls('sublist first #-end complex'); $number_of_calls = 0; - assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_START', 3, 'LAST', 0), array('Atlantis', 'Endeavour'), 'sublist # last complex'); + assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_START', 3, 'LAST', 0), new ListObject(array('Atlantis', 'Endeavour')), 'sublist # last complex'); check_number_of_calls('sublist # last complex'); $number_of_calls = 0; - assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_END', 3, 'LAST', 0), array('Challenger', 'Discovery', 'Atlantis', 'Endeavour'), 'sublist #-end last simple'); + assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_END', 3, 'LAST', 0), new ListObject(array('Challenger', 'Discovery', 'Atlantis', 'Endeavour')), 'sublist #-end last simple'); check_number_of_calls('sublist #-end last simple'); $number_of_calls = 0; assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_START', 0, 'FROM_END', 0), $list2, 'sublist all with # #-end complex'); @@ -1344,24 +1395,24 @@ function test_sublist_complex() { check_number_of_calls('sublist all with #-end # complex'); $number_of_calls = 0; // Checks that the whole list is properly retrieved even if the value for start and end is not a simple number. This is especially important in generators where sublist uses [x:length - y] for # #-end. - assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_START', ((0 + 1) - 1), 'FROM_END', ((0 + 1) - 1)), $list2, 'sublist all with # #-end math complex'); + assertEquals(lists_get_sublist(get_space_shuttles(), 'FROM_START', (0 + 1) - 1, 'FROM_END', (0 + 1) - 1), $list2, 'sublist all with # #-end math complex'); check_number_of_calls('sublist all with # #-end math complex'); } // Tests the "join" block. function test_join() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Vulcan', 'Klingon', 'Borg'); - assertEquals(implode(',', $list2), 'Vulcan,Klingon,Borg', 'join'); - assertEquals(implode(',', true ? $list2 : null), 'Vulcan,Klingon,Borg', 'join order'); + $list2 = new ListObject(array('Vulcan', 'Klingon', 'Borg')); + assertEquals(implode(',', $list2->getArrayCopy()), 'Vulcan,Klingon,Borg', 'join'); + assertEquals(implode(',', (true ? $list2 : null)->getArrayCopy()), 'Vulcan,Klingon,Borg', 'join order'); } // Tests the "split" block. function test_split() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; $text = 'Vulcan,Klingon,Borg'; - assertEquals(explode(',', $text), array('Vulcan', 'Klingon', 'Borg'), 'split'); - assertEquals(explode(',', true ? $text : null), array('Vulcan', 'Klingon', 'Borg'), 'split order'); + assertEquals(new ListObject(explode(',', $text)), new ListObject(array('Vulcan', 'Klingon', 'Borg')), 'split'); + assertEquals(new ListObject(explode(',', true ? $text : null)), new ListObject(array('Vulcan', 'Klingon', 'Borg')), 'split order'); } function lists_sort($list, $type, $direction) { @@ -1371,46 +1422,46 @@ function lists_sort($list, $type, $direction) { 'IGNORE_CASE' => 'strcasecmp' ); $sortCmp = $sortCmpFuncs[$type]; - $list2 = $list; + $list2 = $list->getArrayCopy(); usort($list2, $sortCmp); if ($direction == -1) { $list2 = array_reverse($list2); } - return $list2; + return new ListObject($list2); } // Tests the "alphabetic sort" block. function test_sort_alphabetic() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Vulcan', 'klingon', 'Borg'); - assertEquals(lists_sort($list2, "TEXT", 1), array('Borg', 'Vulcan', 'klingon'), 'sort alphabetic ascending'); - assertEquals(lists_sort(true ? $list2 : null, "TEXT", 1), array('Borg', 'Vulcan', 'klingon'), 'sort alphabetic ascending order'); + $list2 = new ListObject(array('Vulcan', 'klingon', 'Borg')); + assertEquals(lists_sort($list2, "TEXT", 1), new ListObject(array('Borg', 'Vulcan', 'klingon')), 'sort alphabetic ascending'); + assertEquals(lists_sort(true ? $list2 : null, "TEXT", 1), new ListObject(array('Borg', 'Vulcan', 'klingon')), 'sort alphabetic ascending order'); } // Tests the "alphabetic sort ignore case" block. function test_sort_ignoreCase() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array('Vulcan', 'klingon', 'Borg'); - assertEquals(lists_sort($list2, "IGNORE_CASE", 1), array('Borg', 'klingon', 'Vulcan'), 'sort ignore case ascending'); - assertEquals(lists_sort(true ? $list2 : null, "IGNORE_CASE", 1), array('Borg', 'klingon', 'Vulcan'), 'sort ignore case ascending order'); + $list2 = new ListObject(array('Vulcan', 'klingon', 'Borg')); + assertEquals(lists_sort($list2, "IGNORE_CASE", 1), new ListObject(array('Borg', 'klingon', 'Vulcan')), 'sort ignore case ascending'); + assertEquals(lists_sort(true ? $list2 : null, "IGNORE_CASE", 1), new ListObject(array('Borg', 'klingon', 'Vulcan')), 'sort ignore case ascending order'); } // Tests the "numeric sort" block. function test_sort_numeric() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array(8, 18, -1); - assertEquals(lists_sort($list2, "NUMERIC", -1), array(18, 8, -1), 'sort numeric descending'); - assertEquals(lists_sort(true ? $list2 : null, "NUMERIC", -1), array(18, 8, -1), 'sort numeric descending order'); + $list2 = new ListObject(array(8, 18, -1)); + assertEquals(lists_sort($list2, "NUMERIC", -1), new ListObject(array(18, 8, -1)), 'sort numeric descending'); + assertEquals(lists_sort(true ? $list2 : null, "NUMERIC", -1), new ListObject(array(18, 8, -1)), 'sort numeric descending order'); } // Tests the "list reverse" block. function test_lists_reverse() { global $test_name, $naked, $proc_x, $proc_y, $func_x, $func_y, $func_a, $n, $ok, $log, $count, $varToChange, $rand, $item, $text, $number_of_calls, $list2, $proc_z, $func_z, $x, $proc_w, $func_c, $if2, $loglist, $changing_list, $list_copy, $unittestResults; - $list2 = array(8, 18, -1, 64); - assertEquals(array_reverse($list2), array(64, -1, 18, 8), 'reverse a copy'); - assertEquals($list2, array(8, 18, -1, 64), 'reverse a copy original'); - $list2 = array(); - assertEquals(array_reverse($list2), array(), 'empty list'); + $list2 = new ListObject(array(8, 18, -1, 64)); + assertEquals(new ListObject(array_reverse($list2->getArrayCopy())), new ListObject(array(64, -1, 18, 8)), 'reverse a copy'); + assertEquals($list2, new ListObject(array(8, 18, -1, 64)), 'reverse a copy original'); + $list2 = new ListObject(); + assertEquals(new ListObject(array_reverse($list2->getArrayCopy())), new ListObject(), 'empty list'); } // Describe this function... diff --git a/packages/blockly/tests/generators/unittest_php.js b/packages/blockly/tests/generators/unittest_php.js index aedd7e6a186..9fef1675084 100644 --- a/packages/blockly/tests/generators/unittest_php.js +++ b/packages/blockly/tests/generators/unittest_php.js @@ -68,6 +68,12 @@ function phpDefineAssert() { ['function ' + phpGenerator.FUNCTION_NAME_PLACEHOLDER_ + '($actual, $expected, $message) {', ' global ' + resultsVar + ';', + ' if ($actual instanceof ArrayObject) {', + ' $actual = $actual->getArrayCopy();', + ' }', + ' if ($expected instanceof ArrayObject) {', + ' $expected = $expected->getArrayCopy();', + ' }', ' // Asserts that a value equals another value.', ' if (!is_array(' + resultsVar + ')) {', ' throw new Exception("Orphaned assert: " . $message);', diff --git a/packages/plugins/block-plus-minus/test/list_create.mocha.js b/packages/plugins/block-plus-minus/test/list_create.mocha.js index e17d3b852d5..8876e11753f 100644 --- a/packages/plugins/block-plus-minus/test/list_create.mocha.js +++ b/packages/plugins/block-plus-minus/test/list_create.mocha.js @@ -114,7 +114,7 @@ suite('List create block', function () { testCases: [ { title: 'Trivial', - expectedCode: 'array(null, null, null)', + expectedCode: 'new ListObject(array(null, null, null))', createBlock: trivialCreateBlock, }, ], diff --git a/packages/plugins/block-plus-minus/test/procedures.mocha.js b/packages/plugins/block-plus-minus/test/procedures.mocha.js index a35b6518648..4e4470c248d 100644 --- a/packages/plugins/block-plus-minus/test/procedures.mocha.js +++ b/packages/plugins/block-plus-minus/test/procedures.mocha.js @@ -88,6 +88,8 @@ suite('Procedure blocks', function () { }; }; + phpGenerator.setOutputOpeningTag(false); + /** * Test suites for code generation test. * @type {Array} diff --git a/packages/plugins/field-colour/test/blocks_test.mocha.js b/packages/plugins/field-colour/test/blocks_test.mocha.js index fea374f6eba..27175d084bf 100644 --- a/packages/plugins/field-colour/test/blocks_test.mocha.js +++ b/packages/plugins/field-colour/test/blocks_test.mocha.js @@ -186,6 +186,7 @@ function checkResult(suffix, generated) { suite('Colour Block Generators', function () { suiteSetup(function () { + phpGenerator.setOutputOpeningTag(false); installAllBlocks({ javascript: javascriptGenerator, dart: dartGenerator, diff --git a/packages/plugins/field-multilineinput/test/block_test.mocha.js b/packages/plugins/field-multilineinput/test/block_test.mocha.js index d60fd2cf156..802a4fc176b 100644 --- a/packages/plugins/field-multilineinput/test/block_test.mocha.js +++ b/packages/plugins/field-multilineinput/test/block_test.mocha.js @@ -56,6 +56,7 @@ function checkResult(suffix, generated) { suite('Multiline Text Block Generators', function () { suiteSetup(function () { Blockly.setLocale(en); + phpGenerator.setOutputOpeningTag(false); installAllBlocks({ javascript: javascriptGenerator, dart: dartGenerator,