Skip to content

Commit

Permalink
Unary Minus (#84)
Browse files Browse the repository at this point in the history
Fixed unary minus to allow a minus sign in front of functions and parentheses.
  • Loading branch information
phpfui authored Feb 17, 2021
1 parent 936ee5c commit 17cc5b9
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 31 deletions.
70 changes: 39 additions & 31 deletions src/NXP/Classes/Tokenizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ class Tokenizer
/**
* @var string
*/
private $input = "";
private $input = '';
/**
* @var string
*/
private $numberBuffer = "";
private $numberBuffer = '';
/**
* @var string
*/
private $stringBuffer = "";
private $stringBuffer = '';
/**
* @var bool
*/
Expand Down Expand Up @@ -74,48 +74,48 @@ public function tokenize() : self
if ($ch === "'") {
$this->tokens[] = new Token(Token::String, $this->stringBuffer);
$this->inSingleQuotedString = false;
$this->stringBuffer = "";
$this->stringBuffer = '';
continue 2;
}
$this->stringBuffer .= $ch;
continue 2;
case $this->inDoubleQuotedString:
if ($ch === "\"") {
if ($ch === '"') {
$this->tokens[] = new Token(Token::String, $this->stringBuffer);
$this->inDoubleQuotedString = false;
$this->stringBuffer = "";
$this->stringBuffer = '';
continue 2;
}
$this->stringBuffer .= $ch;
continue 2;
case $ch == " " || $ch == "\n" || $ch == "\r" || $ch == "\t":
$this->tokens[] = new Token(Token::Space, "");
case $ch == ' ' || $ch == "\n" || $ch == "\r" || $ch == "\t":
$this->tokens[] = new Token(Token::Space, '');
continue 2;
case $this->isNumber($ch):
if ($this->stringBuffer != "") {
if ($this->stringBuffer != '') {
$this->stringBuffer .= $ch;
continue 2;
}
$this->numberBuffer .= $ch;
$this->allowNegative = false;
break;
/** @noinspection PhpMissingBreakStatementInspection */
case strtolower($ch) === "e":
if ($this->numberBuffer != "" && strpos($this->numberBuffer, ".") !== false) {
$this->numberBuffer .= "e";
$this->allowNegative = true;
case strtolower($ch) === 'e':
if (strlen($this->numberBuffer) && strpos($this->numberBuffer, '.') !== false) {
$this->numberBuffer .= 'e';
$this->allowNegative = false;
break;
}
// no break
case $this->isAlpha($ch):
if ($this->numberBuffer != "") {
if (strlen($this->numberBuffer)) {
$this->emptyNumberBufferAsLiteral();
$this->tokens[] = new Token(Token::Operator, "*");
$this->tokens[] = new Token(Token::Operator, '*');
}
$this->allowNegative = false;
$this->stringBuffer .= $ch;
break;
case $ch == "\"":
case $ch == '"':
$this->inDoubleQuotedString = true;
continue 2;
case $ch == "'":
Expand All @@ -127,33 +127,41 @@ public function tokenize() : self
$this->allowNegative = false;
break;
case $this->isLP($ch):
if ($this->stringBuffer != "") {
if ($this->stringBuffer != '') {
$this->tokens[] = new Token(Token::Function, $this->stringBuffer);
$this->stringBuffer = "";
} elseif ($this->numberBuffer != "") {
$this->stringBuffer = '';
} elseif (strlen($this->numberBuffer)) {
$this->emptyNumberBufferAsLiteral();
$this->tokens[] = new Token(Token::Operator, "*");
$this->tokens[] = new Token(Token::Operator, '*');
}
$this->allowNegative = true;
$this->tokens[] = new Token(Token::LeftParenthesis, "");
$this->tokens[] = new Token(Token::LeftParenthesis, '');
break;
case $this->isRP($ch):
$this->emptyNumberBufferAsLiteral();
$this->emptyStrBufferAsVariable();
$this->allowNegative = false;
$this->tokens[] = new Token(Token::RightParenthesis, "");
$this->tokens[] = new Token(Token::RightParenthesis, '');
break;
case $this->isComma($ch):
$this->emptyNumberBufferAsLiteral();
$this->emptyStrBufferAsVariable();
$this->allowNegative = true;
$this->tokens[] = new Token(Token::ParamSeparator, "");
$this->tokens[] = new Token(Token::ParamSeparator, '');
break;
default:
if ($this->allowNegative && $ch == "-") {
$this->allowNegative = false;
$this->numberBuffer .= "-";
continue 2;
// special case for unary minus
if ($ch == '-') {
if ($this->allowNegative) {
$this->allowNegative = false;
$this->tokens[] = new Token(Token::Operator, '`');
continue 2;
}
// could be in exponent, in which case negative should be added to the numberBuffer
if ($this->numberBuffer && $this->numberBuffer[strlen($this->numberBuffer) - 1] == 'e') {
$this->numberBuffer .= '-';
continue 2;
}
}
$this->emptyNumberBufferAsLiteral();
$this->emptyStrBufferAsVariable();
Expand Down Expand Up @@ -188,9 +196,9 @@ private function isAlpha(string $ch) : bool

private function emptyNumberBufferAsLiteral() : void
{
if ($this->numberBuffer != "") {
if (strlen($this->numberBuffer)) {
$this->tokens[] = new Token(Token::Literal, $this->numberBuffer);
$this->numberBuffer = "";
$this->numberBuffer = '';
}
}

Expand All @@ -211,9 +219,9 @@ private function isRP(string $ch) : bool

private function emptyStrBufferAsVariable() : void
{
if ($this->stringBuffer != "") {
if ($this->stringBuffer != '') {
$this->tokens[] = new Token(Token::Variable, $this->stringBuffer);
$this->stringBuffer = "";
$this->stringBuffer = '';
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/NXP/MathExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ function ($a, $b) {
170,
false
],
'`' => [ // unary minus token
function ($a) {
return 0 - $a;
},
200,
false
],
'*' => [
function ($a, $b) {
return $a * $b;
Expand Down
20 changes: 20 additions & 0 deletions tests/MathTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ public function providerExpressions()
['sin(10) * cos(50) / min(10, (20/2))'],
['sin(10) * cos(50) / min(10, (max(10,20)/2))'],

['100500 * 3.5e5'],
['100500 * 3.5e-5'],
['100500 * 3.5E5'],
['100500 * 3.5E-5'],

Expand Down Expand Up @@ -208,6 +210,24 @@ public function providerExpressions()
['1 + (3 *-1)'],
['1 - 0'],
['1-0'],

['-(1.5)'],
['-log(4)'],
['0-acosh(1.5)'],
['-acosh(1.5)'],
['-(-4)'],
['-(-4 + 5)'],
['-(3 * 1)'],
['-(-3 * -1)'],
['-1 + (-3 * -1)'],
['-1 + ( -3 * 1)'],
['-1 + (3 *-1)'],
['-1 - 0'],
['-1-0'],
['-(4*2)-5'],
['-(4*-2)-5'],
['-(-4*2) - 5'],
['-4*-5'],
];
}

Expand Down

0 comments on commit 17cc5b9

Please sign in to comment.