silverstripe-framework/src/Core/Manifest/TokenisedRegularExpression.php
2017-02-20 22:19:33 +00:00

126 lines
4.5 KiB
PHP

<?php
namespace SilverStripe\Core\Manifest;
/**
* A tokenised regular expression is a parser, similar to a regular expression, that acts on tokens rather than
* characters. This is a crucial component of the ManifestBuilder.
*/
class TokenisedRegularExpression
{
/**
* The regular expression definition
*/
protected $expression;
/**
* The first expression to match
*/
protected $firstMatch;
public function __construct($expression)
{
$this->expression = $expression;
$this->firstMatch = is_array($expression[0]) ? $expression[0][0] : $expression[0];
}
public function findAll($tokens)
{
$tokenTypes = array();
foreach ($tokens as $i => $token) {
if (is_array($token)) {
$tokenType = $token[0];
} else {
$tokenType = $token;
// Pre-process string tokens for matchFrom()
$tokens[$i] = array($token, $token);
}
if ($tokenType == $this->firstMatch) {
$tokenTypes[$i] = $tokenType;
}
}
$allMatches = array();
foreach ($tokenTypes as $startKey => $dud) {
$matches = array();
if ($this->matchFrom($startKey, 0, $tokens, $matches)) {
$allMatches[] = $matches;
}
}
return $allMatches;
}
public function matchFrom($tokenPos, $expressionPos, &$tokens, &$matches)
{
$expressionRule = $this->expression[$expressionPos];
$expectation = is_array($expressionRule) ? $expressionRule[0] : $expressionRule;
if (!is_array($expressionRule)) {
$expressionRule = array();
}
if ($expectation == $tokens[$tokenPos][0]) {
if (isset($expressionRule['save_to'])) {
// Append to an array
if (substr($expressionRule['save_to'], -2) == '[]') {
$matches[substr($expressionRule['save_to'], 0, -2)][] = $tokens[$tokenPos][1];
} // Regular variable setting
else {
$matches[$expressionRule['save_to']] = $tokens[$tokenPos][1];
}
}
// End of the expression
if (!isset($this->expression[$expressionPos+1])) {
return true;
// Process next step as normal
} elseif ($this->matchFrom($tokenPos+1, $expressionPos+1, $tokens, $matches)) {
return true;
// This step is optional
} elseif (isset($expressionRule['optional'])
&& $this->matchFrom($tokenPos, $expressionPos+1, $tokens, $matches)) {
return true;
// Process jumps
} elseif (isset($expressionRule['can_jump_to'])) {
if (is_array($expressionRule['can_jump_to'])) {
foreach ($expressionRule['can_jump_to'] as $canJumpTo) {
// can_jump_to & optional both set
if (isset($expressionRule['optional'])
&& $this->matchFrom($tokenPos, $canJumpTo, $tokens, $matches)) {
return true;
}
// can_jump_to set (optional may or may not be set)
if ($this->matchFrom($tokenPos+1, $canJumpTo, $tokens, $matches)) {
return true;
}
}
} else {
// can_jump_to & optional both set
if (isset($expressionRule['optional'])
&& $this->matchFrom($tokenPos, $expressionRule['can_jump_to'], $tokens, $matches)) {
return true;
}
// can_jump_to set (optional may or may not be set)
if ($this->matchFrom($tokenPos+1, $expressionRule['can_jump_to'], $tokens, $matches)) {
return true;
}
}
}
} elseif (isset($expressionRule['optional'])) {
if (isset($this->expression[$expressionPos+1])) {
return $this->matchFrom($tokenPos, $expressionPos+1, $tokens, $matches);
} else {
return true;
}
} elseif (in_array($tokens[$tokenPos][0], array(T_COMMENT, T_DOC_COMMENT, T_WHITESPACE))) {
return $this->matchFrom($tokenPos + 1, $expressionPos, $tokens, $matches);
}
return false;
}
}