packages/lemon-parser/tests/Unit/Syntax/SymbolRegistryTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Syntax;
6
7use LemonParser\Ast\Location;
8use LemonParser\Syntax\SymbolRegistry;
9use LemonParser\SyntaxException;
10use PHPUnit\Framework\Attributes\CoversClass;
11use PHPUnit\Framework\Attributes\Small;
12use PHPUnit\Framework\Attributes\UsesClass;
13use PHPUnit\Framework\TestCase;
14
15#[CoversClass(SymbolRegistry::class)]
16#[UsesClass(Location::class)]
17#[UsesClass(SyntaxException::class)]
18#[Small]
19final class SymbolRegistryTest extends TestCase
20{
21    public function testSee(): void
22    {
23        $registry = new SymbolRegistry();
24
25        $registry->see('expr');
26
27        self::assertTrue($registry->isKnown('expr'));
28    }
29
30    public function testIsKnown(): void
31    {
32        $registry = new SymbolRegistry();
33
34        self::assertFalse($registry->isKnown('expr'));
35        $registry->rank('PLUS', new Location(1, 1));
36        self::assertTrue($registry->isKnown('PLUS'));
37    }
38
39    public function testRank(): void
40    {
41        $registry = new SymbolRegistry();
42        $registry->rank('PLUS', new Location(1, 7));
43
44        $this->expectException(SyntaxException::class);
45        $this->expectExceptionMessage('Symbol "PLUS" has already be given a precedence. at 2:8');
46
47        $registry->rank('PLUS', new Location(2, 8));
48    }
49
50    public function testType(): void
51    {
52        $registry = new SymbolRegistry();
53        $registry->type('expr', new Location(1, 7));
54
55        self::assertTrue($registry->isKnown('expr'));
56        $this->expectException(SyntaxException::class);
57        $this->expectExceptionMessage('Symbol %type "expr" already defined at 2:7');
58
59        $registry->type('expr', new Location(2, 7));
60    }
61
62    public function testFallBack(): void
63    {
64        $registry = new SymbolRegistry();
65        $registry->fallBack('ABORT', new Location(1, 14));
66
67        self::assertTrue($registry->isKnown('ABORT'));
68        $this->expectException(SyntaxException::class);
69        $this->expectExceptionMessage('More than one fallback assigned to token ABORT at 2:14');
70
71        $registry->fallBack('ABORT', new Location(2, 14));
72    }
73
74    public function testWildcard(): void
75    {
76        $registry = new SymbolRegistry();
77        $registry->wildcard('ANY', new Location(1, 11));
78
79        self::assertTrue($registry->isKnown('ANY'));
80        $this->expectException(SyntaxException::class);
81        $this->expectExceptionMessage('Extra wildcard to token: OTHER at 1:15');
82
83        $registry->wildcard('OTHER', new Location(1, 15));
84    }
85}
86