• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / latte / 20711295966

05 Jan 2026 09:41AM UTC coverage: 94.752% (-0.09%) from 94.845%
20711295966

push

github

dg
added support for Partial Function Application WIP

172 of 179 new or added lines in 7 files covered. (96.09%)

29 existing lines in 8 files now uncovered.

5507 of 5812 relevant lines covered (94.75%)

0.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.83
/src/Latte/Compiler/TokenStream.php
1
<?php
2

3
/**
4
 * This file is part of the Latte (https://latte.nette.org)
5
 * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
 */
7

8
declare(strict_types=1);
9

10
namespace Latte\Compiler;
11

12
use Latte\CompileException;
13
use function array_map, count, implode, is_int, is_string, trim;
14

15

16
/**
17
 * TokenStream loads tokens from $source iterator on-demand, and places them in a buffer to provide access
18
 * to any previous token by index.
19
 */
20
final class TokenStream
21
{
22
        /** @var Token[] */
23
        private array $tokens = [];
24
        private int $index = 0;
25

26

27
        public function __construct(
1✔
28
                private readonly \Iterator $source,
29
        ) {
30
        }
1✔
31

32

33
        /**
34
         * Tells whether the token at current position is of given kind.
35
         */
36
        public function is(int|string ...$kind): bool
1✔
37
        {
38
                return $this->peek()->is(...$kind);
1✔
39
        }
40

41

42
        /**
43
         * Gets the token at $offset from the current position.
44
         */
45
        public function peek(int $offset = 0): ?Token
1✔
46
        {
47
                $pos = $this->index + $offset;
1✔
48
                while ($pos >= 0 && !isset($this->tokens[$pos]) && $this->source->valid()) {
1✔
49
                        if ($this->tokens) {
1✔
50
                                $this->source->next();
1✔
51
                        }
52

53
                        if ($this->source->valid()) {
1✔
54
                                $this->tokens[] = $this->source->current();
1✔
55
                        }
56
                }
57

58
                return $this->tokens[$pos] ?? null;
1✔
59
        }
60

61

62
        /**
63
         * Consumes the current token (if is of given kind) or throws exception on end.
64
         * @throws CompileException
65
         */
66
        public function consume(int|string ...$kind): Token
1✔
67
        {
68
                $token = $this->peek();
1✔
69
                if ($kind && !$token->is(...$kind)) {
1✔
70
                        $kind = array_map(fn($item) => is_string($item) ? "'$item'" : Token::Names[$item], $kind);
1✔
71
                        $this->throwUnexpectedException($kind);
1✔
72
                } elseif (!$token->isEnd()) {
1✔
73
                        $this->index++;
1✔
74
                }
75
                return $token;
1✔
76
        }
77

78

79
        /**
80
         * Consumes the current token of given kind or returns null.
81
         */
82
        public function tryConsume(int|string ...$kind): ?Token
1✔
83
        {
84
                $token = $this->peek();
1✔
85
                if (!$token->is(...$kind)) {
1✔
86
                        return null;
1✔
87
                } elseif (!$token->isEnd()) {
1✔
88
                        $this->index++;
1✔
89
                }
90
                return $token;
1✔
91
        }
92

93

94
        /**
95
         * Sets the input cursor to the position.
96
         */
97
        public function seek(int $index): void
1✔
98
        {
99
                if ($index >= count($this->tokens) || $index < 0) {
1✔
100
                        throw new \InvalidArgumentException('The position is out of range.');
1✔
101
                }
102
                $this->index = $index;
1✔
103
        }
1✔
104

105

106
        /**
107
         * Returns the cursor position.
108
         */
109
        public function getIndex(): int
110
        {
111
                return $this->index;
1✔
112
        }
113

114

115
        /**
116
         * @throws CompileException
117
         * @param  string[]  $expected
118
         */
119
        public function throwUnexpectedException(array $expected = [], string $addendum = '', string $excerpt = ''): never
1✔
120
        {
121
                $token = $this->peek()->text . $excerpt;
1✔
122
                $expected = array_map(fn($item) => is_int($item) ? Token::Names[$item] : $item, $expected);
1✔
123
                throw new CompileException(
1✔
124
                        'Unexpected '
125
                        . ($token === ''
1✔
126
                                ? 'end'
1✔
127
                                : "'" . trim($token, "\n") . "'")
1✔
128
                        . ($expected && count($expected) < 5
1✔
129
                                ? ', expecting ' . implode(', ', $expected)
1✔
130
                                : '')
1✔
131
                        . $addendum,
1✔
132
                        $this->peek()->position,
1✔
133
                );
UNCOV
134
        }
×
135
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc