forked from TYPO3/Fluid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMathExpressionNode.php
87 lines (81 loc) · 3.07 KB
/
MathExpressionNode.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?php
namespace TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression;
/*
* This file belongs to the package "TYPO3 Fluid".
* See LICENSE.txt that was shipped with this package.
*/
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
/**
* Math Expression Syntax Node - is a container for numeric values.
*/
class MathExpressionNode extends AbstractExpressionNode
{
/**
* Pattern which detects the mathematical expressions with either
* object accessor expressions or numbers on left and right hand
* side of a mathematical operator inside curly braces, e.g.:
*
* {variable * 10}, {100 / variable}, {variable + variable2} etc.
*/
public static $detectionExpression = '/
(
{ # Start of shorthand syntax
(?: # Math expression is composed of...
[_a-zA-Z0-9\.]+(?:[\s]?[*+\^\/\%\-]{1}[\s]?[_a-zA-Z0-9\.]+)+ # Various math expressions left and right sides with any spaces
|(?R) # Other expressions inside
)+
} # End of shorthand syntax
)/x';
/**
* @param RenderingContextInterface $renderingContext
* @param string $expression
* @param array $matches
* @return integer|float
*/
public static function evaluateExpression(RenderingContextInterface $renderingContext, $expression, array $matches)
{
// Split the expression on all recognized operators
$matches = [];
preg_match_all('/([+\-*\^\/\%]|[_a-zA-Z0-9\.]+)/s', $expression, $matches);
$matches[0] = array_map('trim', $matches[0]);
// Like the BooleanNode, we dumb down the processing logic to not apply
// any special precedence on the priority of operators. We simply process
// them in order.
$result = array_shift($matches[0]);
$result = static::getTemplateVariableOrValueItself($result, $renderingContext);
$operator = null;
$operators = ['*', '^', '-', '+', '/', '%'];
foreach ($matches[0] as $part) {
if (in_array($part, $operators)) {
$operator = $part;
} else {
$part = static::getTemplateVariableOrValueItself($part, $renderingContext);
$result = self::evaluateOperation($result, $operator, $part);
}
}
return $result;
}
/**
* @param integer|float $left
* @param string $operator
* @param integer|float $right
* @return integer|float
*/
protected static function evaluateOperation($left, $operator, $right)
{
if ($operator === '%') {
return $left % $right;
} elseif ($operator === '-') {
return $left - $right;
} elseif ($operator === '+') {
return $left + $right;
} elseif ($operator === '*') {
return $left * $right;
} elseif ($operator === '/') {
return (integer) $right !== 0 ? $left / $right : 0;
} elseif ($operator === '^') {
return pow($left, $right);
}
return 0;
}
}