UNPKG

7.13 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.TokenReader = void 0;
4var Token_1 = require("./Token");
5var TokenSequence_1 = require("./TokenSequence");
6/**
7 * Manages a stream of tokens that are read by the parser.
8 *
9 * @remarks
10 * Use TokenReader.readToken() to read a token and advance the stream pointer.
11 * Use TokenReader.peekToken() to preview the next token.
12 * Use TokenReader.createMarker() and backtrackToMarker() to rewind to an earlier point.
13 * Whenever readToken() is called, the token is added to an accumulated TokenSequence
14 * that can be extracted by calling extractAccumulatedSequence().
15 */
16var TokenReader = /** @class */ (function () {
17 function TokenReader(parserContext, embeddedTokenSequence) {
18 this._parserContext = parserContext;
19 this.tokens = parserContext.tokens;
20 if (embeddedTokenSequence) {
21 if (embeddedTokenSequence.parserContext !== this._parserContext) {
22 throw new Error('The embeddedTokenSequence must use the same parser context');
23 }
24 this._readerStartIndex = embeddedTokenSequence.startIndex;
25 this._readerEndIndex = embeddedTokenSequence.endIndex;
26 }
27 else {
28 this._readerStartIndex = 0;
29 this._readerEndIndex = this.tokens.length;
30 }
31 this._currentIndex = this._readerStartIndex;
32 this._accumulatedStartIndex = this._readerStartIndex;
33 }
34 /**
35 * Extracts and returns the TokenSequence that was accumulated so far by calls to readToken().
36 * The next call to readToken() will start a new accumulated sequence.
37 */
38 TokenReader.prototype.extractAccumulatedSequence = function () {
39 if (this._accumulatedStartIndex === this._currentIndex) {
40 // If this happens, it indicates a parser bug:
41 throw new Error('Parser assertion failed: The queue should not be empty when' +
42 ' extractAccumulatedSequence() is called');
43 }
44 var sequence = new TokenSequence_1.TokenSequence({
45 parserContext: this._parserContext,
46 startIndex: this._accumulatedStartIndex,
47 endIndex: this._currentIndex
48 });
49 this._accumulatedStartIndex = this._currentIndex;
50 return sequence;
51 };
52 /**
53 * Returns true if the accumulated sequence has any tokens yet. This will be false
54 * when the TokenReader starts, and it will be false immediately after a call
55 * to extractAccumulatedSequence(). Otherwise, it will become true whenever readToken()
56 * is called.
57 */
58 TokenReader.prototype.isAccumulatedSequenceEmpty = function () {
59 return this._accumulatedStartIndex === this._currentIndex;
60 };
61 /**
62 * Like extractAccumulatedSequence(), but returns undefined if nothing has been
63 * accumulated yet.
64 */
65 TokenReader.prototype.tryExtractAccumulatedSequence = function () {
66 if (this.isAccumulatedSequenceEmpty()) {
67 return undefined;
68 }
69 return this.extractAccumulatedSequence();
70 };
71 /**
72 * Asserts that isAccumulatedSequenceEmpty() should return false. If not, an exception
73 * is throw indicating a parser bug.
74 */
75 TokenReader.prototype.assertAccumulatedSequenceIsEmpty = function () {
76 if (!this.isAccumulatedSequenceEmpty()) {
77 // If this happens, it indicates a parser bug:
78 var sequence = new TokenSequence_1.TokenSequence({
79 parserContext: this._parserContext,
80 startIndex: this._accumulatedStartIndex,
81 endIndex: this._currentIndex
82 });
83 var tokenStrings = sequence.tokens.map(function (x) { return x.toString(); });
84 throw new Error('Parser assertion failed: The queue should be empty, but it contains:\n' +
85 JSON.stringify(tokenStrings));
86 }
87 };
88 /**
89 * Returns the next token that would be returned by _readToken(), without
90 * consuming anything.
91 */
92 TokenReader.prototype.peekToken = function () {
93 return this.tokens[this._currentIndex];
94 };
95 /**
96 * Returns the TokenKind for the next token that would be returned by _readToken(), without
97 * consuming anything.
98 */
99 TokenReader.prototype.peekTokenKind = function () {
100 if (this._currentIndex >= this._readerEndIndex) {
101 return Token_1.TokenKind.EndOfInput;
102 }
103 return this.tokens[this._currentIndex].kind;
104 };
105 /**
106 * Like peekTokenKind(), but looks ahead two tokens.
107 */
108 TokenReader.prototype.peekTokenAfterKind = function () {
109 if (this._currentIndex + 1 >= this._readerEndIndex) {
110 return Token_1.TokenKind.EndOfInput;
111 }
112 return this.tokens[this._currentIndex + 1].kind;
113 };
114 /**
115 * Like peekTokenKind(), but looks ahead three tokens.
116 */
117 TokenReader.prototype.peekTokenAfterAfterKind = function () {
118 if (this._currentIndex + 2 >= this._readerEndIndex) {
119 return Token_1.TokenKind.EndOfInput;
120 }
121 return this.tokens[this._currentIndex + 2].kind;
122 };
123 /**
124 * Extract the next token from the input stream and return it.
125 * The token will also be appended to the accumulated sequence, which can
126 * later be accessed via extractAccumulatedSequence().
127 */
128 TokenReader.prototype.readToken = function () {
129 if (this._currentIndex >= this._readerEndIndex) {
130 // If this happens, it's a parser bug
131 throw new Error('Cannot read past end of stream');
132 }
133 var token = this.tokens[this._currentIndex];
134 if (token.kind === Token_1.TokenKind.EndOfInput) {
135 // We don't allow reading the EndOfInput token, because we want _peekToken()
136 // to be always guaranteed to return a valid result.
137 // If this happens, it's a parser bug
138 throw new Error('The EndOfInput token cannot be read');
139 }
140 this._currentIndex++;
141 return token;
142 };
143 /**
144 * Returns the kind of the token immediately before the current token.
145 */
146 TokenReader.prototype.peekPreviousTokenKind = function () {
147 if (this._currentIndex === 0) {
148 return Token_1.TokenKind.EndOfInput;
149 }
150 return this.tokens[this._currentIndex - 1].kind;
151 };
152 /**
153 * Remembers the current position in the stream.
154 */
155 TokenReader.prototype.createMarker = function () {
156 return this._currentIndex;
157 };
158 /**
159 * Rewinds the stream pointer to a previous position in the stream.
160 */
161 TokenReader.prototype.backtrackToMarker = function (marker) {
162 if (marker > this._currentIndex) {
163 // If this happens, it's a parser bug
164 throw new Error('The marker has expired');
165 }
166 this._currentIndex = marker;
167 if (marker < this._accumulatedStartIndex) {
168 this._accumulatedStartIndex = marker;
169 }
170 };
171 return TokenReader;
172}());
173exports.TokenReader = TokenReader;
174//# sourceMappingURL=TokenReader.js.map
\No newline at end of file