xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/InputStream.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
1*37748cd8SNickeau<?php
2*37748cd8SNickeau
3*37748cd8SNickeaudeclare(strict_types=1);
4*37748cd8SNickeau
5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime;
6*37748cd8SNickeau
7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Utils\StringUtils;
8*37748cd8SNickeau
9*37748cd8SNickeau/**
10*37748cd8SNickeau * Vacuum all input from a string and then treat it like a buffer.
11*37748cd8SNickeau */
12*37748cd8SNickeaufinal class InputStream implements CharStream
13*37748cd8SNickeau{
14*37748cd8SNickeau    /** @var int */
15*37748cd8SNickeau    protected $index = 0;
16*37748cd8SNickeau
17*37748cd8SNickeau    /** @var int */
18*37748cd8SNickeau    protected $size = 0;
19*37748cd8SNickeau
20*37748cd8SNickeau    /** @var string */
21*37748cd8SNickeau    public $name = '<empty>';
22*37748cd8SNickeau
23*37748cd8SNickeau    /** @var string */
24*37748cd8SNickeau    public $input;
25*37748cd8SNickeau
26*37748cd8SNickeau    /** @var array<string> */
27*37748cd8SNickeau    public $characters = [];
28*37748cd8SNickeau
29*37748cd8SNickeau    /**
30*37748cd8SNickeau     * @param array<string> $characters
31*37748cd8SNickeau     */
32*37748cd8SNickeau    private function __construct(string $input, array $characters)
33*37748cd8SNickeau    {
34*37748cd8SNickeau        $this->input = $input;
35*37748cd8SNickeau        $this->characters = $characters;
36*37748cd8SNickeau        $this->size = \count($this->characters);
37*37748cd8SNickeau    }
38*37748cd8SNickeau
39*37748cd8SNickeau    public static function fromString(string $input) : InputStream
40*37748cd8SNickeau    {
41*37748cd8SNickeau        $chars = \preg_split('//u', $input, -1, \PREG_SPLIT_NO_EMPTY);
42*37748cd8SNickeau
43*37748cd8SNickeau        return new self($input, $chars === false ? [] : $chars);
44*37748cd8SNickeau    }
45*37748cd8SNickeau
46*37748cd8SNickeau    public static function fromPath(string $path) : InputStream
47*37748cd8SNickeau    {
48*37748cd8SNickeau        $content = \file_get_contents($path);
49*37748cd8SNickeau
50*37748cd8SNickeau        if ($content === false) {
51*37748cd8SNickeau            throw new \InvalidArgumentException(\sprintf('File not found at %s.', $path));
52*37748cd8SNickeau        }
53*37748cd8SNickeau
54*37748cd8SNickeau        return self::fromString($content);
55*37748cd8SNickeau    }
56*37748cd8SNickeau
57*37748cd8SNickeau    public function getIndex() : int
58*37748cd8SNickeau    {
59*37748cd8SNickeau        return $this->index;
60*37748cd8SNickeau    }
61*37748cd8SNickeau
62*37748cd8SNickeau    public function getLength() : int
63*37748cd8SNickeau    {
64*37748cd8SNickeau        return $this->size;
65*37748cd8SNickeau    }
66*37748cd8SNickeau
67*37748cd8SNickeau    public function consume() : void
68*37748cd8SNickeau    {
69*37748cd8SNickeau        if ($this->index >= $this->size) {
70*37748cd8SNickeau            // assert this.LA(1) == Token.EOF
71*37748cd8SNickeau            throw new \RuntimeException('Cannot consume EOF.');
72*37748cd8SNickeau        }
73*37748cd8SNickeau
74*37748cd8SNickeau        $this->index++;
75*37748cd8SNickeau    }
76*37748cd8SNickeau
77*37748cd8SNickeau    public function LA(int $offset) : int
78*37748cd8SNickeau    {
79*37748cd8SNickeau        if ($offset === 0) {
80*37748cd8SNickeau            return 0;// undefined
81*37748cd8SNickeau        }
82*37748cd8SNickeau
83*37748cd8SNickeau        if ($offset < 0) {
84*37748cd8SNickeau            // e.g., translate LA(-1) to use offset=0
85*37748cd8SNickeau            $offset++;
86*37748cd8SNickeau        }
87*37748cd8SNickeau
88*37748cd8SNickeau        $pos = $this->index + $offset - 1;
89*37748cd8SNickeau
90*37748cd8SNickeau        if ($pos < 0 || $pos >= $this->size) {
91*37748cd8SNickeau            // invalid
92*37748cd8SNickeau            return Token::EOF;
93*37748cd8SNickeau        }
94*37748cd8SNickeau
95*37748cd8SNickeau        return StringUtils::codePoint($this->characters[$pos]);
96*37748cd8SNickeau    }
97*37748cd8SNickeau
98*37748cd8SNickeau    public function LT(int $offset) : int
99*37748cd8SNickeau    {
100*37748cd8SNickeau        return $this->LA($offset);
101*37748cd8SNickeau    }
102*37748cd8SNickeau
103*37748cd8SNickeau    /**
104*37748cd8SNickeau     * Mark/release do nothing; we have entire buffer
105*37748cd8SNickeau     */
106*37748cd8SNickeau    public function mark() : int
107*37748cd8SNickeau    {
108*37748cd8SNickeau        return -1;
109*37748cd8SNickeau    }
110*37748cd8SNickeau
111*37748cd8SNickeau    public function release(int $marker) : void
112*37748cd8SNickeau    {
113*37748cd8SNickeau    }
114*37748cd8SNickeau
115*37748cd8SNickeau    /**
116*37748cd8SNickeau     * {@see self::consume()} ahead until `$p === $this->index`; Can't just set
117*37748cd8SNickeau     * `$p = $this->index` as we must update line and column. If we seek
118*37748cd8SNickeau     * backwards, just set `$p`.
119*37748cd8SNickeau     */
120*37748cd8SNickeau    public function seek(int $index) : void
121*37748cd8SNickeau    {
122*37748cd8SNickeau        if ($index <= $this->index) {
123*37748cd8SNickeau            $this->index = $index; // just jump; don't update stream state (line, ...)
124*37748cd8SNickeau
125*37748cd8SNickeau            return;
126*37748cd8SNickeau        }
127*37748cd8SNickeau
128*37748cd8SNickeau        // seek forward
129*37748cd8SNickeau        $this->index = \min($index, $this->size);
130*37748cd8SNickeau    }
131*37748cd8SNickeau
132*37748cd8SNickeau    public function getText(int $start, int $stop) : string
133*37748cd8SNickeau    {
134*37748cd8SNickeau        if ($stop >= $this->size) {
135*37748cd8SNickeau            $stop = $this->size - 1;
136*37748cd8SNickeau        }
137*37748cd8SNickeau
138*37748cd8SNickeau        if ($start >= $this->size) {
139*37748cd8SNickeau            return '';
140*37748cd8SNickeau        }
141*37748cd8SNickeau
142*37748cd8SNickeau        return \implode(\array_slice($this->characters, $start, $stop - $start + 1));
143*37748cd8SNickeau    }
144*37748cd8SNickeau
145*37748cd8SNickeau    public function getSourceName() : string
146*37748cd8SNickeau    {
147*37748cd8SNickeau        return '';
148*37748cd8SNickeau    }
149*37748cd8SNickeau
150*37748cd8SNickeau    public function __toString() : string
151*37748cd8SNickeau    {
152*37748cd8SNickeau        return $this->input;
153*37748cd8SNickeau    }
154*37748cd8SNickeau}
155