Skip to content
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

misc: replace regex-based type parser with character-based one #400

Merged
merged 1 commit into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use CuyZ\Valinor\Definition\PropertyDefinition;
use CuyZ\Valinor\Definition\Repository\AttributesRepository;
use CuyZ\Valinor\Definition\Repository\ClassDefinitionRepository;
use CuyZ\Valinor\Type\ClassType;
use CuyZ\Valinor\Type\GenericType;
use CuyZ\Valinor\Type\Parser\Exception\InvalidType;
use CuyZ\Valinor\Type\Parser\Factory\Specifications\AliasSpecification;
Expand All @@ -23,11 +24,11 @@
use CuyZ\Valinor\Type\Parser\Factory\TypeParserFactory;
use CuyZ\Valinor\Type\Parser\TypeParser;
use CuyZ\Valinor\Type\Type;
use CuyZ\Valinor\Type\ClassType;
use CuyZ\Valinor\Type\Types\UnresolvableType;
use CuyZ\Valinor\Utility\Reflection\Reflection;
use ReflectionMethod;
use ReflectionProperty;
use CuyZ\Valinor\Utility\Reflection\DocParser;

use function array_filter;
use function array_keys;
Expand Down Expand Up @@ -156,7 +157,7 @@ private function typeResolver(ClassType $type, string $targetClass): ReflectionT
private function localTypeAliases(ClassType $type): array
{
$reflection = Reflection::class($type->className());
$rawTypes = Reflection::localTypeAliases($reflection);
$rawTypes = DocParser::localTypeAliases($reflection);

$typeParser = $this->typeParser($type);

Expand All @@ -181,7 +182,7 @@ private function localTypeAliases(ClassType $type): array
private function importedTypeAliases(ClassType $type): array
{
$reflection = Reflection::class($type->className());
$importedTypesRaw = Reflection::importedTypeAliases($reflection);
$importedTypesRaw = DocParser::importedTypeAliases($reflection);

$typeParser = $this->typeParser($type);

Expand Down
28 changes: 21 additions & 7 deletions src/Definition/Repository/Reflection/ReflectionTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use CuyZ\Valinor\Type\Type;
use CuyZ\Valinor\Type\Types\MixedType;
use CuyZ\Valinor\Type\Types\UnresolvableType;
use CuyZ\Valinor\Utility\Reflection\DocParser;
use CuyZ\Valinor\Utility\Reflection\Reflection;
use ReflectionFunctionAbstract;
use ReflectionParameter;
Expand All @@ -23,7 +24,7 @@ public function __construct(
private TypeParser $advancedParser
) {}

public function resolveType(\ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection): Type
public function resolveType(ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection): Type
{
$nativeType = $this->nativeType($reflection);
$typeFromDocBlock = $this->typeFromDocBlock($reflection);
Expand Down Expand Up @@ -51,11 +52,24 @@ public function resolveType(\ReflectionProperty|\ReflectionParameter|\Reflection
return $typeFromDocBlock;
}

private function typeFromDocBlock(\ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection): ?Type
private function typeFromDocBlock(ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection): ?Type
{
$type = $reflection instanceof ReflectionFunctionAbstract
? Reflection::docBlockReturnType($reflection)
: Reflection::docBlockType($reflection);
if ($reflection instanceof ReflectionFunctionAbstract) {
$type = DocParser::functionReturnType($reflection);
} elseif ($reflection instanceof ReflectionProperty) {
$type = DocParser::propertyType($reflection);
} else {
$type = null;

if ($reflection->isPromoted()) {
// @phpstan-ignore-next-line / parameter is promoted so class exists for sure
$type = DocParser::propertyType($reflection->getDeclaringClass()->getProperty($reflection->name));
}

if ($type === null) {
$type = DocParser::parameterType($reflection);
}
}

if ($type === null) {
return null;
Expand All @@ -64,7 +78,7 @@ private function typeFromDocBlock(\ReflectionProperty|\ReflectionParameter|\Refl
return $this->parseType($type, $reflection, $this->advancedParser);
}

private function nativeType(\ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection): ?Type
private function nativeType(ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection): ?Type
{
$reflectionType = $reflection instanceof ReflectionFunctionAbstract
? $reflection->getReturnType()
Expand All @@ -83,7 +97,7 @@ private function nativeType(\ReflectionProperty|\ReflectionParameter|\Reflection
return $this->parseType($type, $reflection, $this->nativeParser);
}

private function parseType(string $raw, \ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection, TypeParser $parser): Type
private function parseType(string $raw, ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection, TypeParser $parser): Type
{
try {
return $parser->parse($raw);
Expand Down
8 changes: 1 addition & 7 deletions src/Library/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@
use CuyZ\Valinor\Type\ClassType;
use CuyZ\Valinor\Type\Parser\Factory\LexingTypeParserFactory;
use CuyZ\Valinor\Type\Parser\Factory\TypeParserFactory;
use CuyZ\Valinor\Type\Parser\Template\BasicTemplateParser;
use CuyZ\Valinor\Type\Parser\Template\TemplateParser;
use CuyZ\Valinor\Type\Parser\TypeParser;
use CuyZ\Valinor\Type\ScalarType;
use CuyZ\Valinor\Type\Types\ArrayType;
Expand Down Expand Up @@ -196,14 +194,10 @@ public function __construct(Settings $settings)

AttributesRepository::class => fn () => new NativeAttributesRepository(),

TypeParserFactory::class => fn () => new LexingTypeParserFactory(
$this->get(TemplateParser::class)
),
TypeParserFactory::class => fn () => new LexingTypeParserFactory(),

TypeParser::class => fn () => $this->get(TypeParserFactory::class)->get(),

TemplateParser::class => fn () => new BasicTemplateParser(),

RecursiveCacheWarmupService::class => fn () => new RecursiveCacheWarmupService(
$this->get(TypeParser::class),
$this->get(ObjectImplementations::class),
Expand Down
9 changes: 6 additions & 3 deletions src/Type/Parser/Exception/Template/DuplicatedTemplateName.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
use LogicException;

/** @internal */
final class DuplicatedTemplateName extends LogicException implements InvalidTemplate
final class DuplicatedTemplateName extends LogicException
{
public function __construct(string $template)
/**
* @param class-string $className
*/
public function __construct(string $className, string $template)
{
parent::__construct(
"The template `$template` was defined at least twice.",
"The template `$template` in class `$className` was defined at least twice.",
1604612898
);
}
Expand Down
7 changes: 4 additions & 3 deletions src/Type/Parser/Exception/Template/InvalidClassTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@

namespace CuyZ\Valinor\Type\Parser\Exception\Template;

use CuyZ\Valinor\Type\Parser\Exception\InvalidType;
use LogicException;

/** @internal */
final class InvalidClassTemplate extends LogicException implements InvalidTemplate
final class InvalidClassTemplate extends LogicException
{
/**
* @param class-string $className
*/
public function __construct(string $className, InvalidTemplate $exception)
public function __construct(string $className, string $template, InvalidType $exception)
{
parent::__construct(
"Template error for class `$className`: {$exception->getMessage()}",
"Invalid template `$template` for class `$className`: {$exception->getMessage()}",
1630092678,
$exception
);
Expand Down
10 changes: 0 additions & 10 deletions src/Type/Parser/Exception/Template/InvalidTemplate.php

This file was deleted.

21 changes: 0 additions & 21 deletions src/Type/Parser/Exception/Template/InvalidTemplateType.php

This file was deleted.

11 changes: 4 additions & 7 deletions src/Type/Parser/Factory/LexingTypeParserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,21 @@
use CuyZ\Valinor\Type\Parser\Lexer\AdvancedClassLexer;
use CuyZ\Valinor\Type\Parser\Lexer\NativeLexer;
use CuyZ\Valinor\Type\Parser\LexingParser;
use CuyZ\Valinor\Type\Parser\Template\TemplateParser;
use CuyZ\Valinor\Type\Parser\TypeParser;

/** @internal */
final class LexingTypeParserFactory implements TypeParserFactory
{
private TypeParser $nativeParser;

public function __construct(private TemplateParser $templateParser) {}

public function get(TypeParserSpecification ...$specifications): TypeParser
{
if (empty($specifications)) {
return $this->nativeParser ??= $this->nativeParser();
}

$lexer = new NativeLexer();
$lexer = new AdvancedClassLexer($lexer, $this, $this->templateParser);
$lexer = new AdvancedClassLexer($lexer, $this);

foreach ($specifications as $specification) {
$lexer = $specification->transform($lexer);
Expand All @@ -38,9 +35,9 @@ public function get(TypeParserSpecification ...$specifications): TypeParser
private function nativeParser(): TypeParser
{
$lexer = new NativeLexer();
$lexer = new AdvancedClassLexer($lexer, $this, $this->templateParser);
$lexer = new LexingParser($lexer);
$lexer = new AdvancedClassLexer($lexer, $this);
$parser = new LexingParser($lexer);

return new CachedParser($lexer);
return new CachedParser($parser);
}
}
31 changes: 0 additions & 31 deletions src/Type/Parser/LazyParser.php

This file was deleted.

4 changes: 1 addition & 3 deletions src/Type/Parser/Lexer/AdvancedClassLexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,21 @@
use CuyZ\Valinor\Type\Parser\Lexer\Token\ClassNameToken;
use CuyZ\Valinor\Type\Parser\Lexer\Token\AdvancedClassNameToken;
use CuyZ\Valinor\Type\Parser\Lexer\Token\Token;
use CuyZ\Valinor\Type\Parser\Template\TemplateParser;

/** @internal */
final class AdvancedClassLexer implements TypeLexer
{
public function __construct(
private TypeLexer $delegate,
private TypeParserFactory $typeParserFactory,
private TemplateParser $templateParser
) {}

public function tokenize(string $symbol): Token
{
$token = $this->delegate->tokenize($symbol);

if ($token instanceof ClassNameToken) {
return new AdvancedClassNameToken($token, $this->typeParserFactory, $this->templateParser);
return new AdvancedClassNameToken($token, $this->typeParserFactory);
}

return $token;
Expand Down
Loading