Pastakhov has uploaded a new change for review. https://gerrit.wikimedia.org/r/191858
Change subject: new Runtime (v 5.0.0) ...................................................................... new Runtime (v 5.0.0) Change-Id: Idbfcca925f6668a6d1ec9810e6f8c1df75c31c58 --- M PhpTags.php M includes/Compiler.php M includes/PhpTagsException.php M includes/Runtime.php 4 files changed, 1,334 insertions(+), 714 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/PhpTags refs/changes/58/191858/1 diff --git a/PhpTags.php b/PhpTags.php index 916b474..700ccfe 100644 --- a/PhpTags.php +++ b/PhpTags.php @@ -15,13 +15,13 @@ die( 'This file is an extension to MediaWiki and thus not a valid entry point.' ); } -const PHPTAGS_MAJOR_VERSION = 4; -const PHPTAGS_MINOR_VERSION = 2; +const PHPTAGS_MAJOR_VERSION = 5; +const PHPTAGS_MINOR_VERSION = 0; const PHPTAGS_RELEASE_VERSION = 0; define( 'PHPTAGS_VERSION', PHPTAGS_MAJOR_VERSION . '.' . PHPTAGS_MINOR_VERSION . '.' . PHPTAGS_RELEASE_VERSION ); const PHPTAGS_HOOK_RELEASE = 6; -const PHPTAGS_RUNTIME_RELEASE = 3; +const PHPTAGS_RUNTIME_RELEASE = 4; const PHPTAGS_JSONLOADER_RELEASE = 1; // Register this extension on Special:Version diff --git a/includes/Compiler.php b/includes/Compiler.php index 4d74bf7..47d7fd4 100644 --- a/includes/Compiler.php +++ b/includes/Compiler.php @@ -17,6 +17,9 @@ */ class Compiler { + // += -= *= /= .= %= &= |= ^= <<= >>= + protected static $assignmentOperators = array( '=', T_PLUS_EQUAL, T_MINUS_EQUAL, T_MUL_EQUAL, T_DIV_EQUAL, T_CONCAT_EQUAL, T_MOD_EQUAL, T_AND_EQUAL, T_OR_EQUAL, T_XOR_EQUAL, T_SL_EQUAL, T_SR_EQUAL ); + /** * Operator Precedence * @see http://www.php.net/manual/en/language.operators.precedence.php @@ -41,8 +44,7 @@ array( T_BOOLEAN_AND ), // && array( T_BOOLEAN_OR ), // || array( '?', ':' ), - // += -= *= /= .= %= &= |= ^= <<= >>= - array( '=', T_PLUS_EQUAL, T_MINUS_EQUAL, T_MUL_EQUAL, T_DIV_EQUAL, T_CONCAT_EQUAL, T_MOD_EQUAL, T_AND_EQUAL, T_OR_EQUAL, T_XOR_EQUAL, T_SL_EQUAL, T_SR_EQUAL ), + null, // self::$assignmentOperators array( T_LOGICAL_AND ), // and array( T_LOGICAL_XOR ), // xor array( T_LOGICAL_OR ), // or @@ -55,20 +57,23 @@ * @var array */ protected static $runtimeOperators = array( - '~' => '~', - '!' => '!', - '*' => '*', - '/' => '/', - '%' => '%', - '+' => '+', - '-' => '-', - '.' => '.', - '<' => '<', - '>' => '>', - '&' => '&', - '^' => '^', - '|' => '|', - '=' => '=', + '~' => PHPTAGS_T_NOT, + '!' => PHPTAGS_T_IS_NOT, + '*' => PHPTAGS_T_MUL, + '/' => PHPTAGS_T_DIV, + '%' => PHPTAGS_T_MOD, + '+' => PHPTAGS_T_PLUS, + '-' => PHPTAGS_T_MINUS, + '.' => PHPTAGS_T_CONCAT, + '<' => PHPTAGS_T_IS_SMALLER, + '>' => PHPTAGS_T_IS_GREATER, + '&' => PHPTAGS_T_AND, + '^' => PHPTAGS_T_XOR, + '|' => PHPTAGS_T_OR, + '=' => PHPTAGS_T_EQUAL, + '"' => PHPTAGS_T_QUOTE, + '@' => PHPTAGS_T_IGNORE_ERROR, + '?' => PHPTAGS_T_TERNARY, T_LOGICAL_OR => PHPTAGS_T_LOGICAL_OR, T_BOOLEAN_OR => PHPTAGS_T_LOGICAL_OR, T_LOGICAL_XOR => PHPTAGS_T_LOGICAL_XOR, @@ -107,6 +112,8 @@ T_ISSET => PHPTAGS_T_ISSET, T_EMPTY => PHPTAGS_T_EMPTY, T_NEW => PHPTAGS_T_NEW, + T_GLOBAL => PHPTAGS_T_GLOBAL, + T_STATIC => PHPTAGS_T_STATIC, ); /** @@ -129,6 +136,7 @@ function __construct() { if ( !self::$precedencesMatrix ) { + self::$operatorsPrecedence[13] = self::$assignmentOperators; foreach ( self::$operatorsPrecedence as $key => &$value ) { self::$precedencesMatrix += array_fill_keys( $value, $key ); } @@ -214,6 +222,8 @@ return $this->stepForeachConstruct( $throwEndTag ); // return true case T_FOR: return $this->stepForConstruct( $throwEndTag ); // return true +// case T_SWITCH: +// return $this->stepSwitchConstruct( $throwEndTag ); // return true case T_CONTINUE: case T_BREAK: $this->stepUP( true ); @@ -245,7 +255,7 @@ // PHP Parse error: syntax error, unexpected $id, throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $this->id ), $this->tokenLine, $this->place ); } - if ( $value[PHPTAGS_STACK_COMMAND] != PHPTAGS_T_VARIABLE ) { // Example global $foo=5; + if ( $value[PHPTAGS_STACK_COMMAND] !== PHPTAGS_T_VARIABLE ) { // Example global $foo=5; throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $value[PHPTAGS_STACK_COMMAND], 'T_VARIABLE' ), $this->tokenLine, $this->place ); } if ( isset($value[PHPTAGS_STACK_ARRAY_INDEX]) ) { @@ -288,7 +298,7 @@ PHPTAGS_STACK_TOKEN_LINE => $this->tokenLine, PHPTAGS_STACK_DEBUG => $text ); $this->stack_push_memory(); - } elseif ( $value[PHPTAGS_STACK_COMMAND] === '=' ) { + } elseif ( $value[PHPTAGS_STACK_COMMAND] === PHPTAGS_T_EQUAL ) { if ( isset($value[PHPTAGS_STACK_PARAM][PHPTAGS_STACK_ARRAY_INDEX]) ) { throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( '[', "','", "';'" ), $this->tokenLine, $this->place ); } @@ -537,7 +547,7 @@ $i++; } } - $result = array( PHPTAGS_STACK_COMMAND=>'"', PHPTAGS_STACK_PARAM=>&$strings, PHPTAGS_STACK_RESULT=>null, PHPTAGS_STACK_TOKEN_LINE=>$this->tokenLine, PHPTAGS_STACK_DEBUG=>$text ); + $result = array( PHPTAGS_STACK_COMMAND=>PHPTAGS_T_QUOTE, PHPTAGS_STACK_PARAM=>&$strings, PHPTAGS_STACK_RESULT=>null, PHPTAGS_STACK_TOKEN_LINE=>$this->tokenLine, PHPTAGS_STACK_DEBUG=>$text ); break; case T_VARIABLE: $cannotRead = false; @@ -572,7 +582,7 @@ $id = $this->id; $text = $this->text; - if ( in_array($id, self::$operatorsPrecedence[13]) ) { // It is assignment operator + if ( in_array($id, self::$assignmentOperators) ) { // It is assignment operator $this->stepUP(); $val =& $this->getNextValue( '=' ); if ( $val == false ) { // Example: $foo=; @@ -751,7 +761,7 @@ throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $this->id, "'('" ), $this->tokenLine, $this->place ); } $param = array(); - $i = 0; + $i = -1; do { $this->stepUP(); if ( $this->id === T_LIST ) { // T_LIST inside T_LIST. Example: list( $foo, list @@ -760,13 +770,13 @@ $value =& $this->getNextValue(); if ( $value === false ) { // Example: list($foo, , $value = null; - } elseif ( $value[PHPTAGS_STACK_COMMAND] != PHPTAGS_T_VARIABLE && $value[PHPTAGS_STACK_COMMAND] != PHPTAGS_T_LIST ) { // Example: unset( $foo+1 ); + } elseif ( $value[PHPTAGS_STACK_COMMAND] !== PHPTAGS_T_VARIABLE && $value[PHPTAGS_STACK_COMMAND] !== PHPTAGS_T_LIST ) { // Example: unset( $foo+1 ); throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $value[PHPTAGS_STACK_COMMAND], 'T_VARIABLE' ), $this->tokenLine, $this->place ); } } $tmp = array( PHPTAGS_STACK_COMMAND=>null, PHPTAGS_STACK_RESULT=>&$value ); - $param[$i] = null; - $this->addValueIntoStack( $tmp, $param, $i++ ); + $param[++$i] = null; + $this->addValueIntoStack( $tmp, $param, $i ); unset( $value, $tmp ); } while ( $this->id === ',' ); if ( $this->id != ')' ) { @@ -776,6 +786,8 @@ $result = array( PHPTAGS_STACK_COMMAND => PHPTAGS_T_LIST, PHPTAGS_STACK_PARAM => &$param, + PHPTAGS_STACK_PARAM_2 => null, + PHPTAGS_STACK_RESULT => null, PHPTAGS_STACK_TOKEN_LINE => $this->tokenLine, PHPTAGS_STACK_DEBUG => $text, ); @@ -791,16 +803,8 @@ // PHP Parse error: syntax error, unexpected $id throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $this->id ), $this->tokenLine, $this->place ); } - $return = array( - PHPTAGS_STACK_COMMAND => '=', - PHPTAGS_STACK_PARAM => $result, - PHPTAGS_STACK_PARAM_2 => null, - PHPTAGS_STACK_RESULT => null, - PHPTAGS_STACK_TOKEN_LINE => $this->tokenLine, - PHPTAGS_STACK_DEBUG => '=', - ); - $this->addValueIntoStack( $val, $return, PHPTAGS_STACK_PARAM_2 ); - return $return; // *********** EXIT *********** + $this->addValueIntoStack( $val, $result, PHPTAGS_STACK_PARAM_2 ); + return $result; // *********** EXIT *********** } break; case T_PRINT: @@ -839,7 +843,7 @@ // PHP Parse error: syntax error, unexpected $id, throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $this->id ), $this->tokenLine, $this->place ); } - if ( $value[PHPTAGS_STACK_COMMAND] != PHPTAGS_T_VARIABLE ) { // Example: unset( $foo+1 ); + if ( $value[PHPTAGS_STACK_COMMAND] !== PHPTAGS_T_VARIABLE ) { // Example: unset( $foo+1 ); throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $value[PHPTAGS_STACK_COMMAND], 'T_VARIABLE' ), $this->tokenLine, $this->place ); } $param[] =& $value; @@ -894,7 +898,7 @@ case '@': // Error Control Operator $this->stepUP(); if ( $this->ignoreErrors === false ) { - $this->stack[] = array( PHPTAGS_STACK_COMMAND => '@', PHPTAGS_STACK_PARAM => true ); + $this->stack[] = array( PHPTAGS_STACK_COMMAND => PHPTAGS_T_IGNORE_ERROR, PHPTAGS_STACK_PARAM => true ); $this->ignoreErrors = true; } $result =& $this->stepValue( $owner ); @@ -965,7 +969,7 @@ case '?': // Make the operator without the second value $ternary = array( - PHPTAGS_STACK_COMMAND => '?', + PHPTAGS_STACK_COMMAND => PHPTAGS_T_TERNARY, PHPTAGS_STACK_PARAM => null, PHPTAGS_STACK_PARAM_2 => null, PHPTAGS_STACK_RESULT => null, @@ -1096,7 +1100,7 @@ PHPTAGS_STACK_DO_FALSE => false, ); $result = array( - PHPTAGS_STACK_COMMAND => '?', + PHPTAGS_STACK_COMMAND => PHPTAGS_T_TERNARY, PHPTAGS_STACK_PARAM => null, PHPTAGS_STACK_PARAM_2 => $param2, PHPTAGS_STACK_RESULT => null, @@ -1152,7 +1156,7 @@ PHPTAGS_STACK_DO_FALSE => $stack_false, ); $result = array( - PHPTAGS_STACK_COMMAND => '?', + PHPTAGS_STACK_COMMAND => PHPTAGS_T_TERNARY, PHPTAGS_STACK_PARAM => null, PHPTAGS_STACK_PARAM_2 => $param2, PHPTAGS_STACK_RESULT => null, @@ -1466,8 +1470,12 @@ if ( $this->id === $end ) { break; } - throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $this->id, "',' or ';'" ), $this->tokenLine, $this->place ); + throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $this->id, ',', ';' ), $this->tokenLine, $this->place ); } + } + + private function stepSwitchConstruct( $throwEndTag ) { + } private function stepForeachConstruct( $throwEndTag = true ) { @@ -1486,7 +1494,7 @@ // PHP Parse error: syntax error, unexpected $id throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $this->id ), $this->tokenLine, $this->place ); } - if ( $arrayExpression[PHPTAGS_STACK_COMMAND] != PHPTAGS_T_VARIABLE && $arrayExpression[PHPTAGS_STACK_COMMAND] != PHPTAGS_T_ARRAY ) { + if ( $arrayExpression[PHPTAGS_STACK_COMMAND] !== PHPTAGS_T_VARIABLE && $arrayExpression[PHPTAGS_STACK_COMMAND] !== PHPTAGS_T_ARRAY ) { // PHP Parse error: syntax error, unexpected $id, expecting T_VARIABLE throw new PhpTagsException( PhpTagsException::PARSE_SYNTAX_ERROR_UNEXPECTED, array( $arrayExpression[PHPTAGS_STACK_COMMAND], 'T_VARIABLE', 'T_ARRAY' ), $this->tokenLine, $this->place ); } @@ -1634,7 +1642,7 @@ $runtimeReturn = Runtime::run( array($command, $tmp), array('PhpTags\\Compiler') ); if ( $runtimeReturn instanceof PhpTagsException ) { if ( $this->ignoreErrors === null ) { - $this->stack[] = array( PHPTAGS_STACK_COMMAND => '@', PHPTAGS_STACK_PARAM => false ); + $this->stack[] = array( PHPTAGS_STACK_COMMAND => PHPTAGS_T_IGNORE_ERROR, PHPTAGS_STACK_PARAM => false ); $this->ignoreErrors = false; } return false; @@ -1650,7 +1658,7 @@ } if ( $this->ignoreErrors === null ) { - $this->stack[] = array( PHPTAGS_STACK_COMMAND => '@', PHPTAGS_STACK_PARAM => false ); + $this->stack[] = array( PHPTAGS_STACK_COMMAND => PHPTAGS_T_IGNORE_ERROR, PHPTAGS_STACK_PARAM => false ); $this->ignoreErrors = false; } return false; diff --git a/includes/PhpTagsException.php b/includes/PhpTagsException.php index f8b9cd4..5a8e803 100644 --- a/includes/PhpTagsException.php +++ b/includes/PhpTagsException.php @@ -162,6 +162,9 @@ case self::FATAL_CALLED_MANY_EXPENSIVE_FUNCTION: $message = "Too many expensive function calls, last is $arguments"; break; + case self::FATAL_WRONG_BREAK_LEVELS: + $message = "Cannot break/continue $arguments levels"; + break; case self::NOTICE_GET_PROPERTY_OF_NON_OBJECT: $message = 'Trying to get property of non-object'; break; @@ -266,6 +269,7 @@ const FATAL_CALL_FUNCTION_ON_NON_OBJECT = 4019; // PHP Fatal error: Call to a member function doo() on a non-object const FATAL_ACCESS_TO_UNDECLARED_STATIC_PROPERTY = 4020; // PHP Fatal error: Access to undeclared static property: F::$rsrr const FATAL_UNEXPECTED_OBJECT_TYPE = 4021; // Fatal error: Unexpected object type stdClass. in + const FATAL_WRONG_BREAK_LEVELS = 4022; // PHP Fatal error: Cannot break/continue 4 levels const FATAL_DENIED_FOR_NAMESPACE = 4500; const FATAL_CALLFUNCTION_INVALID_HOOK = 4501; diff --git a/includes/Runtime.php b/includes/Runtime.php index 2b997af..a1c500c 100644 --- a/includes/Runtime.php +++ b/includes/Runtime.php @@ -1,19 +1,33 @@ <?php namespace PhpTags; -define( 'PHPTAGS_STACK_RESULT', 'r' ); -define( 'PHPTAGS_STACK_COMMAND', 'c' ); -define( 'PHPTAGS_STACK_PARAM', 'p' ); -define( 'PHPTAGS_STACK_PARAM_2', 's' ); -define( 'PHPTAGS_STACK_PARAM_3', 'o' ); -define( 'PHPTAGS_STACK_INC_AFTER', 'i' ); -define( 'PHPTAGS_STACK_TOKEN_LINE', 'l' ); -define( 'PHPTAGS_STACK_DO_TRUE', 't' ); -define( 'PHPTAGS_STACK_DO_FALSE', 'f' ); -define( 'PHPTAGS_STACK_ARRAY_INDEX', 'a' ); -define( 'PHPTAGS_STACK_DEBUG', '#' ); -define( 'PHPTAGS_STACK_AIM', '*' ); -define( 'PHPTAGS_STACK_HOOK_TYPE', 'h' ); +//const PHPTAGS_STACK_RESULT = 'r'; +//const PHPTAGS_STACK_COMMAND = 'c'; +//const PHPTAGS_STACK_PARAM = 'p'; +//const PHPTAGS_STACK_PARAM_2 = 's'; +//const PHPTAGS_STACK_PARAM_3 = 'o'; +//const PHPTAGS_STACK_INC_AFTER = 'i'; +//const PHPTAGS_STACK_TOKEN_LINE = 'l'; +//const PHPTAGS_STACK_DO_TRUE = 't'; +//const PHPTAGS_STACK_DO_FALSE = 'f'; +//const PHPTAGS_STACK_ARRAY_INDEX = 'a'; +//const PHPTAGS_STACK_DEBUG = '#'; +//const PHPTAGS_STACK_AIM = '*'; +//const PHPTAGS_STACK_HOOK_TYPE = 'h'; + +const PHPTAGS_STACK_COMMAND = 0; +const PHPTAGS_STACK_RESULT = 1; +const PHPTAGS_STACK_PARAM = 2; +const PHPTAGS_STACK_PARAM_2 = 3; +const PHPTAGS_STACK_PARAM_3 = 4; +const PHPTAGS_STACK_INC_AFTER = 5; +const PHPTAGS_STACK_TOKEN_LINE = 6; +const PHPTAGS_STACK_DO_TRUE = 7; +const PHPTAGS_STACK_DO_FALSE = 8; +const PHPTAGS_STACK_ARRAY_INDEX = 9; +const PHPTAGS_STACK_DEBUG = 10; +const PHPTAGS_STACK_AIM = 11; +const PHPTAGS_STACK_HOOK_TYPE = 12; define( 'PHPTAGS_HOOK_GET_CONSTANT', '_' ); define( 'PHPTAGS_HOOK_FUNCTION', 'f' ); @@ -28,56 +42,223 @@ define( 'PHPTAGS_OBJECT_DEFINITION', 0 ); define( 'PHPTAGS_METHOD_CONSTRUCTOR', 1 ); -define( 'PHPTAGS_T_LOGICAL_OR', 263 ); -define( 'PHPTAGS_T_LOGICAL_XOR', 264 ); -define( 'PHPTAGS_T_LOGICAL_AND', 265 ); -define( 'PHPTAGS_T_PRINT', 266 ); -define( 'PHPTAGS_T_SR_EQUAL', 268 ); -define( 'PHPTAGS_T_SL_EQUAL', 269 ); -define( 'PHPTAGS_T_XOR_EQUAL', 270 ); -define( 'PHPTAGS_T_OR_EQUAL', 271 ); -define( 'PHPTAGS_T_AND_EQUAL', 272 ); -define( 'PHPTAGS_T_MOD_EQUAL', 273 ); -define( 'PHPTAGS_T_CONCAT_EQUAL', 274 ); -define( 'PHPTAGS_T_DIV_EQUAL', 275 ); -define( 'PHPTAGS_T_MUL_EQUAL', 276 ); -define( 'PHPTAGS_T_MINUS_EQUAL', 277 ); -define( 'PHPTAGS_T_PLUS_EQUAL', 278 ); -define( 'PHPTAGS_T_IS_NOT_IDENTICAL', 281 ); -define( 'PHPTAGS_T_IS_IDENTICAL', 282 ); -define( 'PHPTAGS_T_IS_NOT_EQUAL', 283 ); -define( 'PHPTAGS_T_IS_EQUAL', 284 ); -define( 'PHPTAGS_T_IS_GREATER_OR_EQUAL', 285 ); -define( 'PHPTAGS_T_IS_SMALLER_OR_EQUAL', 286 ); -define( 'PHPTAGS_T_SR', 287 ); -define( 'PHPTAGS_T_SL', 288 ); -define( 'PHPTAGS_T_UNSET_CAST', 290 ); -define( 'PHPTAGS_T_BOOL_CAST', 291 ); -define( 'PHPTAGS_T_ARRAY_CAST', 293 ); -define( 'PHPTAGS_T_STRING_CAST', 294 ); -define( 'PHPTAGS_T_DOUBLE_CAST', 295 ); -define( 'PHPTAGS_T_INT_CAST', 296 ); -define( 'PHPTAGS_T_DEC', 297 ); -define( 'PHPTAGS_T_INC', 298 ); -define( 'PHPTAGS_T_NEW', 300 ); -define( 'PHPTAGS_T_IF', 302 ); -define( 'PHPTAGS_T_HOOK', 308 ); -define( 'PHPTAGS_T_HOOK_CHECK_PARAM', 309 ); -define( 'PHPTAGS_T_VARIABLE', 310 ); -define( 'PHPTAGS_T_WHILE', 319 ); -define( 'PHPTAGS_T_FOREACH', 323 ); -define( 'PHPTAGS_T_AS', 327 ); -define( 'PHPTAGS_T_BREAK', 332 ); -define( 'PHPTAGS_T_CONTINUE', 333 ); -define( 'PHPTAGS_T_RETURN', 337 ); -define( 'PHPTAGS_T_GLOBAL', 344 ); -define( 'PHPTAGS_T_STATIC', 350 ); -define( 'PHPTAGS_T_UNSET', 352 ); -define( 'PHPTAGS_T_ISSET', 353 ); -define( 'PHPTAGS_T_EMPTY', 354 ); -define( 'PHPTAGS_T_LIST', 363 ); -define( 'PHPTAGS_T_ARRAY', 364 ); -define( 'PHPTAGS_T_COPY', 500 ); +/** + * operator: " + */ +const PHPTAGS_T_QUOTE = 0; // " +/** + * operator: . + */ +const PHPTAGS_T_CONCAT = 1; +/** + * operator: + + */ +const PHPTAGS_T_PLUS = 2; +/** + * operator: - + */ +const PHPTAGS_T_MINUS = 3; +/** + * operator: * + */ +const PHPTAGS_T_MUL = 4; +/** + * operator: / + */ +const PHPTAGS_T_DIV = 5; +/** + * operator: == + */ +const PHPTAGS_T_IS_EQUAL = 6; +/** + * get value from variable + */ +const PHPTAGS_T_VARIABLE = 7; +/** + * operator: if + */ +const PHPTAGS_T_IF = 8; +/** + * operator: = + */ +const PHPTAGS_T_EQUAL = 9; +/** + * operator: .= + */ +const PHPTAGS_T_CONCAT_EQUAL = 10; +/** + * operator: /= + */ +const PHPTAGS_T_DIV_EQUAL = 11; +/** + * operator: *= + */ +const PHPTAGS_T_MUL_EQUAL = 12; +/** + * operator: -= + */ +const PHPTAGS_T_MINUS_EQUAL = 13; +/** + * operator: += + */ +const PHPTAGS_T_PLUS_EQUAL = 14; +/** + * operator: !== + */ +const PHPTAGS_T_IS_NOT_IDENTICAL = 15; +/** + * operator: === + */ +const PHPTAGS_T_IS_IDENTICAL = 16; +/** + * operator: != + */ +const PHPTAGS_T_IS_NOT_EQUAL = 17; +/** + * operator: ^= + */ +const PHPTAGS_T_XOR_EQUAL = 18; +/** + * operator: >= + */ +const PHPTAGS_T_IS_GREATER_OR_EQUAL = 19; +/** + * operator: <= + */ +const PHPTAGS_T_IS_SMALLER_OR_EQUAL = 20; +/** + * operator: >> + */ +const PHPTAGS_T_SR = 21; +/** + * operator: << + */ +const PHPTAGS_T_SL = 22; +/** + * operator: (unset) + */ +const PHPTAGS_T_UNSET_CAST = 23; +/** + * operator: (bool) + */ +const PHPTAGS_T_BOOL_CAST = 24; +/** + * operator: (array) + */ +const PHPTAGS_T_ARRAY_CAST = 25; +/** + * operator: (string) + */ +const PHPTAGS_T_STRING_CAST = 26; +/** + * operator: (double) + */ +const PHPTAGS_T_DOUBLE_CAST = 27; +/** + * operator: (int) + */ +const PHPTAGS_T_INT_CAST = 28; +/** + * operator: -- + */ +const PHPTAGS_T_DEC = 29; +/** + * operator: ++ + */ +const PHPTAGS_T_INC = 30; +/** + * operator: new + */ +const PHPTAGS_T_NEW = 31; +/** + * operator: &= + */ +const PHPTAGS_T_AND_EQUAL = 32; +/** + * call phptags hook + */ +const PHPTAGS_T_HOOK = 33; +/** + * check passed param to phptags hook + */ +const PHPTAGS_T_HOOK_CHECK_PARAM = 34; +/** + * it copies value from variable to destination + */ +const PHPTAGS_T_COPY = 35; +const PHPTAGS_T_WHILE = 36; +const PHPTAGS_T_FOREACH = 37; +const PHPTAGS_T_AS = 38; +const PHPTAGS_T_BREAK = 39; +const PHPTAGS_T_CONTINUE = 40; +const PHPTAGS_T_RETURN = 41; +const PHPTAGS_T_GLOBAL = 42; +const PHPTAGS_T_STATIC = 43; +const PHPTAGS_T_UNSET = 44; +const PHPTAGS_T_ISSET = 45; +const PHPTAGS_T_EMPTY = 46; +const PHPTAGS_T_LIST = 47; +const PHPTAGS_T_ARRAY = 48; +const PHPTAGS_T_OR_EQUAL = 49; +/** + * operators: echo, print + */ +const PHPTAGS_T_PRINT = 50; +/** + * operator: || + */ +const PHPTAGS_T_LOGICAL_OR = 51; +/** + * operator: @ + */ +const PHPTAGS_T_IGNORE_ERROR = 52; // @ +/** + * ternary operator: ? + */ +const PHPTAGS_T_TERNARY = 53; // ? +/** + * operator: | + */ +const PHPTAGS_T_OR = 54; // | +/** + * operator: ^ + */ +const PHPTAGS_T_XOR = 55; +/** + * operator: & + */ +const PHPTAGS_T_AND = 56; +/** + * operator: > + */ +const PHPTAGS_T_IS_GREATER = 57; +/** + * operator: < + */ +const PHPTAGS_T_IS_SMALLER = 58; +/** + * operator: xor + */ +const PHPTAGS_T_LOGICAL_XOR = 59; +const PHPTAGS_T_MOD_EQUAL = 60; +/** + * operator: and + */ +const PHPTAGS_T_LOGICAL_AND = 61; +/** + * operator: % + */ +const PHPTAGS_T_MOD = 62; +const PHPTAGS_T_SL_EQUAL = 63; +const PHPTAGS_T_SR_EQUAL = 64; +/** + * operator: ! + */ +const PHPTAGS_T_IS_NOT = 65; +/** + * operator: ~ + */ +const PHPTAGS_T_NOT = 66; /** * The runtime class of the extension PhpTags. @@ -106,10 +287,80 @@ private static $variables = array(); private static $staticVariables = array(); private static $globalVariables = array(); - private static $exceptions = array(); + private static $ignoreErrors = false; private static $scope; private static $parserDisabled = false; private static $errorCategoryAdded = false; + + private static $operators = array( + PHPTAGS_T_QUOTE => 'doQuote', + PHPTAGS_T_CONCAT => 'doConcat', + PHPTAGS_T_PLUS => 'doPlus', + PHPTAGS_T_MINUS => 'doMinus', + PHPTAGS_T_MUL => 'doMul', + PHPTAGS_T_DIV => 'doDiv', + PHPTAGS_T_MOD => 'doMod', + PHPTAGS_T_AND => 'doAnd', + PHPTAGS_T_OR => 'doOr', + PHPTAGS_T_XOR => 'doXor', + PHPTAGS_T_SL => 'doShiftLeft', + PHPTAGS_T_SR => 'doShiftRight', + PHPTAGS_T_LOGICAL_AND => 'doLogicalAnd', + PHPTAGS_T_LOGICAL_XOR => 'doLogicalXor', + PHPTAGS_T_LOGICAL_OR => 'doLogicalOr', + PHPTAGS_T_IS_SMALLER => 'doIsSmaller', + PHPTAGS_T_IS_GREATER => 'doIsGreater', + PHPTAGS_T_IS_SMALLER_OR_EQUAL => 'doIsSmallerOrEqual', + PHPTAGS_T_IS_GREATER_OR_EQUAL => 'doIsGreaterOrEqual', + PHPTAGS_T_IS_EQUAL => 'doIsEqual', + PHPTAGS_T_IS_NOT_EQUAL => 'doIsNotEqual', + PHPTAGS_T_IS_IDENTICAL => 'doIsIdentical', + PHPTAGS_T_IS_NOT_IDENTICAL => 'doIsNotIdentical', + PHPTAGS_T_PRINT => 'doPrint', + PHPTAGS_T_NOT => 'doNot', + PHPTAGS_T_IS_NOT => 'doIsNot', + PHPTAGS_T_INT_CAST => 'doIntCast', + PHPTAGS_T_DOUBLE_CAST => 'doDoubleCast', + PHPTAGS_T_STRING_CAST => 'doStringCast', + PHPTAGS_T_ARRAY_CAST => 'doArrayCast', + PHPTAGS_T_BOOL_CAST => 'doBoolCast', + PHPTAGS_T_UNSET_CAST => 'doUnsetCast', + PHPTAGS_T_VARIABLE => 'doVariable', + PHPTAGS_T_TERNARY => 'doTernary', + PHPTAGS_T_IF => 'doIf', + PHPTAGS_T_FOREACH => 'doForeach', + PHPTAGS_T_WHILE => 'doWhile', + PHPTAGS_T_AS => 'doAs', + PHPTAGS_T_BREAK => 'doBreak', + PHPTAGS_T_CONTINUE => 'doContinue', + PHPTAGS_T_ARRAY => 'doArray', + PHPTAGS_T_STATIC => 'doStatic', + PHPTAGS_T_GLOBAL => 'doGlobal', + PHPTAGS_T_HOOK_CHECK_PARAM => 'doCheckingParam', + PHPTAGS_T_HOOK => 'doCallingHook', + PHPTAGS_T_NEW => 'doNewObject', + PHPTAGS_T_UNSET => 'doUnset', + PHPTAGS_T_ISSET => 'doIsSet', + PHPTAGS_T_EMPTY => 'doIsEmpty', + PHPTAGS_T_RETURN => 'doReturn', + PHPTAGS_T_COPY => 'doCopy', + PHPTAGS_T_IGNORE_ERROR => 'doIgnoreErrors', + PHPTAGS_T_LIST => 'doList', + PHPTAGS_T_INC => 'doIncrease', + PHPTAGS_T_DEC => 'doDecrease', + PHPTAGS_T_EQUAL => 'doSetVal', + PHPTAGS_T_CONCAT_EQUAL => 'doSetConcatVal', + PHPTAGS_T_PLUS_EQUAL => 'doSetPlusVal', + PHPTAGS_T_MINUS_EQUAL => 'doSetMinusVal', + PHPTAGS_T_MUL_EQUAL => 'doSetMulVal', + PHPTAGS_T_DIV_EQUAL => 'doSetDivVal', + PHPTAGS_T_MOD_EQUAL => 'doSetModVal', + PHPTAGS_T_AND_EQUAL => 'doSetAndVal', + PHPTAGS_T_OR_EQUAL => 'doSetOrVal', + PHPTAGS_T_XOR_EQUAL => 'doSetXorVal', + PHPTAGS_T_SL_EQUAL => 'doSetShiftLeftVal', + PHPTAGS_T_SR_EQUAL => 'doSetShiftRightVal', + ); public static function reset() { global $wgPhpTagsMaxLoops; @@ -126,629 +377,984 @@ return self::run( Compiler::compile($code), $args, $scope ); } + /** + * The output cache + * @var array + */ + private static $return; + private static $running; + private static $runIndex; + private static $c; + private static $loopsOwner; + private static $memory; + private static $place; + private static $thisVariables; + + private static function pushDown( $newCode, $newLoopsOwner, &$refReturn ) { + self::$memory[] = array( &$refReturn, self::$running, self::$runIndex, self::$c, self::$loopsOwner ); + self::$running = $newCode; + self::$runIndex = -1; + self::$c = count( $newCode ); + self::$loopsOwner = $newLoopsOwner; + } + + private static function popUp() { + list( self::$running[self::$runIndex][PHPTAGS_STACK_RESULT], self::$running, self::$runIndex, self::$c, self::$loopsOwner ) = array_pop( self::$memory ); + } + + /** + * PHPTAGS_T_QUOTE + * @param array $value + */ + private static function doQuote ( $value ) { + $value[PHPTAGS_STACK_RESULT] = implode( $value[PHPTAGS_STACK_PARAM] ); + } + + /** + * PHPTAGS_T_CONCAT + * @param array $value + */ + private static function doConcat ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] . $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_PLUS + * @param array $value + */ + private static function doPlus ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] + $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_MINUS + * @param array $value + */ + private static function doMinus ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] - $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_MUL + * @param array $value + */ + private static function doMul ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] * $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_DIV + * @param array $value + */ + private static function doDiv ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] / $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_MOD + * @param array $value + */ + private static function doMod ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] % $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_AND + * @param array $value + */ + private static function doAnd ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] & $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_OR + * @param array $value + */ + private static function doOr ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] | $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_XOR + * @param array $value + */ + private static function doXor ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] ^ $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_SL + * @param array $value + */ + private static function doShiftLeft ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] << $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_SR + * @param array $value + */ + private static function doShiftRight ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] >> $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_LOGICAL_AND + * @param array $value + */ + private static function doLogicalAnd ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] && $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_LOGICAL_XOR + * @param array $value + */ + private static function doLogicalXor ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] xor $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_LOGICAL_OR + * @param array $value + */ + private static function doLogicalOr ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] || $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_IS_SMALLER + * @param array $value + */ + private static function doIsSmaller ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] < $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_IS_GREATER + * @param array $value + */ + private static function doIsGreater ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] > $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_IS_SMALLER_OR_EQUAL + * @param array $value + */ + private static function doIsSmallerOrEqual ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] <= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_IS_GREATER_OR_EQUAL + * @param array $value + */ + private static function doIsGreaterOrEqual ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] >= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_IS_EQUAL + * @param array $value + */ + private static function doIsEqual ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] == $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_IS_NOT_EQUAL + * @param array $value + */ + private static function doIsNotEqual ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] != $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_IS_IDENTICAL + * @param array $value + */ + private static function doIsIdentical ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] === $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_IS_NOT_IDENTICAL + * @param array $value + */ + private static function doIsNotIdentical ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] !== $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_PRINT outputs the value + * @param array $value + */ + private static function doPrint ( $value ) { + if( $value[PHPTAGS_STACK_PARAM] instanceof GenericObject ) { + self::$return[] = $value[PHPTAGS_STACK_PARAM]->toString(); + } else { + self::$return[] = $value[PHPTAGS_STACK_PARAM]; + } + } + + /** + * PHPTAGS_T_NOT + * @param array $value + */ + private static function doNot ( $value ) { + $value[PHPTAGS_STACK_RESULT] = ~$value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_IS_NOT + * @param array $value + */ + private static function doIsNot ( $value ) { + $value[PHPTAGS_STACK_RESULT] = !$value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_INT_CAST + * @param array $value + */ + private static function doIntCast ( $value ) { + $value[PHPTAGS_STACK_RESULT] = (int)$value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_DOUBLE_CAST + * @param array $value + */ + private static function doDoubleCast ( $value ) { + $value[PHPTAGS_STACK_RESULT] = (double)$value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_STRING_CAST + * @param array $value + */ + private static function doStringCast ( $value ) { + $value[PHPTAGS_STACK_RESULT] = (string)$value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_ARRAY_CAST + * @param array $value + */ + private static function doArrayCast ( $value ) { + $value[PHPTAGS_STACK_RESULT] = (array)$value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_BOOL_CAST + * @param array $value + */ + private static function doBoolCast ( $value ) { + $value[PHPTAGS_STACK_RESULT] = (bool)$value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_UNSET_CAST + * @param array $value + */ + private static function doUnsetCast ( $value ) { + $value[PHPTAGS_STACK_RESULT] = (unset)$value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_VARIABLE + * @param array $value + */ + private static function doVariable ( $value ) { + $aim = $value[PHPTAGS_STACK_AIM]; + if ( isset(self::$thisVariables[ $value[PHPTAGS_STACK_PARAM] ]) || array_key_exists($value[PHPTAGS_STACK_PARAM], self::$thisVariables) ) { + $value[PHPTAGS_STACK_PARAM_2][$aim] =& self::$thisVariables[ $value[PHPTAGS_STACK_PARAM] ]; + if ( isset($value[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: $foo[1] + foreach ( $value[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { + if ( is_array( $value[PHPTAGS_STACK_PARAM_2][$aim] ) ) { + if ( isset($value[PHPTAGS_STACK_PARAM_2][$aim][$v]) || array_key_exists($v, $value[PHPTAGS_STACK_PARAM_2][$aim]) ) { + $value[PHPTAGS_STACK_PARAM_2][$aim] =& $value[PHPTAGS_STACK_PARAM_2][$aim][$v]; + } else { + // PHP Notice: Undefined offset: $1 + self::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_INDEX, $v ) ); + unset( $value[PHPTAGS_STACK_PARAM_2][$aim] ); + $value[PHPTAGS_STACK_PARAM_2][$aim] = null; + } + } else { + if ( isset( $value[PHPTAGS_STACK_PARAM_2][$aim][$v]) ) { + unset( $value[PHPTAGS_STACK_PARAM_2][$aim] ); + $value[PHPTAGS_STACK_PARAM_2][$aim] = $value[PHPTAGS_STACK_PARAM_2][$aim][$v]; + } else { + // PHP Notice: Uninitialized string offset: $1 + self::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNINIT_STRING_OFFSET, (int)$v ) ); + unset( $value[PHPTAGS_STACK_PARAM_2][$aim] ); + $value[PHPTAGS_STACK_PARAM_2][$aim] = null; + } + } + } + } + } else { + unset( $value[PHPTAGS_STACK_PARAM_2][$aim] ); + $value[PHPTAGS_STACK_PARAM_2][$aim] = null; + Runtime::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_VARIABLE, $value[PHPTAGS_STACK_PARAM] ) ); + } + } + + /** + * PHPTAGS_T_TERNARY + * @param array $value + */ + private static function doTernary ( $value ) { + if( $value[PHPTAGS_STACK_PARAM] ) { // true ? + if( $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_DO_TRUE] ) { // true ? 1+2 : + self::pushDown( $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_DO_TRUE], '?', $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_PARAM] ); + }else{ // true ? 1 : + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_PARAM]; + } + }else{ // false ? + if( $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_DO_FALSE] ) { // false ? ... : 1+2 + self::pushDown( $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_DO_FALSE], '?', $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_PARAM_2] ); + }else{ // false ? ... : 1 + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_PARAM_2]; + } + } + } + + /** + * PHPTAGS_T_IF + * @param array $value + */ + private static function doIf ( $value ) { + $return = null; + if( $value[PHPTAGS_STACK_PARAM] ) { // Example: if( true ) + if( $value[PHPTAGS_STACK_DO_TRUE] ) { // Stack not empty: if(true); + self::pushDown( $value[PHPTAGS_STACK_DO_TRUE], T_IF, $return ); + } + }else{ // Example: if( false ) + if( isset($value[PHPTAGS_STACK_DO_FALSE]) ) { // Stack not empty: if(false) ; else ; + self::pushDown( $value[PHPTAGS_STACK_DO_FALSE], T_IF, $return ); + } + } + } + + /** + * PHPTAGS_T_FOREACH + * @param array $value + */ + private static function doForeach ( $value ) { + if ( !is_array($value[PHPTAGS_STACK_PARAM]) ) { + self::pushException( new PhpTagsException( PhpTagsException::WARNING_INVALID_ARGUMENT_FOR_FOREACH, null ) ); + return; + } + reset( $value[PHPTAGS_STACK_PARAM] ); + $null = null; + self::pushDown( $value[PHPTAGS_STACK_DO_TRUE], T_WHILE, $null ); + } + + /** + * PHPTAGS_T_WHILE + * @param array $value + */ + private static function doWhile ( $value ) { + $null = null; + self::pushDown( $value[PHPTAGS_STACK_DO_TRUE], T_WHILE, $null ); + } + + /** + * PHPTAGS_T_AS + * @param array $value + */ + private static function doAs ( $value ) { + if ( !is_array($value[PHPTAGS_STACK_RESULT]) ) { + Runtime::pushException( new PhpTagsException( PhpTagsException::WARNING_INVALID_ARGUMENT_FOR_FOREACH, null ) ); + return; + } + if ( isset($value[PHPTAGS_STACK_PARAM_2]) ) { // T_DOUBLE_ARROW Example: while ( $foo as $key=>$value ) + if ( !list(self::$thisVariables[ $value[PHPTAGS_STACK_PARAM] ], self::$thisVariables[ $value[PHPTAGS_STACK_PARAM_2] ]) = each($value[PHPTAGS_STACK_RESULT]) ) { + self::popUp(); + } + } else { // Example: while ( $foo as $value ) + if ( !list(,self::$thisVariables[ $value[PHPTAGS_STACK_PARAM] ]) = each($value[PHPTAGS_STACK_RESULT]) ) { + self::popUp(); + } + } + } + + /** + * PHPTAGS_T_BREAK + * @param array $value + */ + private static function doBreak ( $value ) { + $loopsOwner =& self::$loopsOwner; + $memory =& self::$memory; + $originalBreak = $break = $value[PHPTAGS_STACK_RESULT]; + + for ( ; ; ) { + if ( $loopsOwner === T_WHILE ) { + --$break; + } + self::popUp(); + if ( $break === 0 ) { + return; + } elseif ( count( $memory ) === 0 ) { + if ( $break > 1 ) { + throw new PhpTagsException( PhpTagsException::FATAL_WRONG_BREAK_LEVELS, $originalBreak ); + } + return; + } + } + } + + /** + * PHPTAGS_T_CONTINUE + * @param array $value + */ + private static function doContinue ( $value ) { + if( self::$loopsLimit-- <= 0 ) { + throw new PhpTagsException( PhpTagsException::FATAL_LOOPS_LIMIT_REACHED, null, $value[PHPTAGS_STACK_TOKEN_LINE], $place ); + } + $loopsOwner =& self::$loopsOwner; + $memory =& self::$memory; + $originalBreak = $break = $value[PHPTAGS_STACK_RESULT] - 1; + + for ( ; ; ) { + if ( $loopsOwner === T_WHILE ) { + if ( $break > 0 ) { + --$break; + } else { + break; + } + } + self::popUp(); + if ( count( $memory ) === 0 && $break > 0 ) { + throw new PhpTagsException( PhpTagsException::FATAL_WRONG_BREAK_LEVELS, $originalBreak ); + } + } + self::$runIndex = -1; + } + + /** + * PHPTAGS_T_ARRAY inits new array + * @param array $value + */ + private static function doArray ( $value ) { + $newArray = $value[PHPTAGS_STACK_PARAM][0]; + $i = 1; + foreach ( $value[PHPTAGS_STACK_PARAM_2] as $t ) { + list ( $k, $v ) = $t; + $newArray[$k] = $v; + if ( isset($value[PHPTAGS_STACK_PARAM][$i]) ) { + foreach ( $value[PHPTAGS_STACK_PARAM][$i] as $n ) { + $newArray[] = $n; + } + } + ++$i; + } + $value[PHPTAGS_STACK_RESULT] = $newArray; + } + + /** + * PHPTAGS_T_STATIC inits static variables + * @param array $value + */ + private static function doStatic ( $value ) { + $name = $value[PHPTAGS_STACK_PARAM]; // variable name + if( !isset(self::$staticVariables[self::$place]) || !array_key_exists($name, self::$staticVariables[self::$place]) ) { + self::$staticVariables[self::$place][$name] = $value[PHPTAGS_STACK_RESULT]; + if ( $value[PHPTAGS_STACK_DO_TRUE] ) { + $null = null; + self::pushDown( $value[PHPTAGS_STACK_DO_TRUE], T_STATIC, $null ); + } + } + self::$thisVariables[$name] =& self::$staticVariables[self::$place][$name]; + } + + /** + * PHPTAGS_T_GLOBAL inits global variables + * @param array $value + */ + private static function doGlobal ( $value ) { + $gVars =& self::$globalVariables; + foreach( $value[PHPTAGS_STACK_PARAM] as $name ) { // variable names + if( !array_key_exists($name, $gVars) ) { + $gVars[$name] = null; + } + self::$thisVariables[$name] =& $gVars[$name]; + } + } + + /** + * PHPTAGS_T_HOOK_CHECK_PARAM checks param for hooks + * @param array $value + */ + private static function doCheckingParam ( $value ) { + $i = $value[PHPTAGS_STACK_AIM]; + $reference_info = Hooks::getReferenceInfo( + $i, // ordinal number of the argument, zero is first + $value[PHPTAGS_STACK_HOOK_TYPE], + $value[PHPTAGS_STACK_PARAM], // name of function or method + $value[PHPTAGS_STACK_PARAM_3] === false ? false : $value[PHPTAGS_STACK_PARAM_3][PHPTAGS_STACK_PARAM_3] // $object or false + ); + + if ( $value[PHPTAGS_STACK_PARAM_2] === true && $reference_info === false ) { + // Param is variable and it needs to clone + $t = $value[PHPTAGS_STACK_RESULT][$i]; + unset( $value[PHPTAGS_STACK_RESULT][$i] ); + $value[PHPTAGS_STACK_RESULT][$i] = $t; + } elseif ( $value[PHPTAGS_STACK_PARAM_2] === false && $reference_info === true ) { + // Param is not variable and it's need reference + throw new PhpTagsException( PhpTagsException::FATAL_VALUE_PASSED_BY_REFERENCE, null, $value[PHPTAGS_STACK_TOKEN_LINE], $place ); + } + } + + /** + * PHPTAGS_T_HOOK calls hook + * @param array $value + */ + private static function doCallingHook ( $value ) { + $result = Hooks::callHook( + $value[PHPTAGS_STACK_HOOK_TYPE], + $value[PHPTAGS_STACK_PARAM_2], // arguments + $value[PHPTAGS_STACK_PARAM], // name of function or method + $value[PHPTAGS_STACK_PARAM_3] // $object or false + ); + + if ( $result instanceof outPrint ) { + $value[PHPTAGS_STACK_RESULT] = $result->returnValue; + self::$return[] = $result; + } else { + $value[PHPTAGS_STACK_RESULT] = $result; + } + if ( is_object($value[PHPTAGS_STACK_RESULT]) && !($value[PHPTAGS_STACK_RESULT] instanceof iRawOutput || $value[PHPTAGS_STACK_RESULT] instanceof GenericObject) ) { + // @todo + $value[PHPTAGS_STACK_RESULT] = null; + Runtime::pushException( new PhpTagsException( PhpTagsException::WARNING_RETURNED_INVALID_VALUE, $value[PHPTAGS_STACK_PARAM] ) ); + } + } + + /** + * PHPTAGS_T_NEW creates new object + * @param array $value + */ + private static function doNewObject ( $value ) { + $value[PHPTAGS_STACK_RESULT] = Hooks::createObject( $value[PHPTAGS_STACK_PARAM_2], $value[PHPTAGS_STACK_PARAM_3] ); + } + + /** + * PHPTAGS_T_UNSET unsets variables + * @param array $value + */ + private static function doUnset ( $value ) { + $thisVariables =& self::$thisVariables; + foreach ( $value[PHPTAGS_STACK_PARAM] as $val ) { + $name = $val[PHPTAGS_STACK_PARAM]; // Variable Name + if ( isset($thisVariables[$name]) || array_key_exists($name, $thisVariables) ) { // defined variable + if ( isset($val[PHPTAGS_STACK_ARRAY_INDEX]) ) { // There is array index. Example: unset($foo[0]) + $ref =& $thisVariables[$name]; + $tmp = array_pop( $val[PHPTAGS_STACK_ARRAY_INDEX] ); + foreach ( $val[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { + if ( is_string($ref) ) { + throw new PhpTagsException( PhpTagsException::FATAL_CANNOT_UNSET_STRING_OFFSETS, null, $value[PHPTAGS_STACK_TOKEN_LINE], $place ); + } elseif ( !isset($ref[$v]) ) { // undefined array index not for string + continue 2; + } + $ref =& $ref[$v]; + } + if ( is_array($ref) ) { + unset( $ref[$tmp] ); + } else { + throw new PhpTagsException( PhpTagsException::FATAL_CANNOT_UNSET_STRING_OFFSETS, null, $value[PHPTAGS_STACK_TOKEN_LINE], $place ); + } + }else{ // There is no array index. Example: unset($foo) + unset( $thisVariables[$name] ); + } + } elseif ( isset($val[PHPTAGS_STACK_ARRAY_INDEX]) ) { // undefined variable with array index. Example: unset($foo[1]) + self::pushException( new PhpTagsException( PHPTAGS_NOTICE_UNDEFINED_VARIABLE, $name ) ); + } + } + } + + /** + * PHPTAGS_T_ISSET returns TRUE when variables are set + * @param array $value + */ + private static function doIsSet ( $value ) { + $thisVariables =& self::$thisVariables; + foreach($value[PHPTAGS_STACK_PARAM] as $val) { + if( !isset($thisVariables[ $val[PHPTAGS_STACK_PARAM] ]) ) { // undefined variable or variable is null + $value[PHPTAGS_STACK_RESULT] = false; + return; + } // true, variable is defined + if( isset($val[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: isset($foo[1]) + $ref =& $thisVariables[ $val[PHPTAGS_STACK_PARAM] ]; + $tmp = array_pop( $val[PHPTAGS_STACK_ARRAY_INDEX] ); + foreach( $val[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { + if( !isset($ref[$v]) ) { // undefined array index + $value[PHPTAGS_STACK_RESULT] = false; + return; + } + $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[$tmp]) || (is_string($ref) && is_string($tmp ) && $tmp != (string)(int)$tmp ) ) { + $value[PHPTAGS_STACK_RESULT] = false; + return; + } + } // true, variable is defined and have no array index + } + $value[PHPTAGS_STACK_RESULT] = true; + } + + /** + * PHPTAGS_T_EMPTY returns TRUE when variables are empty + * @param array $value + */ + private static function doIsEmpty ( $value ) { + $thisVariables =& self::$thisVariables; + foreach($value[PHPTAGS_STACK_PARAM] as $val) { + if( !array_key_exists($val[PHPTAGS_STACK_PARAM], $thisVariables) ) { // undefined variable + continue; + } + $ref =& $thisVariables[ $val[PHPTAGS_STACK_PARAM] ]; + if( isset($val[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: empty($foo[1]) + $tmp = array_pop( $val[PHPTAGS_STACK_ARRAY_INDEX] ); + foreach( $val[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { + if( !isset($ref[$v]) ) { // undefined array index + continue 2; + } + $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.empty.php Example #2 empty() on String Offsets + if( !empty($ref[$tmp]) && (is_array($ref) || !is_string( $tmp ) || $tmp == (string)(int)$tmp ) ) { + $value[PHPTAGS_STACK_RESULT] = false; + return; + } + }elseif( !empty($ref) ) { // there is no array index and empty() returns false (PHP 5.5.0 supports expressions) + $value[PHPTAGS_STACK_RESULT] = false; + return; + } + } + $value[PHPTAGS_STACK_RESULT] = true; + } + + /** + * PHPTAGS_T_RETURN is designed for compiler only! + * @param array $value + */ + private static function doReturn ( $value ) { + self::$return = self::$return ? new PhpTagsException() : $value[PHPTAGS_STACK_PARAM]; + } + + /** + * PHPTAGS_T_COPY copies value from variable to destination + * @param array $value + */ + private static function doCopy ( $value ) { + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM]; + } + + /** + * PHPTAGS_T_IGNORE_ERROR + * @param array $value + */ + private static function doIgnoreErrors ( $value ) { + self::$ignoreErrors = $value[PHPTAGS_STACK_PARAM]; + } + + /** + * PHPTAGS_T_LIST + * @param array $value + */ + private static function doList ( $value ) { + self::fillList( $value[PHPTAGS_STACK_PARAM_2], $value[PHPTAGS_STACK_PARAM], self::$thisVariables ); + $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_INC + * @param array $value + */ + private static function doIncrease ( $value ) { + $ref =& self::getVariableRef( $value ); + if ( $value[PHPTAGS_STACK_PARAM_2] ) { // $foo++ + $value[PHPTAGS_STACK_RESULT] = $ref++; + }else{ // ++$foo + $value[PHPTAGS_STACK_RESULT] = ++$ref; + } + } + + /** + * PHPTAGS_T_DEC + * @param array $value + */ + private static function doDecrease ( $value ) { + $ref =& self::getVariableRef( $value ); + if ( $value[PHPTAGS_STACK_PARAM_2] ) { // $foo-- + $value[PHPTAGS_STACK_RESULT] = $ref--; + }else{ // --$foo + $value[PHPTAGS_STACK_RESULT] = --$ref; + } + } + + /** + * PHPTAGS_T_EQUAL + * @param array $value + */ + private static function doSetVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref = $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_CONCAT_EQUAL + * @param array $value + */ + private static function doSetConcatVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref .= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_PLUS_EQUAL + * @param array $value + */ + private static function doSetPlusVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref += $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_MINUS_EQUAL + * @param array $value + */ + private static function doSetMinusVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref -= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_MUL_EQUAL + * @param array $value + */ + private static function doSetMulVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref *= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_DIV_EQUAL + * @param array $value + */ + private static function doSetDivVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref /= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_MOD_EQUAL + * @param array $value + */ + private static function doSetModVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref %= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_AND_EQUAL + * @param array $value + */ + private static function doSetAndVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref &= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_OR_EQUAL + * @param array $value + */ + private static function doSetOrVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref |= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_XOR_EQUAL + * @param array $value + */ + private static function doSetXorVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref ^= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_SL_EQUAL + * @param array $value + */ + private static function doSetShiftLeftVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref <<= $value[PHPTAGS_STACK_PARAM_2]; + } + + /** + * PHPTAGS_T_SR_EQUAL + * @param array $value + */ + private static function doSetShiftRightVal ( $value ) { + $ref =& self::getVariableRef( $value ); + $value[PHPTAGS_STACK_RESULT] = $ref <<= $value[PHPTAGS_STACK_PARAM_2]; + } + + private static function & getVariableRef( $value ) { + $thisVariables =& self::$thisVariables; + $variable = $value[PHPTAGS_STACK_PARAM]; + $variableName = $variable[PHPTAGS_STACK_PARAM]; + if( !(isset($thisVariables[$variableName]) || array_key_exists($variableName, $thisVariables)) ) { // Use undefined variable + if( isset($value[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: $foo[1]++ + $thisVariables[$variableName] = array(); + }else{ + $thisVariables[$variableName] = null; + } + if( $value[PHPTAGS_STACK_COMMAND] !== PHPTAGS_T_EQUAL ) { + Runtime::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_VARIABLE, $variableName ) ); + } + } + $ref =& $thisVariables[$variableName]; + if ( isset($variable[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: $foo[1]++ + foreach ( $variable[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { + if ( $v === INF ) { // Example: $foo[] + $t = null; + $ref[] = &$t; + $ref = &$t; + unset( $t ); + } else { + if ( $ref === null ) { + if( $value[PHPTAGS_STACK_COMMAND] !== PHPTAGS_T_EQUAL ) { + // PHP Notice: Undefined offset: $1 + Runtime::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_OFFSET, $v[PHPTAGS_STACK_RESULT] ) ); + } + $ref[$v] = null; + $ref =& $ref[$v]; + } elseif ( is_array($ref) ) { + if ( !( isset($ref[$v]) || array_key_exists($v, $ref) ) ) { + $ref[$v] = null; + if( $value[PHPTAGS_STACK_COMMAND] !== PHPTAGS_T_EQUAL ) { + // PHP Notice: Undefined offset: $1 + Runtime::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_INDEX, $v ) ); + } + } + $ref =& $ref[$v]; + } elseif ( is_string($ref) ) { + // PHP Fatal error: Cannot use string offset as an array + throw new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_OFFSET, $v, $value[PHPTAGS_STACK_TOKEN_LINE], $place ); + } else { + Runtime::pushException( new PhpTagsException( PhpTagsException::FATAL_STRING_OFFSET_AS_ARRAY, $v ) ); + break 2; + // PHP Warning: Cannot use a scalar value as an array + } + } + } + } + return $ref; + } + public static function run( $code, array $args, $scope = '' ) { set_error_handler( '\\PhpTags\\ErrorHandler::onError' ); try { - if( !isset(self::$variables[$scope]) ) { + self::$scope = $scope; + self::$running = $code; + self::$memory = array(); + self::$return = array(); + self::$loopsOwner = null; + self::$place = isset($args[0]) ? $args[0] : ''; // Page name for static variables and error messages + self::$c = count( $code ); + if( false === isset(self::$variables[$scope]) ) { self::$variables[$scope] = array(); } - self::$scope = $scope; - $thisVariables =& self::$variables[$scope]; - $thisVariables['argv'] = $args; - $thisVariables['argc'] = count($args); - $thisVariables['GLOBALS'] = &self::$globalVariables; - $exceptions =& self::$exceptions; - $memory=array(); - $return = array(); - $break = 0; // used for T_BREAK - $continue = false; // used for T_CONTINUE - $loopsOwner = null; - $place = isset($args[0]) ? $args[0] : ''; // Page name for static variables and error messages + self::$thisVariables =& self::$variables[$scope]; + self::$thisVariables['argv'] = $args; + self::$thisVariables['argc'] = count($args); + self::$thisVariables['GLOBALS'] =& self::$globalVariables; - $c = count( $code ); - $codeIndex=-1; + $runCode =& self::$running; + $runIndex =& self::$runIndex; + $loopsOwner =& self::$loopsOwner; + $memory =& self::$memory; + $c =& self::$c; + $operators = self::$operators; + $runIndex = -1; do { - if ( $break ) { - if ( $loopsOwner == T_WHILE ) { - $break--; - continue; - } - break; - } elseif ( $continue ) { - if ( $loopsOwner == T_WHILE ) { - $codeIndex = -1; - $continue = false; - } else { - continue; - } + for ( ++$runIndex; $runIndex < $c; ++$runIndex ) { + $value =& $runCode[$runIndex]; + $call = $operators[ $value[PHPTAGS_STACK_COMMAND] ]; + self::$call( $value ); } - $codeIndex++; - for ( ; $codeIndex < $c; $codeIndex++ ) { - $value =& $code[$codeIndex]; - switch ( $value[PHPTAGS_STACK_COMMAND] ) { - case '"': // Example: echo "abc$foo"; - $value[PHPTAGS_STACK_RESULT] = implode( $value[PHPTAGS_STACK_PARAM] ); - break; - case '.': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] . $value[PHPTAGS_STACK_PARAM_2]; - break; - case '+': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] + $value[PHPTAGS_STACK_PARAM_2]; - break; - case '-': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] - $value[PHPTAGS_STACK_PARAM_2]; - break; - case '*': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] * $value[PHPTAGS_STACK_PARAM_2]; - break; - case '/': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] / $value[PHPTAGS_STACK_PARAM_2]; - break; - case '%': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] % $value[PHPTAGS_STACK_PARAM_2]; - break; - case '&': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] & $value[PHPTAGS_STACK_PARAM_2]; - break; - case '|': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] | $value[PHPTAGS_STACK_PARAM_2]; - break; - case '^': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] ^ $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_SL: // << - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] << $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_SR: // >> - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] >> $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_LOGICAL_AND: // and - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] && $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_LOGICAL_XOR: // xor - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] xor $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_LOGICAL_OR: // or - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] || $value[PHPTAGS_STACK_PARAM_2]; - break; - case '<': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] < $value[PHPTAGS_STACK_PARAM_2]; - break; - case '>': - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] > $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_IS_SMALLER_OR_EQUAL: // <= - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] <= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_IS_GREATER_OR_EQUAL: // >= - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] >= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_IS_EQUAL: // == - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] == $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_IS_NOT_EQUAL: // != - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] != $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_IS_IDENTICAL: // === - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] === $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_IS_NOT_IDENTICAL: // !== - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM] !== $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_PRINT: - if( $value[PHPTAGS_STACK_PARAM] instanceof GenericObject ) { - $return[] = $value[PHPTAGS_STACK_PARAM]->toString(); - } else { - $return[] = $value[PHPTAGS_STACK_PARAM]; - } - break; - case '~': - $value[PHPTAGS_STACK_RESULT] = ~$value[PHPTAGS_STACK_PARAM_2]; - break; - case '!': - $value[PHPTAGS_STACK_RESULT] = !$value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_INT_CAST: // (int) - $value[PHPTAGS_STACK_RESULT] = (int)$value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_DOUBLE_CAST: // (double) - $value[PHPTAGS_STACK_RESULT] = (double)$value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_STRING_CAST: // (string) - $value[PHPTAGS_STACK_RESULT] = (string)$value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_ARRAY_CAST: // (array) - $value[PHPTAGS_STACK_RESULT] = (array)$value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_BOOL_CAST: // (bool) - $value[PHPTAGS_STACK_RESULT] = (bool)$value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_UNSET_CAST: // (unset) - $value[PHPTAGS_STACK_RESULT] = (unset)$value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_VARIABLE: - $aim = $value[PHPTAGS_STACK_AIM]; - if ( isset($thisVariables[ $value[PHPTAGS_STACK_PARAM] ]) || array_key_exists($value[PHPTAGS_STACK_PARAM], $thisVariables) ) { - $value[PHPTAGS_STACK_PARAM_2][$aim] =& $thisVariables[ $value[PHPTAGS_STACK_PARAM] ]; - if ( isset($value[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: $foo[1] - foreach ( $value[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { - if ( is_array( $value[PHPTAGS_STACK_PARAM_2][$aim] ) ) { - if ( isset($value[PHPTAGS_STACK_PARAM_2][$aim][$v]) || array_key_exists($v, $value[PHPTAGS_STACK_PARAM_2][$aim]) ) { - $value[PHPTAGS_STACK_PARAM_2][$aim] =& $value[PHPTAGS_STACK_PARAM_2][$aim][$v]; - } else { - // PHP Notice: Undefined offset: $1 - self::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_INDEX, $v ) ); - unset( $value[PHPTAGS_STACK_PARAM_2][$aim] ); - $value[PHPTAGS_STACK_PARAM_2][$aim] = null; - } - } else { - if ( isset( $value[PHPTAGS_STACK_PARAM_2][$aim][$v]) ) { - unset( $value[PHPTAGS_STACK_PARAM_2][$aim] ); - $value[PHPTAGS_STACK_PARAM_2][$aim] = $value[PHPTAGS_STACK_PARAM_2][$aim][$v]; - } else { - // PHP Notice: Uninitialized string offset: $1 - self::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNINIT_STRING_OFFSET, (int)$v ) ); - unset( $value[PHPTAGS_STACK_PARAM_2][$aim] ); - $value[PHPTAGS_STACK_PARAM_2][$aim] = null; - } - } - } - } - } else { - unset( $value[PHPTAGS_STACK_PARAM_2][$aim] ); - $value[PHPTAGS_STACK_PARAM_2][$aim] = null; - self::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_VARIABLE, $value[PHPTAGS_STACK_PARAM] ) ); - } - break; - case '?': - if( $value[PHPTAGS_STACK_PARAM] ) { // true ? - if( $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_DO_TRUE] ) { // true ? 1+2 : - $memory[] = array( &$value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_PARAM], $code, $codeIndex, $c, $loopsOwner ); - $code = $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_DO_TRUE]; - $codeIndex = -1; - $c = count($code); - $loopsOwner = '?'; - }else{ // true ? 1 : - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_PARAM]; - } - }else{ // false ? - if( $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_DO_FALSE] ) { // false ? ... : 1+2 - $memory[] = array( &$value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_PARAM_2], $code, $codeIndex, $c, $loopsOwner ); - $code = $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_DO_FALSE]; - $codeIndex = -1; - $c = count($code); - $loopsOwner = '?'; - }else{ // false ? ... : 1 - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM_2][PHPTAGS_STACK_PARAM_2]; - } - } - break; - case PHPTAGS_T_IF: - if( $value[PHPTAGS_STACK_PARAM] ) { // Example: if( true ) - if( $value[PHPTAGS_STACK_DO_TRUE] ) { // Stack not empty: if(true); - $memory[] = array( null, $code, $codeIndex, $c, $loopsOwner ); - $code = $value[PHPTAGS_STACK_DO_TRUE]; - $codeIndex = -1; - $c = count($code); - $loopsOwner = T_IF; - } - }else{ // Example: if( false ) - if( isset($value[PHPTAGS_STACK_DO_FALSE]) ) { // Stack not empty: if(false) ; else ; - $memory[] = array( null, $code, $codeIndex, $c, $loopsOwner ); - $code = $value[PHPTAGS_STACK_DO_FALSE]; - $codeIndex = -1; - $c = count($code); - $loopsOwner = T_IF; - } - } - break; - case PHPTAGS_T_FOREACH: - if ( !is_array($value[PHPTAGS_STACK_PARAM]) ) { - self::pushException( new PhpTagsException( PhpTagsException::WARNING_INVALID_ARGUMENT_FOR_FOREACH, null ) ); - break; // **** EXIT **** - } - reset( $value[PHPTAGS_STACK_PARAM] ); - // break is not necessary here - case PHPTAGS_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, $codeIndex, $c, $loopsOwner ); - $code = $value[PHPTAGS_STACK_DO_TRUE]; - $codeIndex = -1; - $c = count($code); - $loopsOwner = T_WHILE; - break; - case PHPTAGS_T_AS: - if ( !is_array($value[PHPTAGS_STACK_RESULT]) ) { - self::pushException( new PhpTagsException( PhpTagsException::WARNING_INVALID_ARGUMENT_FOR_FOREACH, null ) ); - break; // **** EXIT **** - } - if ( isset($value[PHPTAGS_STACK_PARAM_2]) ) { // T_DOUBLE_ARROW Example: while ( $foo as $key=>$value ) - if ( !list($thisVariables[ $value[PHPTAGS_STACK_PARAM] ], $thisVariables[ $value[PHPTAGS_STACK_PARAM_2] ]) = each($value[PHPTAGS_STACK_RESULT]) ) { - break 2; // go to one level down - } - } else { // Example: while ( $foo as $value ) - if ( !list(,$thisVariables[ $value[PHPTAGS_STACK_PARAM] ]) = each($value[PHPTAGS_STACK_RESULT]) ) { - break 2; // go to one level down - } - } - break; - case PHPTAGS_T_BREAK: - $break = $value[PHPTAGS_STACK_RESULT]; - if( $loopsOwner == T_WHILE ) { - $break--; - } - break 2; // go to one level down - case PHPTAGS_T_CONTINUE: - if( self::$loopsLimit-- <= 0 ) { - throw new PhpTagsException( PhpTagsException::FATAL_LOOPS_LIMIT_REACHED, null, $value[PHPTAGS_STACK_TOKEN_LINE], $place ); - } - $break = $value[PHPTAGS_STACK_RESULT]-1; - if( $loopsOwner == T_WHILE && $break == 0 ) { // Example: while(true) continue; - $codeIndex = -1; - break; - } - $continue = true; - break 2; // go to one level down - case PHPTAGS_T_ARRAY: // array - $tmp = $value[PHPTAGS_STACK_PARAM][0]; - $i = 1; - foreach ( $value[PHPTAGS_STACK_PARAM_2] as $t ) { - list ( $k, $v ) = $t; - $tmp[$k] = $v; - if ( isset($value[PHPTAGS_STACK_PARAM][$i]) ) { - foreach ( $value[PHPTAGS_STACK_PARAM][$i] as $n ) { - $tmp[] = $n; - } - } - $i++; - } - $value[PHPTAGS_STACK_RESULT] = $tmp; - break; - case PHPTAGS_T_STATIC: - $vn = $value[PHPTAGS_STACK_PARAM]; // variable name - if( !isset(self::$staticVariables[$place]) || !array_key_exists($vn, self::$staticVariables[$place]) ) { - self::$staticVariables[$place][$vn] = &$value[PHPTAGS_STACK_RESULT]; - if( $value[PHPTAGS_STACK_DO_TRUE] ) { - //self::$staticVariables[$p][$vn] = null; - $memory[] = array( null, $code, $codeIndex, $c, $loopsOwner ); - $code = $value[PHPTAGS_STACK_DO_TRUE]; - $codeIndex = -1; - $c = count($code); - $loopsOwner = T_STATIC; - } - } - $thisVariables[$vn] = &self::$staticVariables[$place][$vn]; - break; - case PHPTAGS_T_GLOBAL: - foreach( $value[PHPTAGS_STACK_PARAM] as $vn ) { // variable names - if( !array_key_exists($vn, self::$globalVariables) ) { - self::$globalVariables[$vn] = null; - } - $thisVariables[$vn] = &self::$globalVariables[$vn]; - } - break; - case PHPTAGS_T_HOOK_CHECK_PARAM: - $i = $value[PHPTAGS_STACK_AIM]; - $reference_info = Hooks::getReferenceInfo( - $i, // ordinal number of the argument, zero is first - $value[PHPTAGS_STACK_HOOK_TYPE], - $value[PHPTAGS_STACK_PARAM], // name of function or method - $value[PHPTAGS_STACK_PARAM_3] === false ? false : $value[PHPTAGS_STACK_PARAM_3][PHPTAGS_STACK_PARAM_3] // $object or false - ); - - if ( $value[PHPTAGS_STACK_PARAM_2] === true && $reference_info === false ) { - // Param is variable and it needs to clone - $t = $value[PHPTAGS_STACK_RESULT][$i]; - unset( $value[PHPTAGS_STACK_RESULT][$i] ); - $value[PHPTAGS_STACK_RESULT][$i] = $t; - } elseif ( $value[PHPTAGS_STACK_PARAM_2] === false && $reference_info === true ) { - // Param is not variable and it's need reference - throw new PhpTagsException( PhpTagsException::FATAL_VALUE_PASSED_BY_REFERENCE, null, $value[PHPTAGS_STACK_TOKEN_LINE], $place ); - } - break; - case PHPTAGS_T_HOOK: - $result = Hooks::callHook( - $value[PHPTAGS_STACK_HOOK_TYPE], - $value[PHPTAGS_STACK_PARAM_2], // arguments - $value[PHPTAGS_STACK_PARAM], // name of function or method - $value[PHPTAGS_STACK_PARAM_3] // $object or false - ); - - if ( $result instanceof outPrint ) { - $value[PHPTAGS_STACK_RESULT] = $result->returnValue; - $return[] = $result; - } else { - $value[PHPTAGS_STACK_RESULT] = $result; - } - if ( is_object($value[PHPTAGS_STACK_RESULT]) && !($value[PHPTAGS_STACK_RESULT] instanceof iRawOutput || $value[PHPTAGS_STACK_RESULT] instanceof GenericObject) ) { - // @todo - $value[PHPTAGS_STACK_RESULT] = null; - self::pushException( new PhpTagsException( PhpTagsException::WARNING_RETURNED_INVALID_VALUE, $value[PHPTAGS_STACK_PARAM] ) ); - } - break; - case PHPTAGS_T_NEW: - $value[PHPTAGS_STACK_RESULT] = Hooks::createObject( $value[PHPTAGS_STACK_PARAM_2], $value[PHPTAGS_STACK_PARAM_3] ); - break; - case PHPTAGS_T_UNSET: - foreach ( $value[PHPTAGS_STACK_PARAM] as $val ) { - $vn = $val[PHPTAGS_STACK_PARAM]; // Variable Name - if ( isset($thisVariables[$vn]) || array_key_exists($vn, $thisVariables) ) { // defined variable - if ( isset($val[PHPTAGS_STACK_ARRAY_INDEX]) ) { // There is array index. Example: unset($foo[0]) - $ref = &$thisVariables[$vn]; - $tmp = array_pop( $val[PHPTAGS_STACK_ARRAY_INDEX] ); - foreach ( $val[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { - if ( is_string($ref) ) { - throw new PhpTagsException( PhpTagsException::FATAL_CANNOT_UNSET_STRING_OFFSETS, null, $value[PHPTAGS_STACK_TOKEN_LINE], $place ); - } elseif ( !isset($ref[$v]) ) { // undefined array index not for string - continue 2; - } - $ref = &$ref[$v]; - } - if ( is_array($ref) ) { - unset( $ref[$tmp] ); - } else { - throw new PhpTagsException( PhpTagsException::FATAL_CANNOT_UNSET_STRING_OFFSETS, null, $value[PHPTAGS_STACK_TOKEN_LINE], $place ); - } - }else{ // There is no array index. Example: unset($foo) - unset( $thisVariables[$vn] ); - } - } elseif ( isset($val[PHPTAGS_STACK_ARRAY_INDEX]) ) { // undefined variable with array index. Example: unset($foo[1]) - self::pushException( new PhpTagsException( PHPTAGS_NOTICE_UNDEFINED_VARIABLE, $vn ) ); - } - } - break; - case PHPTAGS_T_ISSET: - foreach($value[PHPTAGS_STACK_PARAM] as $val) { - if( !isset($thisVariables[ $val[PHPTAGS_STACK_PARAM] ]) ) { // undefined variable or variable is null - $value[PHPTAGS_STACK_RESULT] = false; - break 2; - } // true, variable is defined - if( isset($val[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: isset($foo[1]) - $ref = &$thisVariables[ $val[PHPTAGS_STACK_PARAM] ]; - $tmp = array_pop( $val[PHPTAGS_STACK_ARRAY_INDEX] ); - foreach( $val[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { - if( !isset($ref[$v]) ) { // undefined array index - $value[PHPTAGS_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[$tmp]) || (is_string($ref) && is_string($tmp ) && $tmp != (string)(int)$tmp ) ) { - $value[PHPTAGS_STACK_RESULT] = false; - break 2; - } - } // true, variable is defined and have no array index - } - $value[PHPTAGS_STACK_RESULT] = true; - break; - case PHPTAGS_T_EMPTY: - foreach($value[PHPTAGS_STACK_PARAM] as $val) { - if( !array_key_exists($val[PHPTAGS_STACK_PARAM], $thisVariables) ) { // undefined variable - continue; - } - $ref = &$thisVariables[ $val[PHPTAGS_STACK_PARAM] ]; - if( isset($val[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: empty($foo[1]) - $tmp = array_pop( $val[PHPTAGS_STACK_ARRAY_INDEX] ); - foreach( $val[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { - if( !isset($ref[$v]) ) { // undefined array index - continue 2; - } - $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.empty.php Example #2 empty() on String Offsets - if( !empty($ref[$tmp]) && (is_array($ref) || !is_string( $tmp ) || $tmp == (string)(int)$tmp ) ) { - $value[PHPTAGS_STACK_RESULT] = false; - break 2; - } - }elseif( !empty($ref) ) { // there is no array index and empty() returns false (PHP 5.5.0 supports expressions) - $value[PHPTAGS_STACK_RESULT] = false; - break 2; - } - } - $value[PHPTAGS_STACK_RESULT] = true; - break; - case PHPTAGS_T_RETURN: - if ( $return ) { - return new PhpTagsException(); - } - return $value[PHPTAGS_STACK_PARAM]; - case PHPTAGS_T_COPY: - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM]; - break; - case '@': - if ( $value[PHPTAGS_STACK_PARAM] === true ) { - $exceptions = false; - } else { - $exceptions = array(); - } - break; - default: // ++, --, =, +=, -=, *=, etc... - $variable = &$value[PHPTAGS_STACK_PARAM]; - $variableName = $variable[PHPTAGS_STACK_PARAM]; - if ( $variable[PHPTAGS_STACK_COMMAND] == PHPTAGS_T_LIST ) { // this is T_LIST. Example: list($foo, $bar) = $array; - self::fillList( $value[PHPTAGS_STACK_PARAM_2], $variable, $thisVariables ); - $value[PHPTAGS_STACK_RESULT] = $value[PHPTAGS_STACK_PARAM_2]; - unset( $variable ); - break; /**** EXIT ****/ - } - if( !(isset($thisVariables[$variableName]) || array_key_exists($variableName, $thisVariables)) ) { // Use undefined variable - if( isset($value[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: $foo[1]++ - $thisVariables[$variableName] = array(); - }else{ - $thisVariables[$variableName] = null; - } - if( $value[PHPTAGS_STACK_COMMAND] != '=' ) { - self::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_VARIABLE, $variableName ) ); - } - } - $ref = &$thisVariables[$variableName]; - if ( isset($variable[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: $foo[1]++ - foreach ( $variable[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { - if ( $v === INF ) { // Example: $foo[] - $t = null; - $ref[] = &$t; - $ref = &$t; - unset( $t ); - } else { - if ( $ref === null ) { - if( $value[PHPTAGS_STACK_COMMAND] != '=' ) { - // PHP Notice: Undefined offset: $1 - self::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_OFFSET, $v[PHPTAGS_STACK_RESULT] ) ); - } - $ref[$v] = null; - $ref = &$ref[$v]; - } elseif ( is_array($ref) ) { - if ( !( isset($ref[$v]) || array_key_exists($v, $ref) ) ) { - $ref[$v] = null; - if( $value[PHPTAGS_STACK_COMMAND] != '=' ) { - // PHP Notice: Undefined offset: $1 - self::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_INDEX, $v ) ); - } - } - $ref = &$ref[$v]; - } elseif ( is_string($ref) ) { - // PHP Fatal error: Cannot use string offset as an array - throw new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_OFFSET, $v, $value[PHPTAGS_STACK_TOKEN_LINE], $place ); - } else { - self::pushException( new PhpTagsException( PhpTagsException::FATAL_STRING_OFFSET_AS_ARRAY, $v ) ); - unset( $variable ); - break 2; - // PHP Warning: Cannot use a scalar value as an array - } - } - } - } - switch ( $value[PHPTAGS_STACK_COMMAND] ) { - case PHPTAGS_T_INC: - if ( $value[PHPTAGS_STACK_PARAM_2] ) { // $foo++ - $value[PHPTAGS_STACK_RESULT] = $ref++; - }else{ // ++$foo - $value[PHPTAGS_STACK_RESULT] = ++$ref; - } - break; - case PHPTAGS_T_DEC: - if ( $value[PHPTAGS_STACK_PARAM_2] ) { // $foo-- - $value[PHPTAGS_STACK_RESULT] = $ref--; - }else{ // --$foo - $value[PHPTAGS_STACK_RESULT] = --$ref; - } - break; - case '=': - $value[PHPTAGS_STACK_RESULT] = $ref = $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_CONCAT_EQUAL: // .= - $value[PHPTAGS_STACK_RESULT] = $ref .= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_PLUS_EQUAL: // += - $value[PHPTAGS_STACK_RESULT] = $ref += $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_MINUS_EQUAL: // -= - $value[PHPTAGS_STACK_RESULT] = $ref -= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_MUL_EQUAL: // *= - $value[PHPTAGS_STACK_RESULT] = $ref *= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_DIV_EQUAL: // /= - $value[PHPTAGS_STACK_RESULT] = $ref /= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_MOD_EQUAL: // %= - $value[PHPTAGS_STACK_RESULT] = $ref %= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_AND_EQUAL: // &= - $value[PHPTAGS_STACK_RESULT] = $ref &= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_OR_EQUAL: // |= - $value[PHPTAGS_STACK_RESULT] = $ref |= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_XOR_EQUAL: // ^= - $value[PHPTAGS_STACK_RESULT] = $ref ^= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_SL_EQUAL: // <<= - $value[PHPTAGS_STACK_RESULT] = $ref <<= $value[PHPTAGS_STACK_PARAM_2]; - break; - case PHPTAGS_T_SR_EQUAL: // >>= - $value[PHPTAGS_STACK_RESULT] = $ref >>= $value[PHPTAGS_STACK_PARAM_2]; - break; - } - break; - } - if ( $exceptions ) { - foreach ( $exceptions as $exc ) { - $exc->tokenLine = $value[PHPTAGS_STACK_TOKEN_LINE]; - $exc->place = $place; - $return[] = (string) $exc; - } - $exceptions = array(); - self::addRuntimeErrorCategory(); - } - } - } while( list($code[$codeIndex][PHPTAGS_STACK_RESULT], $code, $codeIndex, $c, $loopsOwner) = array_pop($memory) ); + } while( list($runCode[$runIndex][PHPTAGS_STACK_RESULT], $runCode, $runIndex, $c, $loopsOwner) = array_pop($memory) ); } catch ( PhpTagsException $e ) { - $e->tokenLine = $value[PHPTAGS_STACK_TOKEN_LINE]; - $e->place = $place; - if ( $exceptions ) { - foreach ( $exceptions as $exc ) { - $exc->tokenLine = $value[PHPTAGS_STACK_TOKEN_LINE]; - $exc->place = $place; - $return[] = (string) $exc; - } + if ( self::$ignoreErrors ) { + self::$ignoreErrors = false; + } else { + $e->tokenLine = $value[PHPTAGS_STACK_TOKEN_LINE]; + $e->place = self::$place; + self::addRuntimeErrorCategory(); + self::$return[] = (string) $e; } - $exceptions = array(); - self::addRuntimeErrorCategory(); - $return[] = (string) $e; $value[PHPTAGS_STACK_RESULT] = null; } catch ( \Exception $e ) { - $exceptions = array(); self::addRuntimeErrorCategory(); restore_error_handler(); throw $e; } restore_error_handler(); - return $return; + return self::$return; } - private static function fillList( &$values, &$param, &$thisVariables ) { + static function fillList( &$values, &$parametrs, &$thisVariables ) { $return = array(); - foreach ( $param[PHPTAGS_STACK_PARAM] as $key => $val ) { - if( $val !== null ) { // skip emty params. Example: list(, $bar) = $array; - if( $val[PHPTAGS_STACK_COMMAND] == PHPTAGS_T_LIST ) { // T_LIST inside other T_LIST. Example: list($a, list($b, $c)) = array(1, array(2, 3)); - if ( is_array($values) && isset($values[$key]) ) { - $return[$key] = self::fillList($values[$key], $val, $thisVariables); - } else { - static $a=array(); - $return[$key] = self::fillList($a, $val, $thisVariables); - } - continue; - } - $ref = &$thisVariables[ $val[PHPTAGS_STACK_PARAM] ]; - if ( isset($val[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: list($foo[0], $foo[1]) = $array; - foreach ( $val[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { - if ( $v === INF ) { // Example: $foo[] - $t = null; - $ref[] = &$t; - $ref = &$t; - unset( $t ); - } else { - if ( !isset($ref[$v]) ) { - $ref[$v] = null; - } - $ref = &$ref[$v]; - } - } - } - if ( is_array($values) ) { - if ( isset($values[$key]) ) { - $ref = $values[$key]; - } else { - $ref = null; - // @todo E_NOTICE - } - } else { // list() work with array only - $ref = null; - } - $return[$key] = $ref; + + for ( $pkey = count( $parametrs ) - 1; $pkey >= 0; --$pkey ) { + $param = $parametrs[$pkey]; + if ( $param === null ) { // skip emty params. Example: list(, $bar) = $array; + continue; } + if( $param[PHPTAGS_STACK_COMMAND] == PHPTAGS_T_LIST ) { // T_LIST inside other T_LIST. Example: list($a, list($b, $c)) = array(1, array(2, 3)); + if ( is_array($values) && isset($values[$pkey]) ) { + $return[$pkey] = self::fillList($values[$pkey], $param[PHPTAGS_STACK_PARAM], $thisVariables); + } else { + static $emptyArray=array(); + $return[$pkey] = self::fillList($emptyArray, $param[PHPTAGS_STACK_PARAM], $thisVariables); + } + continue; + } + // $param is variable + $ref = &$thisVariables[ $param[PHPTAGS_STACK_PARAM] ]; + if ( isset($param[PHPTAGS_STACK_ARRAY_INDEX]) ) { // Example: list($foo[0], $foo[1]) = $array; + foreach ( $param[PHPTAGS_STACK_ARRAY_INDEX] as $v ) { + if ( $v === INF ) { // Example: $foo[] + $t = null; + $ref[] = &$t; + $ref = &$t; + unset( $t ); + } else { + if ( !isset($ref[$v]) ) { + $ref[$v] = null; + } + $ref = &$ref[$v]; + } + } + } + if ( is_array($values) ) { + if ( isset($values[$pkey]) || array_key_exists($pkey, $values) ) { + $ref = $values[$pkey]; + } else { + $ref = null; + Runtime::pushException( new PhpTagsException( PhpTagsException::NOTICE_UNDEFINED_OFFSET, $pkey ) ); + } + } else { // list() work with array only + $ref = null; + } + $return[$pkey] = $ref; } } @@ -793,13 +1399,15 @@ } public static function pushException( PhpTagsException $exc ) { - if ( self::$exceptions !== false ) { - self::$exceptions[] = $exc; + if ( self::$ignoreErrors === false ) { + $exc->tokenLine = self::$running[self::$runIndex][PHPTAGS_STACK_TOKEN_LINE]; + $exc->place = self::$place; + self::$return[] = (string) $exc; } } public static function getExceptions() { - return self::$exceptions; + return false; } public static function getVariables() { -- To view, visit https://gerrit.wikimedia.org/r/191858 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Idbfcca925f6668a6d1ec9810e6f8c1df75c31c58 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/PhpTags Gerrit-Branch: master Gerrit-Owner: Pastakhov <pastak...@yandex.ru> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits