1<?php
2
3declare(strict_types=1);
4
5namespace Antlr\Antlr4\Runtime\Atn\Actions;
6
7use Antlr\Antlr4\Runtime\Comparison\Hasher;
8use Antlr\Antlr4\Runtime\Lexer;
9
10/**
11 * This implementation of {@see LexerAction} is used for tracking input offsets
12 * for position-dependent actions within a {@see LexerActionExecutor}.
13 *
14 * This action is not serialized as part of the ATN, and is only required for
15 * position-dependent lexer actions which appear at a location other than the
16 * end of a rule. For more information about DFA optimizations employed for
17 * lexer actions, see {@see LexerActionExecutor::append()} and
18 * {@see LexerActionExecutor::fixOffsetBeforeMatch()}.
19 *
20 * @author Sam Harwell
21 */
22final class LexerIndexedCustomAction implements LexerAction
23{
24    /** @var int */
25    private $offset;
26
27    /** @var LexerAction */
28    private $action;
29
30    /**
31     * Constructs a new indexed custom action by associating a character offset
32     * with a {@see LexerAction}.
33     *
34     * Note: This class is only required for lexer actions for which
35     * {@see LexerAction::isPositionDependent()} returns `true`.
36     *
37     * @param int         $offset The offset into the input {@see CharStream},
38     *                            relative to the token start index, at which
39     *                            the specified lexer action should be executed.
40     * @param LexerAction $action The lexer action to execute at a particular
41     *                            offset in the input {@see CharStream}.
42     */
43    public function __construct(int $offset, LexerAction $action)
44    {
45        $this->offset = $offset;
46        $this->action = $action;
47    }
48
49    /**
50     * Gets the location in the input {@see CharStream} at which the lexer
51     * action should be executed. The value is interpreted as an offset relative
52     * to the token start index.
53     *
54     * @return int The location in the input {@see CharStream} at which the lexer
55     *             action should be executed.
56     */
57    public function getOffset() : int
58    {
59        return $this->offset;
60    }
61
62    /**
63     * Gets the lexer action to execute.
64     *
65     * @return LexerAction A {@see LexerAction} object which executes the lexer action.
66     */
67    public function getAction() : LexerAction
68    {
69        return $this->action;
70    }
71
72    /**
73     * {@inheritdoc}
74     *
75     * @return int This method returns the result of calling
76     *             {@see LexerIndexedCustomAction::getActionType()} on the
77     *             {@see LexerAction} returned by
78     *             {@see LexerIndexedCustomAction::getAction()}.
79     */
80    public function getActionType() : int
81    {
82        return $this->action->getActionType();
83    }
84
85    /**
86     * {@inheritdoc}
87     *
88     * @return bool This method returns `true`.
89     */
90    public function isPositionDependent() : bool
91    {
92        return true;
93    }
94
95    /**
96     * {@inheritdoc}
97     *
98     * This method calls {@see LexerIndexedCustomAction::execute()} on the result
99     * of {@see LexerIndexedCustomAction::getAction()} using the provided `lexer`.
100     */
101    public function execute(Lexer $lexer) : void
102    {
103        // assume the input stream position was properly set by the calling code
104        $this->action->execute($lexer);
105    }
106
107    public function hashCode() : int
108    {
109        return Hasher::hash($this->getActionType(), $this->offset, $this->action);
110    }
111
112    public function equals(object $other) : bool
113    {
114        if ($this === $other) {
115            return true;
116        }
117
118        if (!$other instanceof self) {
119            return false;
120        }
121
122        return $this->offset === $other->offset
123            && $this->action->equals($other->action);
124    }
125}
126