UNPKG

6.16 kBJavaScriptView Raw
1
2
3import { TokenType as tt} from "./parser/tokenizer/types";
4
5
6
7
8
9
10export default class TokenProcessor {
11 __init() {this.resultCode = ""}
12 __init2() {this.tokenIndex = 0}
13
14 constructor(
15 code,
16 tokens,
17 isFlowEnabled,
18 ) {;this.code = code;this.tokens = tokens;this.isFlowEnabled = isFlowEnabled;TokenProcessor.prototype.__init.call(this);TokenProcessor.prototype.__init2.call(this);}
19
20 /**
21 * Make a new TokenProcessor for things like lookahead.
22 */
23 snapshot() {
24 return {resultCode: this.resultCode, tokenIndex: this.tokenIndex};
25 }
26
27 restoreToSnapshot(snapshot) {
28 this.resultCode = snapshot.resultCode;
29 this.tokenIndex = snapshot.tokenIndex;
30 }
31
32 getResultCodeIndex() {
33 return this.resultCode.length;
34 }
35
36 reset() {
37 this.resultCode = "";
38 this.tokenIndex = 0;
39 }
40
41 matchesContextualAtIndex(index, contextualKeyword) {
42 return (
43 this.matches1AtIndex(index, tt.name) &&
44 this.tokens[index].contextualKeyword === contextualKeyword
45 );
46 }
47
48 identifierNameAtIndex(index) {
49 // TODO: We need to process escapes since technically you can have unicode escapes in variable
50 // names.
51 return this.identifierNameForToken(this.tokens[index]);
52 }
53
54 identifierName() {
55 return this.identifierNameForToken(this.currentToken());
56 }
57
58 identifierNameForToken(token) {
59 return this.code.slice(token.start, token.end);
60 }
61
62 stringValueAtIndex(index) {
63 return this.stringValueForToken(this.tokens[index]);
64 }
65
66 stringValue() {
67 return this.stringValueForToken(this.currentToken());
68 }
69
70 stringValueForToken(token) {
71 // This is used to identify when two imports are the same and to resolve TypeScript enum keys.
72 // Ideally we'd process escapes within the strings, but for now we pretty much take the raw
73 // code.
74 return this.code.slice(token.start + 1, token.end - 1);
75 }
76
77 matches1AtIndex(index, t1) {
78 return this.tokens[index].type === t1;
79 }
80
81 matches2AtIndex(index, t1, t2) {
82 return this.tokens[index].type === t1 && this.tokens[index + 1].type === t2;
83 }
84
85 matches3AtIndex(index, t1, t2, t3) {
86 return (
87 this.tokens[index].type === t1 &&
88 this.tokens[index + 1].type === t2 &&
89 this.tokens[index + 2].type === t3
90 );
91 }
92
93 matches1(t1) {
94 return this.tokens[this.tokenIndex].type === t1;
95 }
96
97 matches2(t1, t2) {
98 return this.tokens[this.tokenIndex].type === t1 && this.tokens[this.tokenIndex + 1].type === t2;
99 }
100
101 matches3(t1, t2, t3) {
102 return (
103 this.tokens[this.tokenIndex].type === t1 &&
104 this.tokens[this.tokenIndex + 1].type === t2 &&
105 this.tokens[this.tokenIndex + 2].type === t3
106 );
107 }
108
109 matches4(t1, t2, t3, t4) {
110 return (
111 this.tokens[this.tokenIndex].type === t1 &&
112 this.tokens[this.tokenIndex + 1].type === t2 &&
113 this.tokens[this.tokenIndex + 2].type === t3 &&
114 this.tokens[this.tokenIndex + 3].type === t4
115 );
116 }
117
118 matches5(t1, t2, t3, t4, t5) {
119 return (
120 this.tokens[this.tokenIndex].type === t1 &&
121 this.tokens[this.tokenIndex + 1].type === t2 &&
122 this.tokens[this.tokenIndex + 2].type === t3 &&
123 this.tokens[this.tokenIndex + 3].type === t4 &&
124 this.tokens[this.tokenIndex + 4].type === t5
125 );
126 }
127
128 matchesContextual(contextualKeyword) {
129 return this.matchesContextualAtIndex(this.tokenIndex, contextualKeyword);
130 }
131
132 matchesContextIdAndLabel(type, contextId) {
133 return this.matches1(type) && this.currentToken().contextId === contextId;
134 }
135
136 previousWhitespaceAndComments() {
137 let whitespaceAndComments = this.code.slice(
138 this.tokenIndex > 0 ? this.tokens[this.tokenIndex - 1].end : 0,
139 this.tokenIndex < this.tokens.length ? this.tokens[this.tokenIndex].start : this.code.length,
140 );
141 if (this.isFlowEnabled) {
142 whitespaceAndComments = whitespaceAndComments.replace(/@flow/g, "");
143 }
144 return whitespaceAndComments;
145 }
146
147 replaceToken(newCode) {
148 this.resultCode += this.previousWhitespaceAndComments();
149 this.resultCode += newCode;
150 this.tokenIndex++;
151 }
152
153 replaceTokenTrimmingLeftWhitespace(newCode) {
154 this.resultCode += this.previousWhitespaceAndComments().replace(/[^\r\n]/g, "");
155 this.resultCode += newCode;
156 this.tokenIndex++;
157 }
158
159 removeInitialToken() {
160 this.replaceToken("");
161 }
162
163 removeToken() {
164 this.replaceTokenTrimmingLeftWhitespace("");
165 }
166
167 copyExpectedToken(tokenType) {
168 if (this.tokens[this.tokenIndex].type !== tokenType) {
169 throw new Error(`Expected token ${tokenType}`);
170 }
171 this.copyToken();
172 }
173
174 copyToken() {
175 this.resultCode += this.previousWhitespaceAndComments();
176 this.resultCode += this.code.slice(
177 this.tokens[this.tokenIndex].start,
178 this.tokens[this.tokenIndex].end,
179 );
180 this.tokenIndex++;
181 }
182
183 copyTokenWithPrefix(prefix) {
184 this.resultCode += this.previousWhitespaceAndComments();
185 this.resultCode += prefix;
186 this.resultCode += this.code.slice(
187 this.tokens[this.tokenIndex].start,
188 this.tokens[this.tokenIndex].end,
189 );
190 this.tokenIndex++;
191 }
192
193 appendCode(code) {
194 this.resultCode += code;
195 }
196
197 currentToken() {
198 return this.tokens[this.tokenIndex];
199 }
200
201 currentTokenCode() {
202 const token = this.currentToken();
203 return this.code.slice(token.start, token.end);
204 }
205
206 tokenAtRelativeIndex(relativeIndex) {
207 return this.tokens[this.tokenIndex + relativeIndex];
208 }
209
210 currentIndex() {
211 return this.tokenIndex;
212 }
213
214 /**
215 * Move to the next token. Only suitable in preprocessing steps. When
216 * generating new code, you should use copyToken or removeToken.
217 */
218 nextToken() {
219 if (this.tokenIndex === this.tokens.length) {
220 throw new Error("Unexpectedly reached end of input.");
221 }
222 this.tokenIndex++;
223 }
224
225 previousToken() {
226 this.tokenIndex--;
227 }
228
229 finish() {
230 if (this.tokenIndex !== this.tokens.length) {
231 throw new Error("Tried to finish processing tokens before reaching the end.");
232 }
233 this.resultCode += this.previousWhitespaceAndComments();
234 return this.resultCode;
235 }
236
237 isAtEnd() {
238 return this.tokenIndex === this.tokens.length;
239 }
240}