Adam Pippin
3 years ago
6 changed files with 0 additions and 509 deletions
@ -1,61 +0,0 @@ |
|||
<?php |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Cfnpp\Expression; |
|||
|
|||
/** |
|||
* Parse a string into a series of expression tokens. |
|||
* |
|||
* @author Adam Pippin <hello@adampippin.ca> |
|||
*/ |
|||
class Parser |
|||
{ |
|||
/** |
|||
* List of class names of tokens this parser will parse. |
|||
* |
|||
* @var string[] |
|||
*/ |
|||
public const TOKEN_TYPES = [ |
|||
TokenFunction::class, |
|||
TokenNumericLiteral::class, |
|||
TokenOperator::class, |
|||
TokenStringLiteral::class, |
|||
TokenVariable::class |
|||
]; |
|||
|
|||
/** |
|||
* Parse a string into an expression. |
|||
* |
|||
* @param string $value |
|||
* @return Expression |
|||
*/ |
|||
public function parse(string $value): Expression |
|||
{ |
|||
$original_value = $value; |
|||
$value .= ' '; |
|||
$tokens = []; |
|||
while (strlen($value) > 0) |
|||
{ |
|||
foreach (static::TOKEN_TYPES as $token_class) |
|||
{ |
|||
if ($token_class::isToken($value)) |
|||
{ |
|||
$tokens[] = $token_class::getToken($value); |
|||
|
|||
if (substr($value, 0, 1) != ' ') |
|||
{ |
|||
throw new \Exception('Incompletely consumed token at offset '.(strlen($original_value) - strlen($value)).' in expression '.$original_value); |
|||
} |
|||
|
|||
$value = substr($value, 1); |
|||
continue 2; |
|||
} |
|||
} |
|||
|
|||
throw new \Exception('Unparseable value at offset '.(strlen($original_value) - strlen($value)).' in expression '.$original_value); |
|||
} |
|||
|
|||
return new Expression($tokens); |
|||
} |
|||
} |
@ -1,90 +0,0 @@ |
|||
<?php |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Cfnpp\Expression; |
|||
|
|||
/** |
|||
* Token representing a function. |
|||
* |
|||
* @author Adam Pippin <hello@adampippin.ca> |
|||
*/ |
|||
class TokenFunction extends Token |
|||
{ |
|||
/** |
|||
* List of valid functions this can parse. |
|||
* @var string[] |
|||
*/ |
|||
public const FUNCTIONS = [ |
|||
'concat*', |
|||
'concat' |
|||
]; |
|||
|
|||
/** |
|||
* Function this token represents. |
|||
* @var string |
|||
*/ |
|||
protected $function; |
|||
|
|||
/** |
|||
* Create a new function token. |
|||
* |
|||
* @param string $function |
|||
*/ |
|||
public function __construct($function) |
|||
{ |
|||
$this->function = $function; |
|||
} |
|||
|
|||
/** |
|||
* Get the function this token represents. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function getFunction(): string |
|||
{ |
|||
return $this->function; |
|||
} |
|||
|
|||
/** |
|||
* Determine whether a function token can be parsed from a stream. |
|||
* |
|||
* @param string $stream |
|||
* @return bool |
|||
*/ |
|||
public static function isToken(string $stream): bool |
|||
{ |
|||
foreach (static::FUNCTIONS as $function) |
|||
{ |
|||
if (strlen($stream) > strlen($function) && |
|||
substr($stream, 0, strlen($function)) == $function) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Parse a function token from a stream. |
|||
* |
|||
* Returns token, and modifies stream to remove all consumed characters |
|||
* |
|||
* @param string $stream |
|||
* @return Token |
|||
*/ |
|||
public static function getToken(string &$stream): Token |
|||
{ |
|||
foreach (static::FUNCTIONS as $function) |
|||
{ |
|||
if (strlen($stream) > strlen($function) && |
|||
substr($stream, 0, strlen($function)) == $function) |
|||
{ |
|||
$function = substr($stream, 0, strlen($function)); |
|||
$stream = substr($stream, strlen($function)); |
|||
return new TokenFunction($function); |
|||
} |
|||
} |
|||
throw new \Exception('Could not parse function token!'); |
|||
} |
|||
} |
@ -1,87 +0,0 @@ |
|||
<?php |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Cfnpp\Expression; |
|||
|
|||
/** |
|||
* Token representing a numeric (integer or float) literal. |
|||
* |
|||
* @author Adam Pippin <hello@adampippin.ca> |
|||
*/ |
|||
class TokenNumericLiteral extends Token |
|||
{ |
|||
/** |
|||
* Numeric value this token represents. |
|||
* @var int|float |
|||
*/ |
|||
protected $value; |
|||
|
|||
/** |
|||
* Create a new numeric literal. |
|||
* |
|||
* @param int|float $value |
|||
*/ |
|||
public function __construct($value) |
|||
{ |
|||
$this->value = $value; |
|||
} |
|||
|
|||
/** |
|||
* Get the value this token represents. |
|||
* |
|||
* @return int|float |
|||
*/ |
|||
public function getValue() |
|||
{ |
|||
return $this->value; |
|||
} |
|||
|
|||
/** |
|||
* Determine whether a numeric token can be parsed from a stream. |
|||
* |
|||
* @param string $stream |
|||
* @return bool |
|||
*/ |
|||
public static function isToken(string $stream): bool |
|||
{ |
|||
return is_numeric($stream[0]); |
|||
} |
|||
|
|||
/** |
|||
* Parse a numeric token from a stream. |
|||
* |
|||
* Returns token, and modifies stream to remove all consumed characters. |
|||
* |
|||
* @param string $stream |
|||
* @return Token |
|||
*/ |
|||
public static function getToken(string &$stream): Token |
|||
{ |
|||
$buffer = ''; |
|||
for ($i = 0; $i < strlen($stream); $i++) |
|||
{ |
|||
if (preg_match('/^[0-9]$/', $stream[$i])) |
|||
{ |
|||
$buffer .= $stream[$i]; |
|||
} |
|||
else |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
|
|||
$stream = substr($stream, strlen($buffer)); |
|||
|
|||
if (stristr($buffer, '.')) |
|||
{ |
|||
$buffer = (float)$buffer; |
|||
} |
|||
else |
|||
{ |
|||
$buffer = (int)$buffer; |
|||
} |
|||
|
|||
return new TokenNumericLiteral($buffer); |
|||
} |
|||
} |
@ -1,97 +0,0 @@ |
|||
<?php |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Cfnpp\Expression; |
|||
|
|||
/** |
|||
* Token representing a comparison operator. |
|||
* |
|||
* @author Adam Pippin <hello@adampippin.ca> |
|||
*/ |
|||
class TokenOperator extends Token |
|||
{ |
|||
/** |
|||
* List of valid operators this can parse. |
|||
* @var string[] |
|||
*/ |
|||
public const OPERATORS = [ |
|||
'eq', |
|||
'neq', |
|||
'gt', |
|||
'gte', |
|||
'lt', |
|||
'lte', |
|||
'and', |
|||
'or', |
|||
'not' |
|||
]; |
|||
|
|||
/** |
|||
* Operator this token represents. |
|||
* @var string |
|||
*/ |
|||
protected $operator; |
|||
|
|||
/** |
|||
* Create a new operator token. |
|||
* |
|||
* @param string $operator |
|||
*/ |
|||
public function __construct($operator) |
|||
{ |
|||
$this->operator = $operator; |
|||
} |
|||
|
|||
/** |
|||
* Get the operator this token represents. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function getOperator(): string |
|||
{ |
|||
return $this->operator; |
|||
} |
|||
|
|||
/** |
|||
* Determine whether a operator token can be parsed from a stream. |
|||
* |
|||
* @param string $stream |
|||
* @return bool |
|||
*/ |
|||
public static function isToken(string $stream): bool |
|||
{ |
|||
foreach (static::OPERATORS as $operator) |
|||
{ |
|||
if (strlen($stream) > strlen($operator) && |
|||
substr($stream, 0, strlen($operator)) == $operator) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Parse an operator token from a stream. |
|||
* |
|||
* Returns token, and modifies stream to remove all consumed characters |
|||
* |
|||
* @param string $stream |
|||
* @return Token |
|||
*/ |
|||
public static function getToken(string &$stream): Token |
|||
{ |
|||
foreach (static::OPERATORS as $operator) |
|||
{ |
|||
if (strlen($stream) > strlen($operator) && |
|||
substr($stream, 0, strlen($operator)) == $operator) |
|||
{ |
|||
$operator = substr($stream, 0, strlen($operator)); |
|||
$stream = substr($stream, strlen($operator)); |
|||
return new TokenOperator($operator); |
|||
} |
|||
} |
|||
throw new \Exception('Could not parse operator token!'); |
|||
} |
|||
} |
@ -1,95 +0,0 @@ |
|||
<?php |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Cfnpp\Expression; |
|||
|
|||
/** |
|||
* Token representing a string literal. |
|||
* |
|||
* @author Adam Pippin <hello@adampippin.ca> |
|||
*/ |
|||
class TokenStringLiteral extends Token |
|||
{ |
|||
/** |
|||
* Value of the string literal. |
|||
* @var string |
|||
*/ |
|||
protected $value; |
|||
|
|||
/** |
|||
* Create a new string literal token. |
|||
* |
|||
* @param string $value |
|||
*/ |
|||
public function __construct(string $value) |
|||
{ |
|||
$this->value = $value; |
|||
} |
|||
|
|||
/** |
|||
* Get the value of the string literal. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function getValue(): string |
|||
{ |
|||
return $this->value; |
|||
} |
|||
|
|||
/** |
|||
* Determine whether a string token can be parsed from a stream. |
|||
* |
|||
* @param string $stream |
|||
* @return bool |
|||
*/ |
|||
public static function isToken(string $stream): bool |
|||
{ |
|||
return $stream[0] == '"'; |
|||
} |
|||
|
|||
/** |
|||
* Parse a string literal token from a stream. |
|||
* |
|||
* Returns token, and modifies stream to remove all consumed characters |
|||
* |
|||
* @param string $stream |
|||
* @return Token |
|||
*/ |
|||
public static function getToken(string &$stream): Token |
|||
{ |
|||
$buffer = ''; |
|||
$in_string = false; |
|||
$escaped = false; |
|||
|
|||
for ($i = 0; $i < strlen($stream); $i++) |
|||
{ |
|||
if ($escaped) |
|||
{ |
|||
$buffer .= $stream[$i]; |
|||
$escaped = false; |
|||
} |
|||
elseif ($stream[$i] == '"') |
|||
{ |
|||
if ($in_string) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
$in_string = true; |
|||
} |
|||
elseif ($stream[$i] == '\\') |
|||
{ |
|||
$escaped = true; |
|||
} |
|||
else |
|||
{ |
|||
$buffer .= $stream[$i]; |
|||
} |
|||
} |
|||
|
|||
$stream = substr($stream, $i + 1); |
|||
|
|||
return new TokenStringLiteral($buffer); |
|||
} |
|||
} |
@ -1,79 +0,0 @@ |
|||
<?php |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Cfnpp\Expression; |
|||
|
|||
/** |
|||
* Expression token referencing a variable. |
|||
* |
|||
* @author Adam Pippin <hello@adampippin.ca> |
|||
*/ |
|||
class TokenVariable extends Token |
|||
{ |
|||
/** |
|||
* Name of the variable this token references. |
|||
* @var string |
|||
*/ |
|||
protected $name; |
|||
|
|||
/** |
|||
* Create a new variable token. |
|||
* |
|||
* @param string $name |
|||
*/ |
|||
public function __construct(string $name) |
|||
{ |
|||
$this->name = $name; |
|||
} |
|||
|
|||
/** |
|||
* Get the name of the variable this token references. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function getName(): string |
|||
{ |
|||
return $this->name; |
|||
} |
|||
|
|||
/** |
|||
* Determine whether a variable name token can be parsed from a stream. |
|||
* |
|||
* @param string $stream |
|||
* @return bool |
|||
*/ |
|||
public static function isToken(string $stream): bool |
|||
{ |
|||
return (bool)preg_match('/^[A-Za-z]$/', $stream[0]); |
|||
} |
|||
|
|||
/** |
|||
* Parse a variable token from a stream. |
|||
* |
|||
* Returns token, and modifies stream to remove all consumed characters. |
|||
* |
|||
* @param string $stream |
|||
* @return Token |
|||
*/ |
|||
public static function getToken(string &$stream): Token |
|||
{ |
|||
$buffer = ''; |
|||
$buffer = $stream[0]; |
|||
for ($i = 1; $i < strlen($stream); $i++) |
|||
{ |
|||
if (preg_match('/^[A-Za-z0-9]$/', $stream[$i])) |
|||
{ |
|||
$buffer .= $stream[$i]; |
|||
} |
|||
else |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
|
|||
$stream = substr($stream, strlen($buffer)); |
|||
|
|||
return new TokenVariable($buffer); |
|||
} |
|||
} |
Loading…
Reference in new issue