jenkins-bot has submitted this change and it was merged. Change subject: add operator T_FOREACH ......................................................................
add operator T_FOREACH * show exception foxway as string * fix double variables '$bar' in $code for source 'echo "$foo[$bar]";' * fix double while without braces Time: 498 ms, Memory: 24.75Mb OK (492 tests, 498 assertions) Change-Id: Id917d91f56f0daef19fa0ee716feba284c35620c --- M Foxway.body.php M includes/Compiler.php M includes/ExceptionFoxway.php M includes/Runtime.php M tests/phpunit/includes/RuntimeTest.php 5 files changed, 198 insertions(+), 25 deletions(-) Approvals: Pastakhov: Looks good to me, approved jenkins-bot: Verified diff --git a/Foxway.body.php b/Foxway.body.php index bfcfcb5..4ffbcff 100644 --- a/Foxway.body.php +++ b/Foxway.body.php @@ -51,6 +51,8 @@ array( 'Parser'=>&$parser, 'PPFrame'=>&$frame ) ); $return = implode($result); + } catch (\Foxway\ExceptionFoxway $exc) { + $return = (string) $exc; } catch (Exception $exc) { $return = $exc->getTraceAsString(); } @@ -85,7 +87,10 @@ self::getScope($frame), array( 'Parser'=>&$parser, 'PPFrame'=>&$frame ) ); - } catch (Exception $exc) { + } catch ( \Foxway\ExceptionFoxway $exc ) { + \Foxway\Runtime::$time += microtime(true) - self::$startTime; + return (string) $exc; + } catch ( Exception $exc ) { \Foxway\Runtime::$time += microtime(true) - self::$startTime; return $exc->getTraceAsString(); } diff --git a/includes/Compiler.php b/includes/Compiler.php index 14fa2cf..8c9cbce 100644 --- a/includes/Compiler.php +++ b/includes/Compiler.php @@ -28,6 +28,7 @@ define( 'FOXWAY_ALLOW_ONLY_VARIABLES', 1 << 22 ); define( 'FOXWAY_ALLOW_SKIP_PARAMS', 1 << 23 ); // used in operator T_LIST define( 'FOXWAY_DOUBLE_ARROW_WAS_USED', 1 << 24 ); +define( 'FOXWAY_EXPECT_OPERATOR_AS', 1 << 25 ); // for operator T_FOREACH define( 'FOXWAY_CLEAR_FLAG_FOR_SHIFT_BEFORE_PARENTHESES', FOXWAY_EXPECT_PARENTHESES_WITH_LIST_PARAMS ); //define( 'FOXWAY_CLEAR_FLAG_FOR_SHIFT_AFTER_PARENTHESES', FOXWAY_EXPECT_PARENTHESES_WITH_LIST_PARAMS ); @@ -287,6 +288,7 @@ }else{ // right operator was not used $lastValue = &$tmp; } + $values = array(); // there is variables of array index. Example '$bar' for : echo "$foo[$bar]"; unset($tmp); $stackEncapsed = false; break; @@ -462,14 +464,21 @@ case T_XOR_EQUAL: // ^= case T_SL_EQUAL: // <<= case T_SR_EQUAL: // >>= + if ( $parentFlags & FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); } + // break is not necessary here case T_DOUBLE_ARROW: // => - if ( !$needOperator || !isset($lastValue) || $rightOperators || $parentFlags & FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); } + if ( !$needOperator || !isset($lastValue) || $rightOperators ) { throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); } $needOperator = false; array_unshift( $needParams, array(FOXWAY_STACK_COMMAND=>$id, FOXWAY_STACK_RESULT=>&$lastValue[FOXWAY_STACK_RESULT], FOXWAY_STACK_PARAM=>&$lastValue, FOXWAY_STACK_TOKEN_LINE=>$tokenLine) ); if ( $id == T_DOUBLE_ARROW ) { - if( $parentFlags & FOXWAY_ALLOW_DOUBLE_ARROW == 0 ) { throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); } + if ( $parentFlags & FOXWAY_ALLOW_DOUBLE_ARROW == 0 ) { throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); } $parentFlags = ( $parentFlags & ~FOXWAY_ALLOW_DOUBLE_ARROW ) | FOXWAY_DOUBLE_ARROW_WAS_USED; // Mark double arrow was used + if ( $parentFlags & FOXWAY_ALLOW_ONLY_VARIABLES ) { // T_DOUBLE_ARROW for operator T_FOREACH + array_shift( $needParams ); + unset( $lastValue ); + break; // **** EXIT **** + } } elseif ( $id == '=' ) { if ( $lastValue[FOXWAY_STACK_COMMAND] == T_VARIABLE ) { array_pop( $values ); // remove T_VARIABLE from $values @@ -521,7 +530,19 @@ if( !isset($operator) ) { $needOperator = true; } // Example: $foo[] // break is not necessary here case ')': - if( !$needOperator && !isset($operator) && $parentFlags & FOXWAY_THIS_IS_FUNCTION ) { $needOperator = true; } + if ( !$needOperator && !isset($operator) && $parentFlags & FOXWAY_THIS_IS_FUNCTION ) { $needOperator = true; } // @todo ALLOW_VOID_PARAMS + if ( $parentFlags & FOXWAY_EXPECT_PARENTHES_CLOSE && $parentFlags & FOXWAY_THIS_IS_FUNCTION && $needParams[0][FOXWAY_STACK_COMMAND] == T_FOREACH ) { + if ( $parentFlags & FOXWAY_DOUBLE_ARROW_WAS_USED ) { // T_DOUBLE_ARROW Example: while ( $foo as $key=>$value ) + $needParams[0][FOXWAY_STACK_DO_TRUE][0][FOXWAY_STACK_PARAM_2] = array( $values[0][FOXWAY_STACK_PARAM], $lastValue[FOXWAY_STACK_PARAM] ); + } else { // T_VARIABLE. Example: while ( $foo as $value ) + $needParams[0][FOXWAY_STACK_DO_TRUE][0][FOXWAY_STACK_PARAM_2] = $lastValue[FOXWAY_STACK_PARAM]; + } + $values = array(); + unset( $lastValue ); + $parentFlags = array_pop($parentheses); + $needOperator = false; + break; // **** EXIT **** + } // break is not necessary here case ',': if ( !$needOperator && !isset($lastValue) && $parentFlags & FOXWAY_ALLOW_SKIP_PARAMS ) { @@ -554,13 +575,13 @@ unset( $incompleteOperators[$parentLevel], $math[$parentLevel] ); } }elseif( isset($lastValue) ) { // Operator does not exists, but there is value. Operator and value not exists for: array() or array(1,) - if( isset($lastValue) ) { + //if( isset($lastValue) ) { $operator = &$lastValue; unset($lastValue); - }else{ // Value does not exist. Examples: echo () OR echo , OR echo ; + //}else{ // Value does not exist. Examples: echo () OR echo , OR echo ; // @todo ternary without middle - throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); - } + // throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); + //} } if( $parentFlags & FOXWAY_EXPECT_TERNARY_END ) { // Examples: echo 1?2:3, @@ -602,7 +623,7 @@ $lastValue = &$needParams[0]; array_shift($needParams); $lastValue[FOXWAY_STACK_ARRAY_INDEX][] = &$operator[FOXWAY_STACK_RESULT]; // $lastValue must be T_VARIABLE only - $stack[] = &$lastValue; + $values[] = &$lastValue; unset($operator); if( $parentFlags & FOXWAY_NEED_RESTORE_OPERATOR ) { $operator = array_pop( $memOperators ); @@ -612,22 +633,23 @@ list( $tmp, $math ) = array_pop($memory); // restore $stack, $math $s = self::mergeStackAndMath($tmp, $math); if( $s ) { - $stack = array_merge( $s, $stack ); + $stack = array_merge( $stack, $s ); } break 2; case ')': $parentLevel--; if( $parentFlags & FOXWAY_EXPECT_PARENTHES_CLOSE == 0 ) { throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); } - if( $parentFlags & FOXWAY_THIS_IS_FUNCTION ) { - if( isset($operator) ) { - if( $parentFlags & FOXWAY_EXPECT_LIST_PARAMS ) { + if ( $parentFlags & FOXWAY_THIS_IS_FUNCTION ) { + if ( isset($operator) ) { + //if( $parentFlags & FOXWAY_EXPECT_LIST_PARAMS ) { $needParams[0][FOXWAY_STACK_PARAM][] = &$operator; - if( $parentFlags & FOXWAY_EXPECT_VARIABLE_REFERENCE && $operator[FOXWAY_STACK_COMMAND] == T_VARIABLE ) { - array_pop( $stack ); // @todo refactoring - } - }else{ - throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); - } + if ( $parentFlags & FOXWAY_EXPECT_VARIABLE_REFERENCE && $operator[FOXWAY_STACK_COMMAND] == T_VARIABLE ) { // @todo refactoring + $stack = array(); // @todo refactoring + //array_pop( $stack ); // @todo refactoring + } // @todo refactoring + //}else{ + // throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); + //} unset($operator); } $operator = &$needParams[0]; // restore result of function as value, this will be set as $lastValue @@ -635,7 +657,7 @@ $stack[] = &$operator; // add function to stack } array_shift($needParams); - list( $s, $math ) = array_pop($memory); // restore $stack, $math + list( $s, $math ) = array_pop($memory); // restore $stack, $math @todo NEED_RESTORE_STACK if( $s ) { $stack = array_merge( $s, $stack ); } @@ -744,7 +766,7 @@ break; /********** EXIT **********/ }else{ // if(1) echo 2; $link = &$needParams[0]; - if( $link[FOXWAY_STACK_COMMAND] == T_WHILE ) { // T_WHILE + if( $link[FOXWAY_STACK_COMMAND] != T_IF ) { // T_WHILE, T_FOREACH $stack[] = array( FOXWAY_STACK_COMMAND=>T_CONTINUE, FOXWAY_STACK_RESULT=>1 ); // Add operator T_CONTINUE to the end of the cycle $link[FOXWAY_STACK_DO_TRUE] = array_merge( $link[FOXWAY_STACK_DO_TRUE], $stack ); $stack = array( &$link ); @@ -805,7 +827,7 @@ if( $parentFlags & FOXWAY_EXPECT_START_COMMAND == 0 ) { throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); } // for compatible with functions that use flag FOXWAY_EXPECT_LIST_PARAMS - $memory[] = array(array(), array()); + $memory[] = array( array(), array() ); // @todo NEED_RESTORE_STACK /*ksort($math); array_unshift( $memory, array($stack, $math) ); $stack = array(); @@ -963,7 +985,7 @@ array_pop($parentheses); $parentFlags = array_pop($parentheses); if( !isset($link[FOXWAY_STACK_DO_FALSE]) ) { // operator 'else' not used - if( $link[FOXWAY_STACK_COMMAND] == T_WHILE ) { + if( $link[FOXWAY_STACK_COMMAND] != T_IF ) { // T_WHILE, T_FOREACH $link[FOXWAY_STACK_DO_TRUE][] = array( FOXWAY_STACK_COMMAND=>T_CONTINUE, FOXWAY_STACK_RESULT=>1 ); // Add operator T_CONTINUE to the end of the cycle $tmp = array( &$link ); $ifOperators = array(); @@ -980,8 +1002,9 @@ break; /********** EXIT **********/ }else{ // Exsample: if(1) if(2) { echo 3; } $link = &$needParams[0]; - if( $link[FOXWAY_STACK_COMMAND] == T_WHILE ) { // T_WHILE + if( $link[FOXWAY_STACK_COMMAND] != T_IF ) { // T_WHILE, T_FOREACH $link[FOXWAY_STACK_DO_TRUE] = array_merge( $link[FOXWAY_STACK_DO_TRUE], $tmp ); + $link[FOXWAY_STACK_DO_TRUE][] = array( FOXWAY_STACK_COMMAND=>T_CONTINUE, FOXWAY_STACK_RESULT=>1 ); // Add operator T_CONTINUE to the end of the cycle $tmp = array( &$link ); }else{ // T_IF $link[FOXWAY_STACK_DO_TRUE] = $tmp; @@ -1110,6 +1133,30 @@ self::getNextToken( $tokens, $index, $countTokens, $tokenLine, array('(') ); break; + case T_FOREACH: + if ( $parentFlags & FOXWAY_EXPECT_START_COMMAND == 0 || $stack || isset($operator) || $values ) { + throw new ExceptionFoxway( $id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine ); + } + + array_unshift( $needParams, array(FOXWAY_STACK_COMMAND=>$id, FOXWAY_STACK_DO_TRUE=>array(), FOXWAY_STACK_TOKEN_LINE=>$tokenLine) ); + $parentheses[] = $parentFlags; + $parentheses[] = FOXWAY_EXPECT_START_COMMAND | FOXWAY_EXPECT_SEMICOLON | FOXWAY_EXPECT_DO_TRUE_STACK; + $parentFlags = FOXWAY_ALLOW_ONLY_VARIABLES|FOXWAY_EXPECT_OPERATOR_AS; + + self::getNextToken( $tokens, $index, $countTokens, $tokenLine, array('(') ); + break; + case T_AS: + if ( !$needOperator || !($parentFlags & FOXWAY_EXPECT_OPERATOR_AS) || !isset($lastValue) || $lastValue[FOXWAY_STACK_COMMAND] != T_VARIABLE ) { + throw new ExceptionFoxway( $id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine ); + } + $needOperator = false; + $parentFlags = FOXWAY_ALLOW_ONLY_VARIABLES|FOXWAY_EXPECT_VARIABLE_REFERENCE|FOXWAY_EXPECT_PARENTHES_CLOSE|FOXWAY_THIS_IS_FUNCTION|FOXWAY_ALLOW_DOUBLE_ARROW; + + $needParams[0][FOXWAY_STACK_PARAM] = $lastValue[FOXWAY_STACK_PARAM]; // for reset array + $needParams[0][FOXWAY_STACK_DO_TRUE][0] = array( FOXWAY_STACK_COMMAND=>$id, FOXWAY_STACK_PARAM=>$lastValue[FOXWAY_STACK_PARAM], FOXWAY_STACK_TOKEN_LINE=>$tokenLine); + unset( $lastValue ); + $values = array(); + break; default : throw new ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); break; diff --git a/includes/ExceptionFoxway.php b/includes/ExceptionFoxway.php index 1960613..980a733 100644 --- a/includes/ExceptionFoxway.php +++ b/includes/ExceptionFoxway.php @@ -17,6 +17,11 @@ define( 'FOXWAY_PHP_NOTICE_UNINIT_STRING_OFFSET', 113 ); // PHP Notice: Uninitialized string offset: $1 define( 'FOXWAY_PHP_NOTICE_UNDEFINED_CONSTANT', 114 ); // PHP Notice: Use of undefined constant $1 - assumed '$1' define( 'FOXWAY_PHP_FATAL_CANNOT_UNSET_STRING_OFFSETS', 115 ); // PHP Fatal error: Cannot unset string offsets +define( 'FOXWAY_PHP_WARNING_INVALID_ARGUMENT_FOR_FOREACH', 116 ); // PHP Warning: Invalid argument supplied for foreach() +// PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 73 bytes) +// PHP Fatal error: Maximum execution time of 30 seconds exceeded +// PHP Warning: Variable passed to each() is not an array or object + /** * Error Exception class of Foxway extension. @@ -44,6 +49,9 @@ $place = $this->place; switch ( $this->code ) { + case FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED: + $message = 'HP Parse error: syntax error, unexpected ' . ( is_string($params) ? $params : token_name($params) ); + break; case FOXWAY_PHP_WARNING_DIVISION_BY_ZERO: $message = "PHP Warning: Division by zero"; break; @@ -69,9 +77,13 @@ $message = "PHP Notice: Use of undefined constant $params - assumed '$params'"; break; case FOXWAY_PHP_FATAL_CANNOT_UNSET_STRING_OFFSETS: - $message = "PHP Fatal error: Cannot unset string offsets"; + $message = 'PHP Fatal error: Cannot unset string offsets'; + break; + case FOXWAY_PHP_WARNING_INVALID_ARGUMENT_FOR_FOREACH: + $message = 'PHP Warning: Invalid argument supplied for foreach()'; break; default: + $message = "PHP Fatal error: Undefined error, code {$this->code}"; break; } //return "$message in $place on line $line\n"; diff --git a/includes/Runtime.php b/includes/Runtime.php index 9d8c9ae..36f99ca 100644 --- a/includes/Runtime.php +++ b/includes/Runtime.php @@ -255,6 +255,19 @@ } } break; + case T_FOREACH: + $vn = $value[FOXWAY_STACK_PARAM]; // Variable name + if ( !array_key_exists($vn, $thisVariables) ) { + $return[] = (string) new ExceptionFoxway( $vn, FOXWAY_PHP_NOTICE_UNDEFINED_VARIABLE, $value[FOXWAY_STACK_TOKEN_LINE], $place ); + $return[] = (string) new ExceptionFoxway( null, FOXWAY_PHP_WARNING_INVALID_ARGUMENT_FOR_FOREACH, $value[FOXWAY_STACK_TOKEN_LINE], $place ); + break; // **** EXIT **** + } + if ( !is_array($thisVariables[ $value[FOXWAY_STACK_PARAM] ]) ) { + $return[] = (string) new ExceptionFoxway( null, FOXWAY_PHP_WARNING_INVALID_ARGUMENT_FOR_FOREACH, $value[FOXWAY_STACK_TOKEN_LINE], $place ); + break; // **** EXIT **** + } + reset( $thisVariables[ $value[FOXWAY_STACK_PARAM] ] ); + // break is not necessary here case T_WHILE: // PHP code "while($foo) { ... }" doing as T_WHILE { T_DO($foo) ... }. If $foo == false, T_DO doing as T_BREAK $memory[] = array( null, $code, $i, $c, $loopsOwner ); $code = $value[FOXWAY_STACK_DO_TRUE]; @@ -267,6 +280,17 @@ continue; // this is "while(true)", just go next }// while(false) doing as T_BREAK; break 2; // go to one level down + case T_AS: + if ( is_string($value[FOXWAY_STACK_PARAM_2]) ) { // T_VARIABLE. Example: while ( $foo as $value ) + if ( !list(,$thisVariables[ $value[FOXWAY_STACK_PARAM_2] ]) = each($thisVariables[ $value[FOXWAY_STACK_PARAM] ]) ) { + break 2; // go to one level down + } + } else { // T_DOUBLE_ARROW Example: while ( $foo as $key=>$value ) + if ( !list($thisVariables[ $value[FOXWAY_STACK_PARAM_2][0] ], $thisVariables[ $value[FOXWAY_STACK_PARAM_2][1] ]) = each($thisVariables[ $value[FOXWAY_STACK_PARAM] ]) ) { + break 2; // go to one level down + } + } + break; case T_BREAK: $break = $value[FOXWAY_STACK_RESULT]; if( $loopsOwner == T_WHILE ) { diff --git a/tests/phpunit/includes/RuntimeTest.php b/tests/phpunit/includes/RuntimeTest.php index 43a1ebb..b0d98e8 100644 --- a/tests/phpunit/includes/RuntimeTest.php +++ b/tests/phpunit/includes/RuntimeTest.php @@ -1768,6 +1768,24 @@ '|1|(1)|2|(1)(2)|3|(1)(2)(3)' ); } + public function testRun_while_while_2() { + $this->assertEquals( + Runtime::runSource('$i=1; $y=2; while($i++<4 && $y--) { while($y<5) { echo $y++; } }'), + array(1, 2, 3, 4, 4, 4) + ); + } + public function testRun_while_while_3() { + $this->assertEquals( + Runtime::runSource('$i=1; $y=2; while($i++<4 && $y--) while($y<5) { echo $y++; }'), + array(1, 2, 3, 4, 4, 4) + ); + } + public function testRun_while_while_4() { + $this->assertEquals( + Runtime::runSource('$i=1; $y=2; while($i++<4 && $y--) while($y<5) echo $y++;'), + array(1, 2, 3, 4, 4, 4) + ); + } public function testRun_while_while_continue_1() { $this->assertEquals( implode( Runtime::runSource('$i=1; while( $i<=3 ){ echo "|$i|"; $y=0; while( $y<3 ){ $y++; if( $y==2) continue; echo "($y)"; } $i++; }') ), @@ -3034,4 +3052,71 @@ ); } + public function testRun_foreach_1() { + $this->assertEquals( + Runtime::runSource('$arr = array("one", "two", "three"); foreach ($arr as $value) echo "* Value: $value\n";'), + array("* Value: one\n", "* Value: two\n", "* Value: three\n") + ); + } + public function testRun_foreach_2() { + $this->assertEquals( + Runtime::runSource('foreach ($arr as $value) { echo "* Value: $value\n"; }'), + array("* Value: one\n", "* Value: two\n", "* Value: three\n") + ); + } + public function testRun_foreach_3() { + $this->assertEquals( + Runtime::runSource('$arr = array("one", "two", "three"); foreach ($arr as $value) echo "* Value: $value\n"; echo "end";'), + array("* Value: one\n", "* Value: two\n", "* Value: three\n", 'end') + ); + } + public function testRun_foreach_4() { + $this->assertEquals( + Runtime::runSource('foreach ($arr as $value) { echo "* Value: $value\n"; } echo "end";'), + array("* Value: one\n", "* Value: two\n", "* Value: three\n", 'end') + ); + } + public function testRun_foreach_5() { + $this->assertEquals( + Runtime::runSource('foreach ($arr as $key => $value) { echo $key, $value; }'), + array(0, 'one', 1, 'two', 2, 'three') + ); + } + public function testRun_foreach_6() { + $this->assertEquals( + Runtime::runSource('foreach ($arr as $key => $value) echo "* Key: $key; Value: $value\n"; echo "end";'), + array("* Key: 0; Value: one\n", "* Key: 1; Value: two\n", "* Key: 2; Value: three\n", 'end') + ); + } + public function testRun_foreach_7() { + $this->assertEquals( + Runtime::runSource('foreach ($arr as $key => $value) { echo "* Key: $key; Value: $value\n"; } echo "end";'), + array("* Key: 0; Value: one\n", "* Key: 1; Value: two\n", "* Key: 2; Value: three\n", 'end') + ); + } + public function testRun_foreach_8() { + $this->assertEquals( + Runtime::runSource('$a = array("one" => 1,"two" => 2,"three" => 3,"seventeen" => 17); foreach ($a as $k => $v) {echo "\$a[$k] => $v.";}'), + array('$a[one] => 1.', '$a[two] => 2.', '$a[three] => 3.', '$a[seventeen] => 17.') + ); + } + public function testRun_foreach_9() { + $this->assertEquals( + Runtime::runSource('$a=array(); $a[0][0]="a"; $a[0][1]="b"; $a[1][0]="y"; $a[1][1]="z"; foreach ($a as $v1) { foreach ($v1 as $v2) { echo $v2; } }'), + array('a', 'b', 'y', 'z') + ); + } + public function testRun_foreach_10() { + $this->assertEquals( + Runtime::runSource('foreach ($a as $v1) foreach ($v1 as $v2) { echo $v2; }'), + array('a', 'b', 'y', 'z') + ); + } + public function testRun_foreach_11() { + $this->assertEquals( + Runtime::runSource('foreach ($a as $v1) foreach ($v1 as $v2) echo $v2;'), + array('a', 'b', 'y', 'z') + ); + } + } -- To view, visit https://gerrit.wikimedia.org/r/94874 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Id917d91f56f0daef19fa0ee716feba284c35620c Gerrit-PatchSet: 2 Gerrit-Project: mediawiki/extensions/Foxway Gerrit-Branch: develop Gerrit-Owner: Pastakhov <pastak...@yandex.ru> Gerrit-Reviewer: Pastakhov <pastak...@yandex.ru> Gerrit-Reviewer: jenkins-bot _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits