diff --git a/src/Token/Token.php b/src/Token/Token.php index 907ff325..5424294d 100644 --- a/src/Token/Token.php +++ b/src/Token/Token.php @@ -136,9 +136,17 @@ public function getRelatedToken(): ?self return $this->relatedToken; } - public function setRelatedToken(self $token): void + public function setRelatedToken(self $token, bool $bidirectional = false): void { $this->relatedToken = $token; + + if ($bidirectional) { + if (null !== $token->getRelatedToken()) { + throw new \InvalidArgumentException('Cannot create bidirectional relationship on token with a related token.'); + } + + $token->setRelatedToken($this); + } } /** diff --git a/src/Token/Tokenizer.php b/src/Token/Tokenizer.php index af5bd02b..25fbb908 100644 --- a/src/Token/Tokenizer.php +++ b/src/Token/Tokenizer.php @@ -295,7 +295,7 @@ private function pushToken(int|string $type, string $value = '', ?Token $related $value, $relatedToken ); - $relatedToken?->setRelatedToken($token); + $relatedToken?->setRelatedToken($token, true); if (!\in_array($type, Token::EMPTY_TOKENS, true)) { $this->lastNonEmptyToken = $token; diff --git a/tests/Token/TokenTest.php b/tests/Token/TokenTest.php index 1ea29080..f9e75eaf 100644 --- a/tests/Token/TokenTest.php +++ b/tests/Token/TokenTest.php @@ -22,6 +22,38 @@ public function testGetters(): void static::assertSame($relatedToken, $token->getRelatedToken()); } + public function testRelatedToken(): void + { + $relatedToken = new Token(Token::PUNCTUATION_TYPE, 1, 1, 'file.twig', '['); + $token1 = new Token(Token::PUNCTUATION_TYPE, 1, 2, 'file.twig', ']', $relatedToken); + + static::assertSame($relatedToken, $token1->getRelatedToken()); + static::assertNull($relatedToken->getRelatedToken()); + + $token2 = new Token(Token::PUNCTUATION_TYPE, 1, 1, 'file.twig', '['); + $token2->setRelatedToken($relatedToken); + + static::assertSame($relatedToken, $token2->getRelatedToken()); + static::assertNull($relatedToken->getRelatedToken()); + + $token3 = new Token(Token::PUNCTUATION_TYPE, 1, 1, 'file.twig', '['); + $token3->setRelatedToken($relatedToken, true); + + static::assertSame($relatedToken, $token3->getRelatedToken()); + static::assertSame($token3, $relatedToken->getRelatedToken()); + + $token4 = new Token(Token::PUNCTUATION_TYPE, 1, 1, 'file.twig', '['); + $token4->setRelatedToken($relatedToken); + + static::assertSame($relatedToken, $token4->getRelatedToken()); + static::assertSame($token3, $relatedToken->getRelatedToken()); + + $token5 = new Token(Token::PUNCTUATION_TYPE, 1, 1, 'file.twig', '['); + + $this->expectException(\InvalidArgumentException::class); + $token5->setRelatedToken($relatedToken, true); + } + public function testNullValue(): void { $token = new Token(Token::EOF_TYPE, 2, 1, 'file.twig');