Pastakhov has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/93933


Change subject: add T_ISSET operator
......................................................................

add T_ISSET operator

* add constant FOXWAY_ALLOW_ONLY_VARIABLES for isset and unset operators
* fix T_EMPTY for tests echo_empty_array

Time: 422 ms, Memory: 25.25Mb
OK (448 tests, 454 assertions)

Change-Id: Ie27fe36386f92e514bc45379a9ada9efbd47f833
---
M includes/Compiler.php
M includes/Runtime.php
M tests/phpunit/includes/RuntimeTest.php
3 files changed, 209 insertions(+), 20 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Foxway 
refs/changes/33/93933/1

diff --git a/includes/Compiler.php b/includes/Compiler.php
index 3568bf4..596bfea 100644
--- a/includes/Compiler.php
+++ b/includes/Compiler.php
@@ -25,6 +25,7 @@
 define( 'FOXWAY_EXPECT_ARRAY_INDEX_CLOSE', 1 << 19 );
 define( 'FOXWAY_EXPECT_EQUAL_END', 1 << 20 );
 define( 'FOXWAY_EQUAL_HAVE_OPERATOR', 1 << 21 );
+define( 'FOXWAY_ALLOW_ONLY_VARIABLES', 1 << 22 );
 
 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 );
@@ -169,7 +170,7 @@
                                case T_CONSTANT_ENCAPSED_STRING: // "foo" or 
'bar'
                                case T_STRING: // true, false, null ...
                                case T_NUM_STRING: // echo "$foo[1]"; 1 is num 
string
-                                       if( $needOperator ) { throw new 
ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
+                                       if( $needOperator || $parentFlags & 
FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new ExceptionFoxway($id, 
FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
                                        $needOperator = true;
                                        $parentFlags &= 
FOXWAY_CLEAR_FLAG_FOR_VALUE;
 
@@ -268,7 +269,7 @@
                                                break;
                                        }
                                        // This is a closing double quote
-                                       if( $needOperator ) { throw new 
ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
+                                       if( $needOperator || $parentFlags & 
FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new ExceptionFoxway($id, 
FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
                                        $needOperator = true;
 
                                        $tmp = array(
@@ -292,7 +293,7 @@
                                        break;
                                case T_INC:
                                case T_DEC:
-                                       if( $stackEncapsed !== false || 
$incrementOperator ) { throw new ExceptionFoxway($id, 
FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
+                                       if( $stackEncapsed !== false || 
$incrementOperator || $parentFlags & FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new 
ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
 
                                        $precedence = 
self::$precedencesMatrix[$id];
                                        if( $needOperator ) { // $foo++
@@ -312,7 +313,7 @@
                                        break;
                                case '+':
                                case '-':
-                                       if( !$needOperator ) { // This is 
negative statement of the next value: -$foo, -5, 5 + -5 ...
+                                       if( !$needOperator && ($parentFlags & 
FOXWAY_ALLOW_ONLY_VARIABLES) == 0 ) { // This is negative statement of the next 
value: -$foo, -5, 5 + -5 ...
                                                if( $id == '-' ) { // ignore '+'
                                                        array_unshift( 
$rightOperators, array(FOXWAY_STACK_COMMAND=>$id, FOXWAY_STACK_RESULT=>null, 
FOXWAY_STACK_PARAM=>0, FOXWAY_STACK_TOKEN_LINE=>$tokenLine) );
                                                        if( 
isset($rightOperators[1]) ) { // this is not first right operator. Example: 
echo (int)-
@@ -348,7 +349,7 @@
                                case T_IS_IDENTICAL:            // ===
                                case T_IS_NOT_IDENTICAL:        // !==
                                case '?':                       // Ternary 
operator
-                                       if( !$needOperator ) { throw new 
ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
+                                       if( !$needOperator || $parentFlags & 
FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new ExceptionFoxway($id, 
FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
                                        // break is not necessary here
                                case ':': // Ternary middle
                                        if( $rightOperators ) { throw new 
ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
@@ -461,7 +462,7 @@
                                        array_pop( $values ); // remove 
T_VARIABLE from $values
                                        // break is not necessary here
                                case T_DOUBLE_ARROW:    // =>
-                                       if( !$needOperator || !$lastValue || 
$rightOperators ) { throw new ExceptionFoxway($id, 
FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
+                                       if( !$needOperator || !$lastValue || 
$rightOperators || $parentFlags & FOXWAY_ALLOW_ONLY_VARIABLES ) { 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) );
@@ -763,7 +764,7 @@
                                        //$operator = false;
                                        break;
                                case '(':
-                                       if( $needOperator ) { throw new 
ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
+                                       if( $needOperator || $parentFlags & 
FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new ExceptionFoxway($id, 
FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
 
                                        $parentheses[] = $parentFlags;
                                        $parentFlags = 
FOXWAY_EXPECT_PARENTHES_CLOSE | ($parentFlags & 
FOXWAY_CLEAR_FLAG_FOR_SHIFT_BEFORE_PARENTHESES) >> 1;
@@ -839,7 +840,7 @@
                                        self::getNextToken( $tokens, $index, 
$countTokens, $tokenLine, array('(') );
                                        break;
                                case T_ARRAY:           // array
-                                       if( $needOperator ) { throw new 
ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
+                                       if( $needOperator || $parentFlags & 
FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new ExceptionFoxway($id, 
FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
 
                                        $parentheses[] = $parentFlags;
                                        $parentFlags = 
FOXWAY_EXPECT_PARENTHES_CLOSE|FOXWAY_ALLOW_COMMA_AT_END_PARENTHES|FOXWAY_EXPECT_LIST_PARAMS|FOXWAY_THIS_IS_FUNCTION|FOXWAY_ALLOW_DOUBLE_ARROW;
@@ -868,7 +869,7 @@
                                case T_STRING_CAST:     // (string)
                                case T_BOOL_CAST:       // (bool)
                                case T_UNSET_CAST:      // (unset)
-                                       if( $needOperator ) { throw new 
ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
+                                       if( $needOperator || $parentFlags & 
FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new ExceptionFoxway($id, 
FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
 
                                        array_unshift( $rightOperators, 
array(FOXWAY_STACK_COMMAND=>$id, FOXWAY_STACK_RESULT=>null, 
FOXWAY_STACK_TOKEN_LINE=>$tokenLine) );
                                        if( isset($rightOperators[1]) ) { // 
this is not first right operator. Example: echo (int)-
@@ -1037,7 +1038,7 @@
                                        $bytecode[][] = $tmp;
                                        break;
                                case T_PRINT: // print
-                                       if( $needOperator ) { throw new 
ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
+                                       if( $needOperator || $parentFlags & 
FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new ExceptionFoxway($id, 
FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
                                        $parentheses[] = $parentFlags;
                                        $parentFlags = FOXWAY_EXPECT_SEMICOLON 
| FOXWAY_THIS_IS_FUNCTION;
 
@@ -1064,10 +1065,14 @@
                                case T_ISSET:
                                case T_UNSET:
                                case T_EMPTY:
-                                       if( $needOperator ) { throw new 
ExceptionFoxway($id, FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
+                                       if( $needOperator || $parentFlags & 
FOXWAY_ALLOW_ONLY_VARIABLES ) { throw new ExceptionFoxway($id, 
FOXWAY_PHP_SYNTAX_ERROR_UNEXPECTED, $tokenLine); }
 
                                        $parentheses[] = $parentFlags;
-                                       $parentFlags = 
FOXWAY_EXPECT_PARENTHES_CLOSE|FOXWAY_EXPECT_LIST_PARAMS|FOXWAY_THIS_IS_FUNCTION;
+                                       if( $id == T_EMPTY ) {
+                                               $parentFlags = 
FOXWAY_EXPECT_PARENTHES_CLOSE|FOXWAY_EXPECT_LIST_PARAMS|FOXWAY_THIS_IS_FUNCTION;
+                                       }else{
+                                               $parentFlags = 
FOXWAY_EXPECT_PARENTHES_CLOSE|FOXWAY_EXPECT_LIST_PARAMS|FOXWAY_THIS_IS_FUNCTION|FOXWAY_ALLOW_ONLY_VARIABLES;
+                                       }
 
                                        array_unshift( $needParams, array( 
FOXWAY_STACK_COMMAND=>$id, FOXWAY_STACK_RESULT=>null, 
FOXWAY_STACK_PARAM=>array(), FOXWAY_STACK_TOKEN_LINE=>$tokenLine ) );
 
diff --git a/includes/Runtime.php b/includes/Runtime.php
index f035d57..5f73f50 100644
--- a/includes/Runtime.php
+++ b/includes/Runtime.php
@@ -957,6 +957,34 @@
                                                        }
                                                }
                                                break;
+                                       case T_ISSET:
+                                               
foreach($value[FOXWAY_STACK_PARAM] as $val) {
+                                                       if( 
$val[FOXWAY_STACK_COMMAND] != T_VARIABLE ) { // Example: isset($foo);
+                                                               throw new 
Exception; // @todo
+                                                       }
+                                                       if( 
!isset($thisVariables[ $val[FOXWAY_STACK_PARAM] ]) ) { // undefined variable
+                                                               
$value[FOXWAY_STACK_RESULT] = false;
+                                                               break 2;
+                                                       } // true, variable is 
defined
+                                                       if( 
isset($val[FOXWAY_STACK_ARRAY_INDEX]) ) { // Example: isset($foo[1])
+                                                               $ref = 
&$thisVariables[ $val[FOXWAY_STACK_PARAM] ];
+                                                               $vn = 
array_pop( $val[FOXWAY_STACK_ARRAY_INDEX] );
+                                                               foreach( 
$val[FOXWAY_STACK_ARRAY_INDEX] as $v ) {
+                                                                       if( 
!isset($ref[$v]) ) { // undefined array index
+                                                                               
$value[FOXWAY_STACK_RESULT] = false;
+                                                                               
break 3;
+                                                                       }
+                                                                       $ref = 
&$ref[$v];
+                                                               }
+                                                               // @todo 
->>>>>>>>>>>> | ************************************************************* | 
<<<<< it only for compatible with PHP 5.4 if used PHP 5.3 @see 
http://www.php.net/manual/en/function.isset.php Example #2 isset() on String 
Offsets
+                                                               if( 
!isset($ref[$vn]) || (is_string($ref) && is_string($vn) && $vn != 
(string)(int)$vn) ) {
+                                                                       
$value[FOXWAY_STACK_RESULT] = false;
+                                                                       break 2;
+                                                               }
+                                                       } // true, variable is 
defined and have no array index
+                                               }
+                                               $value[FOXWAY_STACK_RESULT] = 
true;
+                                               break;
                                        case T_EMPTY:
                                                
foreach($value[FOXWAY_STACK_PARAM] as $val) {
                                                        if( 
$val[FOXWAY_STACK_COMMAND] == T_VARIABLE ) { // Example: empty($foo);
@@ -967,7 +995,7 @@
                                                        }else{
                                                                $ref = 
&$val[FOXWAY_STACK_RESULT];
                                                        }
-                                                       if( 
isset($val[FOXWAY_STACK_ARRAY_INDEX]) ) { // Example: $foo[1]
+                                                       if( 
isset($val[FOXWAY_STACK_ARRAY_INDEX]) ) { // Example: empty($foo[1])
                                                                $vn = 
array_pop( $val[FOXWAY_STACK_ARRAY_INDEX] );
                                                                foreach( 
$val[FOXWAY_STACK_ARRAY_INDEX] as $v ) {
                                                                        if( 
!isset($ref[$v]) ) { // undefined array index
@@ -975,16 +1003,12 @@
                                                                        }
                                                                        $ref = 
&$ref[$v];
                                                                }
-                                                               if( 
is_string($ref) ) { // @todo it only for compatible with PHP 5.4 on PHP 5.3 
@see http://www.php.net/manual/en/function.empty.php Example #2 empty() on 
String Offsets
-                                                                       if( 
(is_string($vn) && $vn == (string)(int)$vn && !empty($ref[$vn]) || 
(!is_string($vn) && !empty($ref[$vn]))) ) {
-                                                                               
$value[FOXWAY_STACK_RESULT] = false;
-                                                                               
break 2;
-                                                                       }// 
index is string
-                                                               }elseif( 
!empty($ref[$vn]) ) {
+                                                               // @todo 
->>>>>>>>>>>> | ************************************************************* | 
<<<<< it only for compatible with PHP 5.4 if used PHP 5.3 @see 
http://www.php.net/manual/en/function.empty.php Example #2 empty() on String 
Offsets
+                                                               if( 
!empty($ref[$vn]) && (is_array($ref) || !is_string($vn) || $vn == 
(string)(int)$vn) ) {
                                                                        
$value[FOXWAY_STACK_RESULT] = false;
                                                                        break 2;
                                                                }
-                                                       }elseif( !empty($ref) ) 
{ // there is no array index and empty() returns false
+                                                       }elseif( !empty($ref) ) 
{ // there is no array index and empty() returns false (PHP 5.5.0 supports 
expressions)
                                                                
$value[FOXWAY_STACK_RESULT] = false;
                                                                break 2;
                                                        }
diff --git a/tests/phpunit/includes/RuntimeTest.php 
b/tests/phpunit/includes/RuntimeTest.php
index 8e9e91c..5d02676 100644
--- a/tests/phpunit/includes/RuntimeTest.php
+++ b/tests/phpunit/includes/RuntimeTest.php
@@ -2778,6 +2778,49 @@
                                array('empty')
                                );
        }
+       public function testRun_echo_empty_array_1() {
+               $this->assertEquals(
+                               Runtime::runSource('$a = array ("test" => 1, 
"hello" => NULL, "pie" => array("a" => "apple"));
+echo empty($a["test"]) ? "true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_empty_array_2() {
+               $this->assertEquals(
+                               Runtime::runSource('echo empty($a["foo"]) ? 
"true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_empty_array_3() {
+               $this->assertEquals(
+                               Runtime::runSource('echo empty($a["hello"]) ? 
"true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_empty_array_4() {
+               $this->assertEquals(
+                               Runtime::runSource('echo empty($a["pie"]["a"]) 
? "true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_empty_array_5() {
+               $this->assertEquals(
+                               Runtime::runSource('echo empty($a["pie"]["b"]) 
? "true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_empty_array_6() {
+               $this->assertEquals(
+                               Runtime::runSource('echo 
empty($a["pie"]["a"]["b"]) ? "true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_empty_array_7() {
+               $this->assertEquals(
+                               Runtime::runSource('echo 
empty($a["pie"]["b"]["a"]) ? "true" : "false";'),
+                               array('true')
+                               );
+       }
        public function testRun_echo_empty_key_string_1() {
                $this->assertEquals(
                                Runtime::runSource('$expected_array_got_string 
= "somestring";
@@ -2815,4 +2858,121 @@
                                array('true')
                                );
        }
+
+       public function testRun_echo_isset_1() {
+               $this->assertEquals(
+                               Runtime::runSource('$var = ""; echo isset($var) 
? "true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_isset_2() {
+               $this->assertEquals(
+                               Runtime::runSource('echo isset($varForIsset) ? 
"true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_3() {
+               $this->assertEquals(
+                               Runtime::runSource('echo isset($var, 
$varForIsset) ? "true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_4() {
+               $this->assertEquals(
+                               Runtime::runSource('echo isset($varForIsset, 
$var) ? "true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_5() {
+               $this->assertEquals(
+                               Runtime::runSource('$varForIsset = "test"; echo 
isset($varForIsset, $var) ? "true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_isset_6() {
+               $this->assertEquals(
+                               Runtime::runSource('$varForIsset = NULL; echo 
isset($varForIsset, $var) ? "true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_array_1() {
+               $this->assertEquals(
+                               Runtime::runSource('$a = array ("test" => 1, 
"hello" => NULL, "pie" => array("a" => "apple"));
+echo isset($a["test"]) ? "true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_isset_array_2() {
+               $this->assertEquals(
+                               Runtime::runSource('echo isset($a["foo"]) ? 
"true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_array_3() {
+               $this->assertEquals(
+                               Runtime::runSource('echo isset($a["hello"]) ? 
"true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_array_4() {
+               $this->assertEquals(
+                               Runtime::runSource('echo isset($a["pie"]["a"]) 
? "true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_isset_array_5() {
+               $this->assertEquals(
+                               Runtime::runSource('echo isset($a["pie"]["b"]) 
? "true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_array_6() {
+               $this->assertEquals(
+                               Runtime::runSource('echo 
isset($a["pie"]["a"]["b"]) ? "true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_array_7() {
+               $this->assertEquals(
+                               Runtime::runSource('echo 
isset($a["pie"]["b"]["a"]) ? "true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_key_string_1() {
+               $this->assertEquals(
+                               Runtime::runSource('$expected_array_got_string 
= "somestring";
+echo isset($expected_array_got_string[0]) ? "true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_isset_key_string_2() {
+               $this->assertEquals(
+                               Runtime::runSource('echo 
isset($expected_array_got_string["0"]) ? "true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_isset_key_string_3() {
+               $this->assertEquals(
+                               Runtime::runSource('echo 
isset($expected_array_got_string[0.5]) ? "true" : "false";'),
+                               array('true')
+                               );
+       }
+       public function testRun_echo_isset_key_string_4() { //PHP 5.4 changes 
how isset() behaves when passed string offsets.
+               $this->assertEquals(
+                               Runtime::runSource('echo 
isset($expected_array_got_string["some_key"]) ? "true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_key_string_5() { //PHP 5.4 changes 
how isset() behaves when passed string offsets.
+               $this->assertEquals(
+                               Runtime::runSource('echo 
isset($expected_array_got_string["0.5"]) ? "true" : "false";'),
+                               array('false')
+                               );
+       }
+       public function testRun_echo_isset_key_string_6() { //PHP 5.4 changes 
how isset() behaves when passed string offsets.
+               $this->assertEquals(
+                               Runtime::runSource('echo 
isset($expected_array_got_string["0 Mostel"]) ? "true" : "false";'),
+                               array('false')
+                               );
+       }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/93933
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie27fe36386f92e514bc45379a9ada9efbd47f833
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Foxway
Gerrit-Branch: develop
Gerrit-Owner: Pastakhov <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to