-
-
Notifications
You must be signed in to change notification settings - Fork 163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added DNF type support #505
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?php | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End of line character is invalid; expected |
||
|
||
namespace Go\Aop\Pointcut\DNF\AST; | ||
|
||
readonly class Node | ||
{ | ||
public function __construct( | ||
public NodeType $type, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line indented incorrectly; expected 4 spaces, found 8 |
||
public ?string $identifier = null, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line indented incorrectly; expected 4 spaces, found 8 |
||
public ?Node $left = null, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line indented incorrectly; expected 4 spaces, found 8 |
||
public ?Node $right = null, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line indented incorrectly; expected 4 spaces, found 8 |
||
) { | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End of line character is invalid; expected |
||
|
||
namespace Go\Aop\Pointcut\DNF\AST; | ||
|
||
enum NodeType | ||
{ | ||
case IDENTIFIER; | ||
case AND; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
case OR; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?php | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End of line character is invalid; expected |
||
|
||
namespace Go\Aop\Pointcut\DNF\Parser; | ||
|
||
enum Token | ||
{ | ||
case EOF; | ||
case IDENTIFIER; | ||
case LPAREN; | ||
case RPAREN; | ||
case AND; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
case OR; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<?php | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End of line character is invalid; expected |
||
|
||
namespace Go\Aop\Pointcut\DNF\Parser; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There must be one blank line after the namespace declaration |
||
class TokenCollection implements TokenCollectionInterface | ||
{ | ||
/** | ||
* @param \ArrayIterator<\PhpToken> $tokens | ||
*/ | ||
public function __construct( | ||
private readonly \ArrayIterator $tokens | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line indented incorrectly; expected 4 spaces, found 8 |
||
) { | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public function expect(Token $token): void | ||
{ | ||
/** @var Token $nextToken */ | ||
[$nextToken] = $this->next(); | ||
|
||
if ($nextToken !== $token) { | ||
throw new \Exception(sprintf('Expected %s, but got %s', $token->name, $nextToken->name)); | ||
} | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public function next(): array | ||
{ | ||
if (! $this->tokens->valid()) { | ||
return [Token::EOF, null]; | ||
} | ||
|
||
$val = trim($this->tokens->current()->text); | ||
|
||
if ($val === '') { | ||
return $this->next(); | ||
} | ||
|
||
$return = [$this->getToken($val), $val]; | ||
$this->tokens->next(); | ||
|
||
return $return; | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public function peek(int $i): array | ||
{ | ||
$offset = $this->tokens->key() + $i; | ||
if (! $this->tokens->offsetExists($offset)) { | ||
return [Token::EOF, null]; | ||
} | ||
|
||
$val = trim($this->tokens->offsetGet($offset)->text); | ||
|
||
return [$this->getToken($val), $val]; | ||
} | ||
|
||
private function getToken(string $val): Token | ||
{ | ||
return match ($val) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space before opening parenthesis of function call prohibited |
||
chr(26) => Token::EOF, | ||
'(' => Token::LPAREN, | ||
')' => Token::RPAREN, | ||
'|' => Token::OR, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
'&' => Token::AND, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
default => Token::IDENTIFIER | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line indented incorrectly; expected 8 spaces, found 12 |
||
}; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End of line character is invalid; expected |
||
|
||
namespace Go\Aop\Pointcut\DNF\Parser; | ||
|
||
interface TokenCollectionInterface | ||
{ | ||
/** | ||
* @throws \Exception | ||
*/ | ||
public function expect(Token $token): void; | ||
|
||
/** | ||
* @return array{0: Token, 1: string|null} | ||
*/ | ||
public function next(): array; | ||
|
||
/** | ||
* @return array{0: Token, 1: string|null} | ||
*/ | ||
public function peek(int $i): array; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected 1 newline at end of file; 0 found |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
<?php | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End of line character is invalid; expected |
||
|
||
namespace Go\Aop\Pointcut\DNF\Parser; | ||
|
||
use Exception; | ||
use Go\Aop\Pointcut\DNF\AST\Node; | ||
use Go\Aop\Pointcut\DNF\AST\NodeType; | ||
use PhpToken; | ||
|
||
class TokenizerParser implements TokenizerParserInterface | ||
{ | ||
public function parse(string $input): Node | ||
{ | ||
return $this->parseExpression($this->tokenize($input)); | ||
} | ||
|
||
private function tokenize(string $input): TokenCollection | ||
{ | ||
$input = sprintf('<?php %s%s', $input, chr(/* EOF */26)); | ||
$tokens = new \ArrayIterator(PhpToken::tokenize($input)); | ||
$arrayIntersect = array_intersect( | ||
(array)$tokens, | ||
['string', 'bool', 'array', 'float', 'int', 'integer', 'null', 'resource'] | ||
); | ||
if ($arrayIntersect !== []) { | ||
throw new Exception(sprintf('Tokens [%s] not allowed', implode(', ', $arrayIntersect))); | ||
} | ||
|
||
$tokens = new TokenCollection($tokens); | ||
//skip '<?php' | ||
$tokens->next(); | ||
|
||
return $tokens; | ||
} | ||
|
||
private function parseSubExpression( | ||
TokenCollection $tokens, | ||
int $bindingPower, | ||
bool $insideParenthesis = false | ||
): ?Node { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found 0 spaces |
||
[$token, $val] = $tokens->next(); | ||
switch ($token) { | ||
case Token::LPAREN: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CASE statements must be defined using a colon |
||
$left = $this->parseSubexpression($tokens, 0, true); | ||
$tokens->expect(Token::RPAREN); | ||
break; | ||
case Token::IDENTIFIER: | ||
$left = new Node(NodeType::IDENTIFIER, $val); | ||
break; | ||
default: | ||
throw new Exception('Bad Token'); | ||
} | ||
|
||
while (true) { | ||
[$token] = $tokens->peek(0); | ||
|
||
if ($token === Token::OR && $insideParenthesis) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
throw new \Exception('Only intersections allowed in the group'); | ||
} | ||
|
||
switch ($token) { | ||
case Token::OR: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
case Token::AND: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
[$leftBP, $rightBP] = $this->getBindingPower($token); | ||
if ($leftBP < $bindingPower) { | ||
break 2; | ||
} | ||
$tokens->next(); | ||
$right = $this->parseSubexpression($tokens, $rightBP, $insideParenthesis); | ||
$left = $this->operatorNode($token, $left, $right); | ||
break; | ||
case Token::RPAREN: | ||
case Token::EOF: | ||
default: | ||
break 2; | ||
} | ||
} | ||
|
||
return $left; | ||
} | ||
|
||
private function parseExpression(TokenCollection $tokens): ?Node | ||
{ | ||
$sub = $this->parseSubExpression($tokens, 0); | ||
$tokens->expect(Token::EOF); | ||
|
||
return $sub; | ||
} | ||
|
||
private function operatorNode(Token $type, Node $left, ?Node $right): Node | ||
{ | ||
return match ($type) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space before opening parenthesis of function call prohibited |
||
Token::OR => new Node(NodeType::OR, left: $left, right: $right), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
Token::AND => new Node(NodeType::AND, left: $left, right: $right), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
default => throw new Exception('invalid op') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line indented incorrectly; expected 8 spaces, found 12 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line indented incorrectly; expected 8 spaces, found 12 |
||
}; | ||
} | ||
|
||
/** | ||
* @param Token $type | ||
* | ||
* @return array{0: int, 1: int} | ||
*/ | ||
private function getBindingPower(Token $type): array | ||
{ | ||
return match ($type) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space before opening parenthesis of function call prohibited There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space before opening parenthesis of function call prohibited |
||
Token::OR => [1, 2], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
Token::AND => [3, 4], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
default => throw new Exception('Invalid operator') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line indented incorrectly; expected 8 spaces, found 12 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line indented incorrectly; expected 8 spaces, found 12 |
||
}; | ||
} | ||
|
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?php | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End of line character is invalid; expected There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End of line character is invalid; expected |
||
|
||
namespace Go\Aop\Pointcut\DNF\Parser; | ||
|
||
interface TokenizerParserInterface | ||
{ | ||
public function parse(string $input); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected 1 newline at end of file; 0 found There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected 1 newline at end of file; 0 found |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<?php | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End of line character is invalid; expected There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End of line character is invalid; expected |
||
|
||
namespace Go\Aop\Pointcut\DNF; | ||
|
||
use Go\Aop\Pointcut\DNF\AST\Node; | ||
use Go\Aop\Pointcut\DNF\AST\NodeType; | ||
use Go\ParserReflection\ReflectionFileNamespace; | ||
|
||
class SemanticAnalyzer implements SemanticAnalyzerInterface | ||
{ | ||
public function verifyTree(?Node $tree, \ReflectionClass|ReflectionFileNamespace $val) | ||
{ | ||
if ($tree !== null && $tree->type === NodeType::IDENTIFIER && $tree->identifier !== null) { | ||
$parentClasses = $this->getParentClasses($val); | ||
|
||
return in_array($tree->identifier, $parentClasses, true) | ||
|| $val->implementsInterface($tree->identifier); | ||
} | ||
|
||
if ($tree?->type === NodeType::AND) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
return $this->verifyTree($tree->left, $val) && $this->verifyTree($tree->right, $val); | ||
} | ||
|
||
if ($tree->type === NodeType::OR) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP keywords must be lowercase; expected |
||
return $this->verifyTree($tree->left, $val) || $this->verifyTree($tree->right, $val); | ||
} | ||
} | ||
|
||
/** | ||
* @param ReflectionFileNamespace|\ReflectionClass $val | ||
* | ||
* @return array | ||
*/ | ||
public function getParentClasses(ReflectionFileNamespace|\ReflectionClass $val): array | ||
{ | ||
$parentClasses = []; | ||
while ($val->getParentClass()) { | ||
$parentClasses[] = $val->getParentClass()->getName(); | ||
$val = $val->getParentClass(); | ||
} | ||
|
||
return $parentClasses; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected 1 newline at end of file; 0 found |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space before opening parenthesis of function call prohibited