Fixed comma operator

Added unit tests for expressions in function arguments.
Changed array_push to $var[] = native code.
This commit is contained in:
Bruce Wells 2019-01-15 20:04:16 -05:00
parent 265cff175e
commit 47df3edbb6
5 changed files with 73 additions and 29 deletions

View file

@ -36,21 +36,17 @@ class Calculator
{ {
$stack = []; $stack = [];
foreach ($tokens as $token) { foreach ($tokens as $token) {
if ($token instanceof TokenNumber) { if ($token instanceof TokenNumber || $token instanceof TokenStringDoubleQuoted || $token instanceof TokenStringSingleQuoted) {
array_push($stack, $token); $stack[] = $token;
} else if ($token instanceof TokenStringDoubleQuoted) {
array_push($stack, $token);
} else if ($token instanceof TokenStringSingleQuoted) {
array_push($stack, $token);
} else if ($token instanceof TokenVariable) { } else if ($token instanceof TokenVariable) {
$variable = $token->getValue(); $variable = $token->getValue();
if (!array_key_exists($variable, $variables)) { if (!array_key_exists($variable, $variables)) {
throw new UnknownVariableException($variable); throw new UnknownVariableException($variable);
} }
$value = $variables[$variable]; $value = $variables[$variable];
array_push($stack, new TokenNumber($value)); $stack[] = new TokenNumber($value);
} else if ($token instanceof InterfaceOperator || $token instanceof TokenFunction) { } else if ($token instanceof InterfaceOperator || $token instanceof TokenFunction) {
array_push($stack, $token->execute($stack)); $stack[] = $token->execute($stack);
} }
} }
$result = array_pop($stack); $result = array_pop($stack);

View file

@ -77,7 +77,7 @@ class Lexer
} elseif ($token instanceof TokenVariable) { } elseif ($token instanceof TokenVariable) {
$output[] = $token; $output[] = $token;
} elseif ($token instanceof TokenFunction) { } elseif ($token instanceof TokenFunction) {
array_push($stack, $token); $stack[] = $token;
} elseif ($token instanceof AbstractOperator) { } elseif ($token instanceof AbstractOperator) {
// While we have something on the stack // While we have something on the stack
while (($count = count($stack)) > 0 while (($count = count($stack)) > 0
@ -104,9 +104,12 @@ class Lexer
$output[] = array_pop($stack); $output[] = array_pop($stack);
} }
array_push($stack, $token); // Comma operators do nothing really, don't put them on the stack
if (! ($token instanceof TokenComma)) {
$stack[] = $token;
}
} elseif ($token instanceof TokenLeftBracket) { } elseif ($token instanceof TokenLeftBracket) {
array_push($stack, $token); $stack[] = $token;
} elseif ($token instanceof TokenRightBracket) { } elseif ($token instanceof TokenRightBracket) {
while (($current = array_pop($stack)) && (!($current instanceof TokenLeftBracket))) { while (($current = array_pop($stack)) && (!($current instanceof TokenLeftBracket))) {
$output[] = $current; $output[] = $current;

View file

@ -13,7 +13,7 @@ namespace NXP\Classes\Token;
/** /**
* @author Alexander Kiryukhin <a.kiryukhin@mail.ru> * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
*/ */
class TokenComma implements InterfaceToken class TokenComma extends AbstractOperator
{ {
/** /**
* @return string * @return string
@ -22,4 +22,32 @@ class TokenComma implements InterfaceToken
{ {
return '\,'; return '\,';
} }
/**
* Comma operator is lowest priority
*
* @return int
*/
public function getPriority()
{
return 0;
}
/**
* @return string
*/
public function getAssociation()
{
return self::RIGHT_RIGHT;
}
/**
* @param array $stack
* @return TokenNumber
*/
public function execute(&$stack)
{
// Comma operators don't do anything, stack has already executed
}
} }

View file

@ -32,9 +32,10 @@ class TokenFunction extends AbstractContainerToken implements InterfaceFunction
$args = []; $args = [];
list($places, $function) = $this->value; list($places, $function) = $this->value;
for ($i = 0; $i < $places; $i++) { for ($i = 0; $i < $places; $i++) {
$args[] = array_pop($stack)->getValue(); array_unshift($args, array_pop($stack)->getValue());
} }
$result = call_user_func_array($function, array_reverse($args));
$result = call_user_func_array($function, $args);
return new TokenNumber($result); return new TokenNumber($result);
} }

View file

@ -154,6 +154,22 @@ class MathTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(round(100/30), $calculator->execute('round(100/30)')); $this->assertEquals(round(100/30), $calculator->execute('round(100/30)'));
} }
public function testEvaluateFunctionParameters()
{
$calculator = new MathExecutor();
$calculator->addFunction('round', function ($value, $decimals)
{
return round($value, $decimals);
}
);
$expression = 'round(100 * 1.111111, 2)';
eval('$phpResult = ' . $expression . ';');
$this->assertEquals($phpResult, $calculator->execute($expression));
$expression = 'round((100*0.04)+(((100*1.02)+0.5)*1.28),2)';
eval('$phpResult = ' . $expression . ';');
$this->assertEquals($phpResult, $calculator->execute($expression));
}
public function testQuotes() public function testQuotes()
{ {
$calculator = new MathExecutor(); $calculator = new MathExecutor();