diff --git a/.github/workflows/branch-validations.yaml b/.github/workflows/branch-validations.yaml index 5d67b20..0406cbb 100644 --- a/.github/workflows/branch-validations.yaml +++ b/.github/workflows/branch-validations.yaml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: symfonycorp/security-checker-action@v2 + - uses: symfonycorp/security-checker-action@v3 composer: runs-on: ubuntu-latest @@ -27,16 +27,19 @@ jobs: with: php-version: '8.1' tools: composer:v2 + - name: Composer cache uses: actions/cache@v2 with: key: composer-${{ hashFiles('**/composer.lock') }} path: ${{ github.workspace }}/.cache + - name: Vendor cache uses: actions/cache@v2 with: key: vendor-${{ hashFiles('**/composer.lock') }} path: ${{ github.workspace }}/vendor + - name: Tools cache uses: actions/cache@v2 with: @@ -68,16 +71,19 @@ jobs: with: php-version: '8.1' tools: composer:v2 + - name: Composer cache uses: actions/cache@v2 with: key: composer-${{ hashFiles('**/composer.lock') }} path: ${{ github.workspace }}/.cache + - name: Vendor cache uses: actions/cache@v2 with: key: vendor-${{ hashFiles('**/composer.lock') }} path: ${{ github.workspace }}/vendor + - name: Tools cache uses: actions/cache@v2 with: diff --git a/composer.json b/composer.json index 66160e1..5160d18 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ ], "require": { "php": "^8.0", - "ext-mbstring": "*" + "ext-mbstring": "^8.0", + "psr/log": "^2.0 || ^3.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.15", diff --git a/composer.lock b/composer.lock index 43b0285..ec737fb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,59 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c9bd0e80e7e22f425eb286b5c42b5f54", - "packages": [], + "content-hash": "6d73951acc3119aabd404dbbe0967053", + "packages": [ + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + } + ], "packages-dev": [ { "name": "dealerdirect/phpcodesniffer-composer-installer", @@ -84,35 +135,35 @@ }, { "name": "ergebnis/composer-normalize", - "version": "2.24.0", + "version": "2.28.3", "source": { "type": "git", "url": "https://github.com/ergebnis/composer-normalize.git", - "reference": "0492b8de602ac601f5d53a5ef9c9558701a18f31" + "reference": "ec75a2bf751f6fec165e9ea0262655b8ca397e5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ergebnis/composer-normalize/zipball/0492b8de602ac601f5d53a5ef9c9558701a18f31", - "reference": "0492b8de602ac601f5d53a5ef9c9558701a18f31", + "url": "https://api.github.com/repos/ergebnis/composer-normalize/zipball/ec75a2bf751f6fec165e9ea0262655b8ca397e5c", + "reference": "ec75a2bf751f6fec165e9ea0262655b8ca397e5c", "shasum": "" }, "require": { "composer-plugin-api": "^2.0.0", "ergebnis/json-normalizer": "~2.1.0", "ergebnis/json-printer": "^3.2.0", - "justinrainbow/json-schema": "^5.2.11", + "justinrainbow/json-schema": "^5.2.12", "localheinz/diff": "^1.1.1", "php": "^7.4 || ^8.0" }, "require-dev": { - "composer/composer": "^2.2.5", + "composer/composer": "^2.3.9", "ergebnis/license": "^1.2.0", - "ergebnis/php-cs-fixer-config": "^3.4.0", + "ergebnis/php-cs-fixer-config": "^4.4.0", "fakerphp/faker": "^1.19.0", - "phpunit/phpunit": "^9.5.17", - "psalm/plugin-phpunit": "~0.16.1", - "symfony/filesystem": "^5.4.6", - "vimeo/psalm": "^4.22.0" + "phpunit/phpunit": "^9.5.21", + "psalm/plugin-phpunit": "~0.17.0", + "symfony/filesystem": "^5.4.9", + "vimeo/psalm": "^4.24.0" }, "type": "composer-plugin", "extra": { @@ -149,13 +200,7 @@ "issues": "https://github.com/ergebnis/composer-normalize/issues", "source": "https://github.com/ergebnis/composer-normalize" }, - "funding": [ - { - "url": "https://github.com/localheinz", - "type": "github" - } - ], - "time": "2022-03-09T08:15:05+00:00" + "time": "2022-07-05T16:09:10+00:00" }, { "name": "ergebnis/json-normalizer", @@ -358,16 +403,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.11", + "version": "5.2.12", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "2ab6744b7296ded80f8cc4f9509abbff393399aa" + "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ab6744b7296ded80f8cc4f9509abbff393399aa", - "reference": "2ab6744b7296ded80f8cc4f9509abbff393399aa", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", + "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", "shasum": "" }, "require": { @@ -422,9 +467,9 @@ ], "support": { "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/5.2.11" + "source": "https://github.com/justinrainbow/json-schema/tree/5.2.12" }, - "time": "2021-07-22T09:24:00+00:00" + "time": "2022-04-13T08:02:27+00:00" }, { "name": "localheinz/diff", @@ -488,28 +533,27 @@ }, { "name": "phpstan/extension-installer", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/phpstan/extension-installer.git", - "reference": "66c7adc9dfa38b6b5838a9fb728b68a7d8348051" + "reference": "f06dbb052ddc394e7896fcd1cfcd533f9f6ace40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/66c7adc9dfa38b6b5838a9fb728b68a7d8348051", - "reference": "66c7adc9dfa38b6b5838a9fb728b68a7d8348051", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/f06dbb052ddc394e7896fcd1cfcd533f9f6ace40", + "reference": "f06dbb052ddc394e7896fcd1cfcd533f9f6ace40", "shasum": "" }, "require": { - "composer-plugin-api": "^1.1 || ^2.0", - "php": "^7.1 || ^8.0", - "phpstan/phpstan": ">=0.11.6" + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.8.0" }, "require-dev": { - "composer/composer": "^1.8", - "phing/phing": "^2.16.3", + "composer/composer": "^2.0", "php-parallel-lint/php-parallel-lint": "^1.2.0", - "phpstan/phpstan-strict-rules": "^0.11 || ^0.12" + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" }, "type": "composer-plugin", "extra": { @@ -527,41 +571,37 @@ "description": "Composer plugin for automatic installation of PHPStan extensions", "support": { "issues": "https://github.com/phpstan/extension-installer/issues", - "source": "https://github.com/phpstan/extension-installer/tree/1.1.0" + "source": "https://github.com/phpstan/extension-installer/tree/1.2.0" }, - "time": "2020-12-13T13:06:13+00:00" + "time": "2022-10-17T12:59:16+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.2.0", + "version": "1.13.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "dbc093d7af60eff5cd575d2ed761b15ed40bd08e" + "reference": "aac44118344d197e6d5f7c6cee91885f0a89acdd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/dbc093d7af60eff5cd575d2ed761b15ed40bd08e", - "reference": "dbc093d7af60eff5cd575d2ed761b15ed40bd08e", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/aac44118344d197e6d5f7c6cee91885f0a89acdd", + "reference": "aac44118344d197e6d5f7c6cee91885f0a89acdd", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { "psr-4": { "PHPStan\\PhpDocParser\\": [ @@ -576,26 +616,26 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.2.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.13.1" }, - "time": "2021-09-16T20:46:02+00:00" + "time": "2022-11-20T08:52:26+00:00" }, { "name": "phpstan/phpstan", - "version": "1.4.9", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "1a45f44d319cf000a8c960af6b7435741e944771" + "reference": "d6fdf01c53978b6429f1393ba4afeca39cc68afa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1a45f44d319cf000a8c960af6b7435741e944771", - "reference": "1a45f44d319cf000a8c960af6b7435741e944771", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d6fdf01c53978b6429f1393ba4afeca39cc68afa", + "reference": "d6fdf01c53978b6429f1393ba4afeca39cc68afa", "shasum": "" }, "require": { - "php": "^7.1|^8.0" + "php": "^7.2|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -605,11 +645,6 @@ "phpstan.phar" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, "autoload": { "files": [ "bootstrap.php" @@ -620,9 +655,13 @@ "MIT" ], "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.4.9" + "source": "https://github.com/phpstan/phpstan/tree/1.9.2" }, "funding": [ { @@ -633,16 +672,12 @@ "url": "https://github.com/phpstan", "type": "github" }, - { - "url": "https://www.patreon.com/phpstan", - "type": "patreon" - }, { "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", "type": "tidelift" } ], - "time": "2022-03-10T08:52:08+00:00" + "time": "2022-11-10T09:56:11+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -696,21 +731,21 @@ }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.1.0", + "version": "1.4.4", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "e12d55f74a8cca18c6e684c6450767e055ba7717" + "reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/e12d55f74a8cca18c6e684c6450767e055ba7717", - "reference": "e12d55f74a8cca18c6e684c6450767e055ba7717", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6", + "reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0", - "phpstan/phpstan": "^1.2.0" + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.8.6" }, "require-dev": { "nikic/php-parser": "^4.13.0", @@ -720,9 +755,6 @@ }, "type": "phpstan-extension", "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - }, "phpstan": { "includes": [ "rules.neon" @@ -741,38 +773,38 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.1.0" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.4" }, - "time": "2021-11-18T09:30:29+00:00" + "time": "2022-09-21T11:38:17+00:00" }, { "name": "slevomat/coding-standard", - "version": "7.0.19", + "version": "7.2.1", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "bef66a43815bbf9b5f49775e9ded3f7c6ba0cc37" + "reference": "aff06ae7a84e4534bf6f821dc982a93a5d477c90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/bef66a43815bbf9b5f49775e9ded3f7c6ba0cc37", - "reference": "bef66a43815bbf9b5f49775e9ded3f7c6ba0cc37", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/aff06ae7a84e4534bf6f821dc982a93a5d477c90", + "reference": "aff06ae7a84e4534bf6f821dc982a93a5d477c90", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", - "php": "^7.1 || ^8.0", - "phpstan/phpdoc-parser": "^1.0.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": "^1.5.1", "squizlabs/php_codesniffer": "^3.6.2" }, "require-dev": { - "phing/phing": "2.17.2", + "phing/phing": "2.17.3", "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "1.4.6", + "phpstan/phpstan": "1.4.10|1.7.1", "phpstan/phpstan-deprecation-rules": "1.0.0", - "phpstan/phpstan-phpunit": "1.0.0", - "phpstan/phpstan-strict-rules": "1.1.0", - "phpunit/phpunit": "7.5.20|8.5.21|9.5.16" + "phpstan/phpstan-phpunit": "1.0.0|1.1.1", + "phpstan/phpstan-strict-rules": "1.2.3", + "phpunit/phpunit": "7.5.20|8.5.21|9.5.20" }, "type": "phpcodesniffer-standard", "extra": { @@ -792,7 +824,7 @@ "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/7.0.19" + "source": "https://github.com/slevomat/coding-standard/tree/7.2.1" }, "funding": [ { @@ -804,20 +836,20 @@ "type": "tidelift" } ], - "time": "2022-03-01T18:01:41+00:00" + "time": "2022-05-25T10:58:12+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.6.2", + "version": "3.7.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a" + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", "shasum": "" }, "require": { @@ -860,7 +892,7 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2021-12-12T21:44:58+00:00" + "time": "2022-06-18T07:21:10+00:00" } ], "aliases": [], @@ -870,8 +902,8 @@ "prefer-lowest": false, "platform": { "php": "^8.0", - "ext-mbstring": "*" + "ext-mbstring": "^8.0" }, "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } diff --git a/phpcs.xml.dist b/phpcs.xml.dist index bf40ce2..fe0b85e 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -636,6 +636,10 @@ 5 + + src/StdoutMessageLogger.php + + src/Atn/Transitions/AbstractPredicateTransition.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index e4ce2f4..0c0bb88 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -16,18 +16,9 @@ parameters: missingCheckedExceptionInThrows: true tooWideThrowType: true ignoreErrors: - - - path: src/Dfa/DFA.php - message: '#^Property Antlr\\Antlr4\\Runtime\\Dfa\\DFAState\:\:\$edges \(SplFixedArray\\|null\) does not accept SplFixedArray\.$#' - - - path: src/Atn/ParserATNSimulator.php - message: '#^Property Antlr\\Antlr4\\Runtime\\Dfa\\DFAState\:\:\$edges \(SplFixedArray\\|null\) does not accept SplFixedArray\.$#' - path: src/Atn/ParserATNSimulator.php message: '#^Property Antlr\\Antlr4\\Runtime\\Dfa\\DFAState\:\:\$edges \(SplFixedArray\\|null\) does not accept non\-empty\-array\, Antlr\\Antlr4\\Runtime\\Dfa\\DFAState\>\|SplFixedArray\\.$#' - - - path: src/Atn/LexerATNSimulator.php - message: '#^Property Antlr\\Antlr4\\Runtime\\Dfa\\DFAState\:\:\$edges \(SplFixedArray\\|null\) does not accept SplFixedArray\\.$#' - path: src/Atn/LexerATNSimulator.php message: '#^Property Antlr\\Antlr4\\Runtime\\Dfa\\DFAState\:\:\$edges \(SplFixedArray\\|null\) does not accept non\-empty\-array\, Antlr\\Antlr4\\Runtime\\Dfa\\DFAState\>\|SplFixedArray\\.$#' \ No newline at end of file diff --git a/src/Atn/ATNConfig.php b/src/Atn/ATNConfig.php index 425b9b0..7e9c9b9 100644 --- a/src/Atn/ATNConfig.php +++ b/src/Atn/ATNConfig.php @@ -157,7 +157,7 @@ public function toString(bool $showAlt): string $buf .= ',[' . $this->context . ']'; } - if ($this->semanticContext->equals(SemanticContext::none())) { + if (!$this->semanticContext->equals(SemanticContext::none())) { $buf .= ',' . $this->semanticContext; } @@ -177,9 +177,9 @@ public function __toString(): string $this->state, $this->alt, $this->context !== null ? ',[' . $this->context . ']' : '', - $this->semanticContext->equals(SemanticContext::none()) ? - ',' . $this->semanticContext : - '', + $this->semanticContext->equals(SemanticContext::none()) + ? '' + : ',' . $this->semanticContext, $this->reachesIntoOuterContext > 0 ? ',up=' . $this->reachesIntoOuterContext : '', ); } diff --git a/src/Atn/ParserATNSimulator.php b/src/Atn/ParserATNSimulator.php index 36c31a4..57fb55a 100644 --- a/src/Atn/ParserATNSimulator.php +++ b/src/Atn/ParserATNSimulator.php @@ -24,6 +24,7 @@ use Antlr\Antlr4\Runtime\Error\Exceptions\RecognitionException; use Antlr\Antlr4\Runtime\IntervalSet; use Antlr\Antlr4\Runtime\IntStream; +use Antlr\Antlr4\Runtime\LoggerProvider; use Antlr\Antlr4\Runtime\Parser; use Antlr\Antlr4\Runtime\ParserRuleContext; use Antlr\Antlr4\Runtime\PredictionContexts\PredictionContext; @@ -35,6 +36,7 @@ use Antlr\Antlr4\Runtime\Utils\BitSet; use Antlr\Antlr4\Runtime\Utils\DoubleKeyMap; use Antlr\Antlr4\Runtime\Utils\Set; +use Psr\Log\LoggerInterface as Logger; /** * The embodiment of the adaptive LL(*), ALL(*), parsing strategy. @@ -231,6 +233,8 @@ */ final class ParserATNSimulator extends ATNSimulator { + public static bool $traceAtnSimulation = false; + protected Parser $parser; /** @var array */ @@ -260,6 +264,8 @@ final class ParserATNSimulator extends ATNSimulator protected ?DFA $dfa = null; + private Logger $logger; + /** * @param array $decisionToDFA */ @@ -273,6 +279,7 @@ public function __construct( $this->parser = $parser; $this->decisionToDFA = $decisionToDFA; + $this->logger = LoggerProvider::getLogger(); } public function reset(): void @@ -296,6 +303,18 @@ public function clearDFA(): void */ public function adaptivePredict(TokenStream $input, int $decision, ParserRuleContext $outerContext): int { + if (self::$traceAtnSimulation) { + $this->logger->debug( + 'adaptivePredict decision {decision} exec LA(1)=={token} line {line}:{pos}', + [ + 'decision' => $decision, + 'token' => $this->getTokenName($input->LA(1)), + 'line' => $input->LT(1)?->getLine(), + 'pos' => $input->LT(1)?->getCharPositionInLine(), + ], + ); + } + $this->input = $input; $this->startIndex = $input->getIndex(); $this->outerContext = $outerContext; @@ -404,6 +423,19 @@ public function execATN( int $startIndex, ParserRuleContext $outerContext, ): ?int { + if (self::$traceAtnSimulation) { + $this->logger->debug( + 'execATN decision {decision}, DFA state {state}, LA(1)=={token} line {line}:{pos}', + [ + 'decision' => $dfa->decision, + 'state' => $s0->__toString(), + 'token' => $this->getTokenName($input->LA(1)), + 'line' => $input->LT(1)?->getLine(), + 'pos' => $input->LT(1)?->getCharPositionInLine(), + ], + ); + } + $previousD = $s0; $t = $input->LA(1); @@ -655,6 +687,12 @@ protected function execATNWithFullContext( int $startIndex, ParserRuleContext $outerContext, ): int { + if (self::$traceAtnSimulation) { + $this->logger->debug('execATNWithFullContext {state}', [ + 'state' => $s0->__toString(), + ]); + } + $fullCtx = true; $foundExactAmbig = false; $reach = null; @@ -890,15 +928,18 @@ protected function computeReachSet(ATNConfigSet $closure, int $t, bool $fullCtx) * multiple alternatives are viable.*/ if ($skippedStopStates !== null && (!$fullCtx || !PredictionMode::hasConfigInRuleStopState($reach))) { - if (\count($skippedStopStates) === 0) { - throw new \LogicException('Skipped stop states cannot be empty.'); - } - foreach ($skippedStopStates as $lValue) { $reach->add($lValue, $this->mergeCache); } } + if (self::$traceAtnSimulation) { + $this->logger->debug('computeReachSet {closure} -> {reach}', [ + 'closure' => $closure->__toString(), + 'reach' => $reach->__toString(), + ]); + } + if ($reach->isEmpty()) { return null; } @@ -964,6 +1005,13 @@ protected function computeStartState(ATNState $p, RuleContext $ctx, bool $fullCt $initialContext = PredictionContext::fromRuleContext($this->atn, $ctx); $configs = new ATNConfigSet($fullCtx); + if (self::$traceAtnSimulation) { + $this->logger->debug('computeStartState from ATN state {state} initialContext={initialContext}', [ + 'state' => $p->__toString(), + 'initialContext' => $initialContext->__toString(), + ]); + } + foreach ($p->getTransitions() as $i => $t) { $c = new ATNConfig(null, $t->target, $initialContext, null, $i + 1); $closureBusy = new Set(); @@ -1464,6 +1512,12 @@ protected function closureCheckingStopState( int $depth, bool $treatEofAsEpsilon, ): void { + if (self::$traceAtnSimulation) { + $this->logger->debug('closure({config})', [ + 'config' => $config->toString(true), + ]); + } + if ($config->state instanceof RuleStopState) { // We hit rule end. If we have context info, use it run thru all possible stack tops in ctx $context = $config->context; @@ -2150,6 +2204,12 @@ protected function addDFAState(DFA $dfa, DFAState $D): DFAState $existing = $dfa->states->get($D); if ($existing instanceof DFAState) { + if (self::$traceAtnSimulation) { + $this->logger->debug('addDFAState {state} exists', [ + 'state' => $D->__toString(), + ]); + } + return $existing; } @@ -2160,6 +2220,12 @@ protected function addDFAState(DFA $dfa, DFAState $D): DFAState $D->configs->setReadonly(true); } + if (self::$traceAtnSimulation) { + $this->logger->debug('addDFAState new {state}', [ + 'state' => $D->__toString(), + ]); + } + $dfa->states->add($D); return $D; diff --git a/src/LoggerProvider.php b/src/LoggerProvider.php new file mode 100644 index 0000000..5bb5cd1 --- /dev/null +++ b/src/LoggerProvider.php @@ -0,0 +1,26 @@ +getByTwoKeys($a, $b); if ($previous !== null) { + if (ParserATNSimulator::$traceAtnSimulation) { + LoggerProvider::getLogger() + ->debug('mergeArrays a={a},b={b} -> previous', [ + 'a' => $a->__toString(), + 'b' => $b->__toString(), + ]); + } + return $previous; } $previous = $mergeCache->getByTwoKeys($b, $a); if ($previous !== null) { + if (ParserATNSimulator::$traceAtnSimulation) { + LoggerProvider::getLogger() + ->debug('mergeArrays a={a},b={b} -> previous', [ + 'a' => $a->__toString(), + 'b' => $b->__toString(), + ]); + } + return $previous; } } @@ -500,6 +518,14 @@ public static function mergeArrays( $mergeCache->set($a, $b, $a); } + if (ParserATNSimulator::$traceAtnSimulation) { + LoggerProvider::getLogger() + ->debug('mergeArrays a={a},b={b} -> a', [ + 'a' => $a->__toString(), + 'b' => $b->__toString(), + ]); + } + return $a; } @@ -508,6 +534,14 @@ public static function mergeArrays( $mergeCache->set($a, $b, $b); } + if (ParserATNSimulator::$traceAtnSimulation) { + LoggerProvider::getLogger() + ->debug('mergeArrays a={a},b={b} -> b', [ + 'a' => $a->__toString(), + 'b' => $b->__toString(), + ]); + } + return $b; } @@ -515,6 +549,15 @@ public static function mergeArrays( $mergeCache->set($a, $b, $M); } + if (ParserATNSimulator::$traceAtnSimulation) { + LoggerProvider::getLogger() + ->debug('mergeArrays a={a},b={b} -> M', [ + 'a' => $a->__toString(), + 'b' => $b->__toString(), + 'M' => $M->__toString(), + ]); + } + return $M; } diff --git a/src/RuntimeMetaData.php b/src/RuntimeMetaData.php index 58db9a1..cad69b6 100644 --- a/src/RuntimeMetaData.php +++ b/src/RuntimeMetaData.php @@ -51,7 +51,7 @@ final class RuntimeMetaData * - suffix is an optional string. When `suffix` is omitted, the `-` * (hyphen-minus) appearing before it is also omitted. */ - public const VERSION = '4.11.1'; + public const VERSION = '4.12.0'; /** * Gets the currently executing version of the ANTLR 4 runtime library. diff --git a/src/StdoutMessageLogger.php b/src/StdoutMessageLogger.php new file mode 100644 index 0000000..58d2af4 --- /dev/null +++ b/src/StdoutMessageLogger.php @@ -0,0 +1,33 @@ + $context + */ + public function log($level, \Stringable|string $message, array $context = []): void + { + \fwrite(\STDOUT, self::formatMessage($message, $context) . \PHP_EOL); + } + + /** + * @param array $context + */ + private static function formatMessage(\Stringable|string $message, array $context): string + { + $replace = []; + foreach ($context as $key => $val) { + $replace['{' . $key . '}'] = $val; + } + + return \strtr((string) $message, $replace); + } +} diff --git a/src/Utils/Pair.php b/src/Utils/Pair.php index fc80417..3a3c5a3 100644 --- a/src/Utils/Pair.php +++ b/src/Utils/Pair.php @@ -38,6 +38,14 @@ public function hashCode(): int public function __toString(): string { - return \sprintf('%s, %s', (string) $this->a, (string) $this->b); + return \sprintf( + '%s, %s', + $this->a === null + ? 'null' + : ($this->a instanceof \Stringable ? (string) $this->a : $this->a::class), + $this->b === null + ? 'null' + : ($this->b instanceof \Stringable ? (string) $this->b : $this->b::class), + ); } }