2007-01-05 02:13:39 +00:00
|
|
|
|
<?php
|
2018-02-24 22:06:58 +00:00
|
|
|
|
/**
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
|
*
|
|
|
|
|
*/
|
2007-01-05 02:13:39 +00:00
|
|
|
|
|
2022-03-05 15:06:59 +00:00
|
|
|
|
namespace MediaWiki\Extension\ParserFunctions;
|
2019-03-28 03:52:55 +00:00
|
|
|
|
|
2016-12-22 22:47:24 +00:00
|
|
|
|
use UtfNormal\Validator;
|
|
|
|
|
|
2021-03-06 19:48:11 +00:00
|
|
|
|
class ExprParser {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
|
2021-03-06 19:48:11 +00:00
|
|
|
|
// Character classes
|
|
|
|
|
private const EXPR_WHITE_CLASS = " \t\r\n";
|
|
|
|
|
private const EXPR_NUMBER_CLASS = '0123456789.';
|
2007-01-05 02:13:39 +00:00
|
|
|
|
|
2021-03-06 19:48:11 +00:00
|
|
|
|
// Token types
|
|
|
|
|
private const EXPR_WHITE = 1;
|
|
|
|
|
private const EXPR_NUMBER = 2;
|
|
|
|
|
private const EXPR_NEGATIVE = 3;
|
|
|
|
|
private const EXPR_POSITIVE = 4;
|
|
|
|
|
private const EXPR_PLUS = 5;
|
|
|
|
|
private const EXPR_MINUS = 6;
|
|
|
|
|
private const EXPR_TIMES = 7;
|
|
|
|
|
private const EXPR_DIVIDE = 8;
|
|
|
|
|
private const EXPR_MOD = 9;
|
|
|
|
|
private const EXPR_OPEN = 10;
|
|
|
|
|
private const EXPR_CLOSE = 11;
|
|
|
|
|
private const EXPR_AND = 12;
|
|
|
|
|
private const EXPR_OR = 13;
|
|
|
|
|
private const EXPR_NOT = 14;
|
|
|
|
|
private const EXPR_EQUALITY = 15;
|
|
|
|
|
private const EXPR_LESS = 16;
|
|
|
|
|
private const EXPR_GREATER = 17;
|
|
|
|
|
private const EXPR_LESSEQ = 18;
|
|
|
|
|
private const EXPR_GREATEREQ = 19;
|
|
|
|
|
private const EXPR_NOTEQ = 20;
|
|
|
|
|
private const EXPR_ROUND = 21;
|
|
|
|
|
private const EXPR_EXPONENT = 22;
|
|
|
|
|
private const EXPR_SINE = 23;
|
|
|
|
|
private const EXPR_COSINE = 24;
|
|
|
|
|
private const EXPR_TANGENS = 25;
|
|
|
|
|
private const EXPR_ARCSINE = 26;
|
|
|
|
|
private const EXPR_ARCCOS = 27;
|
|
|
|
|
private const EXPR_ARCTAN = 28;
|
|
|
|
|
private const EXPR_EXP = 29;
|
|
|
|
|
private const EXPR_LN = 30;
|
|
|
|
|
private const EXPR_ABS = 31;
|
|
|
|
|
private const EXPR_FLOOR = 32;
|
|
|
|
|
private const EXPR_TRUNC = 33;
|
|
|
|
|
private const EXPR_CEIL = 34;
|
|
|
|
|
private const EXPR_POW = 35;
|
|
|
|
|
private const EXPR_PI = 36;
|
|
|
|
|
private const EXPR_FMOD = 37;
|
|
|
|
|
private const EXPR_SQRT = 38;
|
2019-09-05 22:07:54 +00:00
|
|
|
|
|
2021-03-06 19:48:11 +00:00
|
|
|
|
private const MAX_STACK_SIZE = 100;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
|
2021-03-06 19:48:11 +00:00
|
|
|
|
private const PRECEDENCE = [
|
|
|
|
|
self::EXPR_NEGATIVE => 10,
|
|
|
|
|
self::EXPR_POSITIVE => 10,
|
|
|
|
|
self::EXPR_EXPONENT => 10,
|
|
|
|
|
self::EXPR_SINE => 9,
|
|
|
|
|
self::EXPR_COSINE => 9,
|
|
|
|
|
self::EXPR_TANGENS => 9,
|
|
|
|
|
self::EXPR_ARCSINE => 9,
|
|
|
|
|
self::EXPR_ARCCOS => 9,
|
|
|
|
|
self::EXPR_ARCTAN => 9,
|
|
|
|
|
self::EXPR_EXP => 9,
|
|
|
|
|
self::EXPR_LN => 9,
|
|
|
|
|
self::EXPR_ABS => 9,
|
|
|
|
|
self::EXPR_FLOOR => 9,
|
|
|
|
|
self::EXPR_TRUNC => 9,
|
|
|
|
|
self::EXPR_CEIL => 9,
|
|
|
|
|
self::EXPR_NOT => 9,
|
|
|
|
|
self::EXPR_SQRT => 9,
|
|
|
|
|
self::EXPR_POW => 8,
|
|
|
|
|
self::EXPR_TIMES => 7,
|
|
|
|
|
self::EXPR_DIVIDE => 7,
|
|
|
|
|
self::EXPR_MOD => 7,
|
|
|
|
|
self::EXPR_FMOD => 7,
|
|
|
|
|
self::EXPR_PLUS => 6,
|
|
|
|
|
self::EXPR_MINUS => 6,
|
|
|
|
|
self::EXPR_ROUND => 5,
|
|
|
|
|
self::EXPR_EQUALITY => 4,
|
|
|
|
|
self::EXPR_LESS => 4,
|
|
|
|
|
self::EXPR_GREATER => 4,
|
|
|
|
|
self::EXPR_LESSEQ => 4,
|
|
|
|
|
self::EXPR_GREATEREQ => 4,
|
|
|
|
|
self::EXPR_NOTEQ => 4,
|
|
|
|
|
self::EXPR_AND => 3,
|
|
|
|
|
self::EXPR_OR => 2,
|
|
|
|
|
self::EXPR_PI => 0,
|
|
|
|
|
self::EXPR_OPEN => -1,
|
|
|
|
|
self::EXPR_CLOSE => -1,
|
2017-06-06 15:20:02 +00:00
|
|
|
|
];
|
2007-01-05 02:13:39 +00:00
|
|
|
|
|
2021-03-06 19:48:11 +00:00
|
|
|
|
private const NAMES = [
|
|
|
|
|
self::EXPR_NEGATIVE => '-',
|
|
|
|
|
self::EXPR_POSITIVE => '+',
|
|
|
|
|
self::EXPR_NOT => 'not',
|
|
|
|
|
self::EXPR_TIMES => '*',
|
|
|
|
|
self::EXPR_DIVIDE => '/',
|
|
|
|
|
self::EXPR_MOD => 'mod',
|
|
|
|
|
self::EXPR_FMOD => 'fmod',
|
|
|
|
|
self::EXPR_PLUS => '+',
|
|
|
|
|
self::EXPR_MINUS => '-',
|
|
|
|
|
self::EXPR_ROUND => 'round',
|
|
|
|
|
self::EXPR_EQUALITY => '=',
|
|
|
|
|
self::EXPR_LESS => '<',
|
|
|
|
|
self::EXPR_GREATER => '>',
|
|
|
|
|
self::EXPR_LESSEQ => '<=',
|
|
|
|
|
self::EXPR_GREATEREQ => '>=',
|
|
|
|
|
self::EXPR_NOTEQ => '<>',
|
|
|
|
|
self::EXPR_AND => 'and',
|
|
|
|
|
self::EXPR_OR => 'or',
|
|
|
|
|
self::EXPR_EXPONENT => 'e',
|
|
|
|
|
self::EXPR_SINE => 'sin',
|
|
|
|
|
self::EXPR_COSINE => 'cos',
|
|
|
|
|
self::EXPR_TANGENS => 'tan',
|
|
|
|
|
self::EXPR_ARCSINE => 'asin',
|
|
|
|
|
self::EXPR_ARCCOS => 'acos',
|
|
|
|
|
self::EXPR_ARCTAN => 'atan',
|
|
|
|
|
self::EXPR_LN => 'ln',
|
|
|
|
|
self::EXPR_EXP => 'exp',
|
|
|
|
|
self::EXPR_ABS => 'abs',
|
|
|
|
|
self::EXPR_FLOOR => 'floor',
|
|
|
|
|
self::EXPR_TRUNC => 'trunc',
|
|
|
|
|
self::EXPR_CEIL => 'ceil',
|
|
|
|
|
self::EXPR_POW => '^',
|
|
|
|
|
self::EXPR_PI => 'pi',
|
|
|
|
|
self::EXPR_SQRT => 'sqrt',
|
2017-06-06 15:20:02 +00:00
|
|
|
|
];
|
2007-01-06 20:56:46 +00:00
|
|
|
|
|
2021-03-06 19:48:11 +00:00
|
|
|
|
private const WORDS = [
|
|
|
|
|
'mod' => self::EXPR_MOD,
|
|
|
|
|
'fmod' => self::EXPR_FMOD,
|
|
|
|
|
'and' => self::EXPR_AND,
|
|
|
|
|
'or' => self::EXPR_OR,
|
|
|
|
|
'not' => self::EXPR_NOT,
|
|
|
|
|
'round' => self::EXPR_ROUND,
|
|
|
|
|
'div' => self::EXPR_DIVIDE,
|
|
|
|
|
'e' => self::EXPR_EXPONENT,
|
|
|
|
|
'sin' => self::EXPR_SINE,
|
|
|
|
|
'cos' => self::EXPR_COSINE,
|
|
|
|
|
'tan' => self::EXPR_TANGENS,
|
|
|
|
|
'asin' => self::EXPR_ARCSINE,
|
|
|
|
|
'acos' => self::EXPR_ARCCOS,
|
|
|
|
|
'atan' => self::EXPR_ARCTAN,
|
|
|
|
|
'exp' => self::EXPR_EXP,
|
|
|
|
|
'ln' => self::EXPR_LN,
|
|
|
|
|
'abs' => self::EXPR_ABS,
|
|
|
|
|
'trunc' => self::EXPR_TRUNC,
|
|
|
|
|
'floor' => self::EXPR_FLOOR,
|
|
|
|
|
'ceil' => self::EXPR_CEIL,
|
|
|
|
|
'pi' => self::EXPR_PI,
|
|
|
|
|
'sqrt' => self::EXPR_SQRT,
|
2017-06-06 15:20:02 +00:00
|
|
|
|
];
|
2009-02-01 03:56:24 +00:00
|
|
|
|
|
2007-01-05 02:13:39 +00:00
|
|
|
|
/**
|
|
|
|
|
* Evaluate a mathematical expression
|
|
|
|
|
*
|
|
|
|
|
* The algorithm here is based on the infix to RPN algorithm given in
|
|
|
|
|
* http://montcs.bloomu.edu/~bobmon/Information/RPN/infix2rpn.shtml
|
|
|
|
|
* It's essentially the same as Dijkstra's shunting yard algorithm.
|
2017-10-14 13:46:55 +00:00
|
|
|
|
* @param string $expr
|
2011-12-19 23:44:11 +00:00
|
|
|
|
* @return string
|
2020-03-26 15:49:16 +00:00
|
|
|
|
* @throws ExprError
|
2007-01-05 02:13:39 +00:00
|
|
|
|
*/
|
2016-03-08 12:02:18 +00:00
|
|
|
|
public function doExpression( $expr ) {
|
2017-06-06 15:20:02 +00:00
|
|
|
|
$operands = [];
|
|
|
|
|
$operators = [];
|
2007-01-05 02:13:39 +00:00
|
|
|
|
|
|
|
|
|
# Unescape inequality operators
|
2017-06-06 15:20:02 +00:00
|
|
|
|
$expr = strtr( $expr, [ '<' => '<', '>' => '>',
|
|
|
|
|
'−' => '-', '−' => '-' ] );
|
2007-01-06 20:56:46 +00:00
|
|
|
|
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$p = 0;
|
|
|
|
|
$end = strlen( $expr );
|
|
|
|
|
$expecting = 'expression';
|
2012-12-17 10:25:26 +00:00
|
|
|
|
$name = '';
|
2007-01-05 02:13:39 +00:00
|
|
|
|
|
|
|
|
|
while ( $p < $end ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
if ( count( $operands ) > self::MAX_STACK_SIZE || count( $operators ) > self::MAX_STACK_SIZE ) {
|
2010-10-02 22:36:34 +00:00
|
|
|
|
throw new ExprError( 'stack_exhausted' );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
|
|
|
|
$char = $expr[$p];
|
|
|
|
|
$char2 = substr( $expr, $p, 2 );
|
2007-01-06 20:56:46 +00:00
|
|
|
|
|
2007-01-05 02:13:39 +00:00
|
|
|
|
// Mega if-elseif-else construct
|
2008-01-13 01:06:28 +00:00
|
|
|
|
// Only binary operators fall through for processing at the bottom, the rest
|
2007-01-05 02:13:39 +00:00
|
|
|
|
// finish their processing and continue
|
|
|
|
|
|
|
|
|
|
// First the unlimited length classes
|
2007-01-06 20:56:46 +00:00
|
|
|
|
|
2019-03-17 05:39:09 +00:00
|
|
|
|
// @phan-suppress-next-line PhanParamSuspiciousOrder false positive
|
2021-03-06 19:48:11 +00:00
|
|
|
|
if ( strpos( self::EXPR_WHITE_CLASS, $char ) !== false ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
// Whitespace
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$p += strspn( $expr, self::EXPR_WHITE_CLASS, $p );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
continue;
|
2019-03-17 05:39:09 +00:00
|
|
|
|
// @phan-suppress-next-line PhanParamSuspiciousOrder false positive
|
2021-03-06 19:48:11 +00:00
|
|
|
|
} elseif ( strpos( self::EXPR_NUMBER_CLASS, $char ) !== false ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
// Number
|
2016-03-08 11:54:05 +00:00
|
|
|
|
if ( $expecting !== 'expression' ) {
|
2010-10-02 22:36:34 +00:00
|
|
|
|
throw new ExprError( 'unexpected_number' );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the rest of it
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$length = strspn( $expr, self::EXPR_NUMBER_CLASS, $p );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
// Convert it to float, silently removing double decimal points
|
2016-03-25 11:26:57 +00:00
|
|
|
|
$operands[] = (float)substr( $expr, $p, $length );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$p += $length;
|
|
|
|
|
$expecting = 'operator';
|
|
|
|
|
continue;
|
|
|
|
|
} elseif ( ctype_alpha( $char ) ) {
|
|
|
|
|
// Word
|
|
|
|
|
// Find the rest of it
|
|
|
|
|
$remaining = substr( $expr, $p );
|
|
|
|
|
if ( !preg_match( '/^[A-Za-z]*/', $remaining, $matches ) ) {
|
|
|
|
|
// This should be unreachable
|
2010-10-02 22:36:34 +00:00
|
|
|
|
throw new ExprError( 'preg_match_failure' );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
|
|
|
|
$word = strtolower( $matches[0] );
|
|
|
|
|
$p += strlen( $word );
|
|
|
|
|
|
|
|
|
|
// Interpret the word
|
2021-03-06 19:48:11 +00:00
|
|
|
|
if ( !isset( self::WORDS[$word] ) ) {
|
2010-10-02 22:36:34 +00:00
|
|
|
|
throw new ExprError( 'unrecognised_word', $word );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::WORDS[$word];
|
2017-06-06 15:20:02 +00:00
|
|
|
|
switch ( $op ) {
|
2018-10-15 10:35:36 +00:00
|
|
|
|
// constant
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_EXPONENT:
|
2018-10-15 10:35:36 +00:00
|
|
|
|
if ( $expecting !== 'expression' ) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
$operands[] = exp( 1 );
|
|
|
|
|
$expecting = 'operator';
|
|
|
|
|
continue 2;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_PI:
|
2018-10-15 10:35:36 +00:00
|
|
|
|
if ( $expecting !== 'expression' ) {
|
|
|
|
|
throw new ExprError( 'unexpected_number' );
|
|
|
|
|
}
|
|
|
|
|
$operands[] = pi();
|
|
|
|
|
$expecting = 'operator';
|
|
|
|
|
continue 2;
|
|
|
|
|
// Unary operator
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_NOT:
|
|
|
|
|
case self::EXPR_SINE:
|
|
|
|
|
case self::EXPR_COSINE:
|
|
|
|
|
case self::EXPR_TANGENS:
|
|
|
|
|
case self::EXPR_ARCSINE:
|
|
|
|
|
case self::EXPR_ARCCOS:
|
|
|
|
|
case self::EXPR_ARCTAN:
|
|
|
|
|
case self::EXPR_EXP:
|
|
|
|
|
case self::EXPR_LN:
|
|
|
|
|
case self::EXPR_ABS:
|
|
|
|
|
case self::EXPR_FLOOR:
|
|
|
|
|
case self::EXPR_TRUNC:
|
|
|
|
|
case self::EXPR_CEIL:
|
|
|
|
|
case self::EXPR_SQRT:
|
2018-10-15 10:35:36 +00:00
|
|
|
|
if ( $expecting !== 'expression' ) {
|
|
|
|
|
throw new ExprError( 'unexpected_operator', $word );
|
|
|
|
|
}
|
|
|
|
|
$operators[] = $op;
|
|
|
|
|
continue 2;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
|
|
|
|
// Binary operator, fall through
|
|
|
|
|
$name = $word;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char2 === '<=' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$name = $char2;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_LESSEQ;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$p += 2;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char2 === '>=' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$name = $char2;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_GREATEREQ;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$p += 2;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char2 === '<>' || $char2 === '!=' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$name = $char2;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_NOTEQ;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$p += 2;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char === '+' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
++$p;
|
2016-03-08 11:54:05 +00:00
|
|
|
|
if ( $expecting === 'expression' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
// Unary plus
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$operators[] = self::EXPR_POSITIVE;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
// Binary plus
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_PLUS;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char === '-' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
++$p;
|
2016-03-08 11:54:05 +00:00
|
|
|
|
if ( $expecting === 'expression' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
// Unary minus
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$operators[] = self::EXPR_NEGATIVE;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
// Binary minus
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_MINUS;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char === '*' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$name = $char;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_TIMES;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
++$p;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char === '/' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$name = $char;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_DIVIDE;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
++$p;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char === '^' ) {
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$name = $char;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_POW;
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
++$p;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char === '(' ) {
|
2016-03-08 11:54:05 +00:00
|
|
|
|
if ( $expecting === 'operator' ) {
|
2010-10-02 22:36:34 +00:00
|
|
|
|
throw new ExprError( 'unexpected_operator', '(' );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$operators[] = self::EXPR_OPEN;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
++$p;
|
|
|
|
|
continue;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char === ')' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$lastOp = end( $operators );
|
2021-03-06 19:48:11 +00:00
|
|
|
|
while ( $lastOp && $lastOp !== self::EXPR_OPEN ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$this->doOperation( $lastOp, $operands );
|
|
|
|
|
array_pop( $operators );
|
|
|
|
|
$lastOp = end( $operators );
|
|
|
|
|
}
|
|
|
|
|
if ( $lastOp ) {
|
|
|
|
|
array_pop( $operators );
|
|
|
|
|
} else {
|
2010-10-02 22:36:34 +00:00
|
|
|
|
throw new ExprError( 'unexpected_closing_bracket' );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
|
|
|
|
$expecting = 'operator';
|
|
|
|
|
++$p;
|
|
|
|
|
continue;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char === '=' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$name = $char;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_EQUALITY;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
++$p;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char === '<' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$name = $char;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_LESS;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
++$p;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} elseif ( $char === '>' ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$name = $char;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
$op = self::EXPR_GREATER;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
++$p;
|
2018-02-24 23:59:23 +00:00
|
|
|
|
} else {
|
2018-02-02 08:24:19 +00:00
|
|
|
|
$utfExpr = Validator::cleanUp( substr( $expr, $p ) );
|
|
|
|
|
throw new ExprError( 'unrecognised_punctuation', mb_substr( $utfExpr, 0, 1 ) );
|
2018-02-24 23:59:23 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
|
|
|
|
|
// Binary operator processing
|
2016-03-08 11:54:05 +00:00
|
|
|
|
if ( $expecting === 'expression' ) {
|
2010-10-02 22:36:34 +00:00
|
|
|
|
throw new ExprError( 'unexpected_operator', $name );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Shunting yard magic
|
|
|
|
|
$lastOp = end( $operators );
|
2021-03-06 19:48:11 +00:00
|
|
|
|
while ( $lastOp && self::PRECEDENCE[$op] <= self::PRECEDENCE[$lastOp] ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$this->doOperation( $lastOp, $operands );
|
|
|
|
|
array_pop( $operators );
|
|
|
|
|
$lastOp = end( $operators );
|
|
|
|
|
}
|
|
|
|
|
$operators[] = $op;
|
|
|
|
|
$expecting = 'expression';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Finish off the operator array
|
2021-04-03 21:29:19 +00:00
|
|
|
|
// phpcs:ignore MediaWiki.ControlStructures.AssignmentInControlStructures.AssignmentInControlStructures
|
2007-01-05 02:13:39 +00:00
|
|
|
|
while ( $op = array_pop( $operators ) ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
if ( $op === self::EXPR_OPEN ) {
|
2010-10-02 22:36:34 +00:00
|
|
|
|
throw new ExprError( 'unclosed_bracket' );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
2007-01-06 20:56:46 +00:00
|
|
|
|
$this->doOperation( $op, $operands );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
2007-01-06 20:56:46 +00:00
|
|
|
|
|
2007-01-05 02:13:39 +00:00
|
|
|
|
return implode( "<br />\n", $operands );
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-19 23:44:11 +00:00
|
|
|
|
/**
|
2017-10-14 13:46:55 +00:00
|
|
|
|
* @param int $op
|
|
|
|
|
* @param array &$stack
|
2011-12-19 23:44:11 +00:00
|
|
|
|
* @throws ExprError
|
|
|
|
|
*/
|
2016-03-08 12:02:18 +00:00
|
|
|
|
public function doOperation( $op, &$stack ) {
|
2007-01-05 02:13:39 +00:00
|
|
|
|
switch ( $op ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_NEGATIVE:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = -$arg;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_POSITIVE:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_TIMES:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = $left * $right;
|
2021-05-03 09:10:46 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_DIVIDE:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2012-12-07 02:31:13 +00:00
|
|
|
|
if ( !$right ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'division_by_zero', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = $left / $right;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_MOD:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2012-12-28 21:27:23 +00:00
|
|
|
|
$right = (int)array_pop( $stack );
|
|
|
|
|
$left = (int)array_pop( $stack );
|
|
|
|
|
if ( !$right ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'division_by_zero', self::NAMES[$op] );
|
2012-12-28 21:27:23 +00:00
|
|
|
|
}
|
|
|
|
|
$stack[] = $left % $right;
|
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_FMOD:
|
2012-12-28 21:27:23 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2012-12-28 21:27:23 +00:00
|
|
|
|
}
|
|
|
|
|
$right = (double)array_pop( $stack );
|
|
|
|
|
$left = (double)array_pop( $stack );
|
2012-12-07 02:31:13 +00:00
|
|
|
|
if ( !$right ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'division_by_zero', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2012-12-28 21:27:23 +00:00
|
|
|
|
$stack[] = fmod( $left, $right );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_PLUS:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = $left + $right;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_MINUS:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = $left - $right;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_AND:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
|
|
|
|
$stack[] = ( $left && $right ) ? 1 : 0;
|
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_OR:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
|
|
|
|
$stack[] = ( $left || $right ) ? 1 : 0;
|
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_EQUALITY:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = ( $left == $right ) ? 1 : 0;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_NOT:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = ( !$arg ) ? 1 : 0;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_ROUND:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2016-03-25 11:26:57 +00:00
|
|
|
|
$digits = (int)array_pop( $stack );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$value = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = round( $value, $digits );
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_LESS:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = ( $left < $right ) ? 1 : 0;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_GREATER:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = ( $left > $right ) ? 1 : 0;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_LESSEQ:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = ( $left <= $right ) ? 1 : 0;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_GREATEREQ:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = ( $left >= $right ) ? 1 : 0;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_NOTEQ:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2007-01-05 02:13:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = ( $left != $right ) ? 1 : 0;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_EXPONENT:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2008-03-28 11:59:12 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = $left * pow( 10, $right );
|
2008-03-28 11:59:12 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_SINE:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = sin( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_COSINE:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = cos( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_TANGENS:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = tan( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_ARCSINE:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( $arg < -1 || $arg > 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'invalid_argument', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = asin( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_ARCCOS:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( $arg < -1 || $arg > 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'invalid_argument', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = acos( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_ARCTAN:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = atan( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_EXP:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = exp( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_LN:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( $arg <= 0 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'invalid_argument_ln', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = log( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_ABS:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = abs( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_FLOOR:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = floor( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_TRUNC:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2009-02-18 05:57:38 +00:00
|
|
|
|
$stack[] = (int)$arg;
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_CEIL:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$arg = array_pop( $stack );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
$stack[] = ceil( $arg );
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_POW:
|
2011-12-19 23:44:11 +00:00
|
|
|
|
if ( count( $stack ) < 2 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
$right = array_pop( $stack );
|
|
|
|
|
$left = array_pop( $stack );
|
2017-06-06 15:20:02 +00:00
|
|
|
|
$result = pow( $left, $right );
|
|
|
|
|
if ( $result === false ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'division_by_zero', self::NAMES[$op] );
|
2011-12-19 23:44:11 +00:00
|
|
|
|
}
|
2017-06-06 15:20:02 +00:00
|
|
|
|
$stack[] = $result;
|
* (bug 13216 ) Add trigonometrical functions sin, cos, tan, asin, acos, atan and exp, ln, abs, floor, trunc, ceil, ^, and the constants pi and e.
This should help to avoid complicate templates which simulates these functions for geocoding purposes.
Patch by Rene Kijewski
2008-04-23 15:08:39 +00:00
|
|
|
|
break;
|
2021-03-06 19:48:11 +00:00
|
|
|
|
case self::EXPR_SQRT:
|
2013-01-06 19:26:26 +00:00
|
|
|
|
if ( count( $stack ) < 1 ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'missing_operand', self::NAMES[$op] );
|
2013-01-06 19:26:26 +00:00
|
|
|
|
}
|
|
|
|
|
$arg = array_pop( $stack );
|
|
|
|
|
$result = sqrt( $arg );
|
|
|
|
|
if ( is_nan( $result ) ) {
|
2021-03-06 19:48:11 +00:00
|
|
|
|
throw new ExprError( 'not_a_number', self::NAMES[$op] );
|
2013-01-06 19:26:26 +00:00
|
|
|
|
}
|
|
|
|
|
$stack[] = $result;
|
|
|
|
|
break;
|
2007-01-05 02:13:39 +00:00
|
|
|
|
default:
|
|
|
|
|
// Should be impossible to reach here.
|
2019-09-05 22:07:54 +00:00
|
|
|
|
// @codeCoverageIgnoreStart
|
2010-10-02 22:36:34 +00:00
|
|
|
|
throw new ExprError( 'unknown_error' );
|
2019-09-05 22:07:54 +00:00
|
|
|
|
// @codeCoverageIgnoreEnd
|
2007-01-05 02:13:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|