Index: extensions/ParserFunctions/Expr.php =================================================================== --- extensions/ParserFunctions/Expr.php (revision 17825) +++ extensions/ParserFunctions/Expr.php (arbetskopia) @@ -30,6 +30,14 @@ define( 'EXPR_GREATEREQ', 19 ); define( 'EXPR_NOTEQ', 20 ); define( 'EXPR_ROUND', 21 ); +define( 'EXPR_INT_DIVIDE', 22); +define( 'EXPR_CEIL', 23); +define( 'EXPR_FLOOR', 24); +define( 'EXPR_ABS', 25); +define( 'EXPR_FLOAT_MOD', 26); +define( 'EXPR_POW', 27); +define( 'EXPR_SQRT', 28); +define( 'EXPR_E', 29); class ExprError extends Exception { public function __construct($msg, $parameter = ''){ @@ -43,10 +51,18 @@ var $precedence = array( EXPR_NEGATIVE => 10, EXPR_POSITIVE => 10, + EXPR_E => 10, EXPR_NOT => 9, + EXPR_ABS => 9, + EXPR_CEIL => 9, + EXPR_FLOOR => 9, + EXPR_POW => 9, + EXPR_SQRT => 9, EXPR_TIMES => 8, EXPR_DIVIDE => 8, + EXPR_INT_DIVIDE => 8, EXPR_MOD => 8, + EXPR_FLOAT_MOD => 8, EXPR_PLUS => 6, EXPR_MINUS => 6, EXPR_ROUND => 5, @@ -69,6 +85,7 @@ EXPR_TIMES => '*', EXPR_DIVIDE => '/', EXPR_MOD => 'mod', + EXPR_FLOAT_MOD => 'fmod', EXPR_PLUS => '+', EXPR_MINUS => '-', EXPR_ROUND => 'round', @@ -80,6 +97,13 @@ EXPR_NOTEQ => '<>', EXPR_AND => 'and', EXPR_OR => 'or', + EXPR_INT_DIVIDE => 'idiv', + EXPR_ABS => 'abs', + EXPR_CEIL => 'ceil', + EXPR_FLOOR => 'floor', + EXPR_POW => '^', + EXPR_SQRT => 'sqrt', + EXPR_E => 'e', ); @@ -89,7 +113,14 @@ 'or' => EXPR_OR, 'not' => EXPR_NOT, 'round' => EXPR_ROUND, - 'div' => EXPR_DIVIDE + 'div' => EXPR_DIVIDE, + 'idiv' => EXPR_INT_DIVIDE, + 'floor' => EXPR_FLOOR, + 'ceil' => EXPR_CEIL, + 'abs' => EXPR_ABS, + 'fmod' => EXPR_FLOAT_MOD, + 'sqrt' => EXPR_SQRT, + 'e' => EXPR_E, //A workaround to handle php type numbers in the 1E-01 format ); @@ -182,6 +213,10 @@ // Unary operator switch($op){ case EXPR_NOT: + case EXPR_CEIL: + case EXPR_FLOOR: + case EXPR_ABS: + case EXPR_SQRT: if ( $expecting != 'expression' ) { throw new ExprError('unexpected_operator', $word); } @@ -272,6 +307,10 @@ $name = $char; $op = EXPR_GREATER; ++$p; + } elseif ( $char == '^' ) { + $name = $char; + $op = EXPR_POW; + ++$p; } else { throw new ExprError('unrecognised_punctuation', $char); } @@ -404,6 +443,57 @@ $left = array_pop( $stack ); $stack[] = ( $left != $right ) ? 1 : 0; break; + case EXPR_ABS: + if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); + $arg = array_pop( $stack ); + $stack[] = abs($arg); + break; + case EXPR_CEIL: + if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); + $arg = array_pop( $stack ); + $stack[] = ceil($arg); + break; + case EXPR_FLOOR: + if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); + $arg = array_pop( $stack ); + $stack[] = floor($arg); + break; + case EXPR_E: + if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); + $right = array_pop( $stack ); + $left = array_pop( $stack ); + // can never be NaN + $stack[] = $left * pow(10,$right); + break; + case EXPR_POW: + if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); + $right = array_pop( $stack ); + $left = array_pop( $stack ); + $result = pow($left,$right); + if (is_nan($result)) throw new ExprError('not_a_number', $this->names[$op]); + $stack[] = $result; + break; + case EXPR_FLOAT_MOD: + if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); + $right = array_pop( $stack ); + $left = array_pop( $stack ); + if ( $right == 0 ) throw new ExprError('division_by_zero', $this->names[$op]); + $stack[] = fmod($left,$right); + break; + case EXPR_SQRT: + if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); + $arg = array_pop( $stack ); + $result = sqrt($arg); + if (is_nan($result)) throw new ExprError('not_a_number', $this->names[$op]); + $stack[] = $result; + break; + case EXPR_INT_DIVIDE: + if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); + $right = array_pop( $stack ); + $left = array_pop( $stack ); + if ( $right == 0 ) throw new ExprError('division_by_zero', $this->names[$op]); + $stack[] = (int)($left / $right); + break; default: // Should be impossible to reach here. throw new ExprError('unknown_error'); Index: extensions/ParserFunctions/ParserFunctions.php =================================================================== --- extensions/ParserFunctions/ParserFunctions.php (revision 17825) +++ extensions/ParserFunctions/ParserFunctions.php (arbetskopia) @@ -38,7 +38,36 @@ return $e->getMessage(); } } + function maxHook(&$parser) { + $args = func_get_args(); + array_shift( $args ); + $exprParser = $this->getExprParser(); + foreach($args as $expr){ + $res = $exprParser->doExpression($expr); + if( $res === false ) + return $exprParser->lastErrorMessage.print_r($args,true); + else + $result[] = $res; + } + return max($result); + } + + function minHook(&$parser) { + $args = func_get_args(); + array_shift( $args ); + + $exprParser = $this->getExprParser(); + foreach($args as $expr){ + $res = $exprParser->doExpression($expr); + if( $res === false ) + return $exprParser->lastErrorMessage.print_r($args,true); + else + $result[] = $res; + } + return min($result); + } + function ifexpr( &$parser, $expr = '', $then = '', $else = '' ) { try{ if($this->getExprParser()->doExpression( $expr )) { @@ -157,6 +186,8 @@ $wgParser->setFunctionHook( 'switch', array( &$wgExtParserFunctions, 'switchHook' ) ); $wgParser->setFunctionHook( 'ifexist', array( &$wgExtParserFunctions, 'ifexist' ) ); $wgParser->setFunctionHook( 'time', array( &$wgExtParserFunctions, 'time' ) ); + $wgParser->setFunctionHook( 'max', array( &$wgExtParserFunctions, 'maxHook' ) ); + $wgParser->setFunctionHook( 'min', array( &$wgExtParserFunctions, 'minHook' ) ); $wgMessageCache->addMessage( 'pfunc_time_error', "Error: invalid time" ); $wgMessageCache->addMessage( 'pfunc_time_too_long', "Error: too many #time calls" ); @@ -185,6 +216,8 @@ $magicWords['default'] = array( 0, '#default' ); $magicWords['ifexist'] = array( 0, 'ifexist' ); $magicWords['time'] = array( 0, 'time' ); + $magicWords['max'] = array( 0, 'max' ); + $magicWords['min'] = array( 0, 'min' ); } return true; }