packages/lemon-parser/tests/Unit/Ast/RuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Ast;
6
7use LemonParser\Ast\CodeBlock;
8use LemonParser\Ast\Location;
9use LemonParser\Ast\RhsItem;
10use LemonParser\Ast\Rule;
11use LemonParser\Ast\Symbol;
12use PHPUnit\Framework\Attributes\CoversClass;
13use PHPUnit\Framework\Attributes\Small;
14use PHPUnit\Framework\Attributes\UsesClass;
15use PHPUnit\Framework\TestCase;
16
17#[CoversClass(Rule::class)]
18#[UsesClass(CodeBlock::class)]
19#[UsesClass(Location::class)]
20#[UsesClass(RhsItem::class)]
21#[UsesClass(Symbol::class)]
22#[Small]
23final class RuleTest extends TestCase
24{
25    public function testWithPrecedence(): void
26    {
27        $rule = new Rule(new Symbol('expr', new Location(1, 1)), 'A', [], null, null, false, new Location(1, 1));
28
29        $marked = $rule->withPrecedence(new Symbol('PLUS', new Location(1, 20)));
30
31        self::assertSame('PLUS', $marked->precedence?->name);
32        self::assertNull($rule->precedence);
33        self::assertSame(['expr', 'A', '1:1'], [$marked->lhs->name, $marked->lhsAlias, (string) $marked->location]);
34    }
35
36    public function testWithCode(): void
37    {
38        $rule = new Rule(new Symbol('expr', new Location(1, 1)), null, [], null, null, false, new Location(1, 1));
39
40        $withCode = $rule->withCode(new CodeBlock(' x ', new Location(1, 20)));
41
42        self::assertSame(' x ', $withCode->code?->code);
43        self::assertNull($rule->code);
44    }
45
46    public function testWithNeverReduce(): void
47    {
48        $rule = new Rule(new Symbol('expr', new Location(1, 1)), null, [], null, null, false, new Location(1, 1));
49
50        self::assertTrue($rule->withNeverReduce()->neverReduce);
51        self::assertFalse($rule->neverReduce);
52    }
53
54    public function testSymbols(): void
55    {
56        $items = [
57            new RhsItem([new Symbol('expr', new Location(1, 10))], 'B'),
58            new RhsItem([new Symbol('PLUS', new Location(1, 15)), new Symbol('MINUS', new Location(1, 20))], null),
59            new RhsItem([new Symbol('NUM', new Location(1, 26))], 'C'),
60        ];
61        $rule = new Rule(new Symbol('expr', new Location(1, 1)), null, $items, null, null, false, new Location(1, 1));
62
63        self::assertSame(['expr', 'PLUS', 'MINUS', 'NUM'], array_map(static fn (Symbol $symbol): string => $symbol->name, $rule->symbols()));
64    }
65}
66