xbintsc 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +191 -0
  3. package/bin/xbintsc.js +26 -0
  4. package/dist/src/ast/factory.d.ts +11 -0
  5. package/dist/src/ast/factory.js +36 -0
  6. package/dist/src/ast/factory.js.map +1 -0
  7. package/dist/src/ast/nodes.d.ts +848 -0
  8. package/dist/src/ast/nodes.js +247 -0
  9. package/dist/src/ast/nodes.js.map +1 -0
  10. package/dist/src/ast/visitor.d.ts +18 -0
  11. package/dist/src/ast/visitor.js +52 -0
  12. package/dist/src/ast/visitor.js.map +1 -0
  13. package/dist/src/binder/binder.d.ts +82 -0
  14. package/dist/src/binder/binder.js +443 -0
  15. package/dist/src/binder/binder.js.map +1 -0
  16. package/dist/src/cli/main.d.ts +16 -0
  17. package/dist/src/cli/main.js +191 -0
  18. package/dist/src/cli/main.js.map +1 -0
  19. package/dist/src/codegen/llvm.d.ts +31 -0
  20. package/dist/src/codegen/llvm.js +1178 -0
  21. package/dist/src/codegen/llvm.js.map +1 -0
  22. package/dist/src/codegen/values.d.ts +23 -0
  23. package/dist/src/codegen/values.js +32 -0
  24. package/dist/src/codegen/values.js.map +1 -0
  25. package/dist/src/diagnostics/diagnostic.d.ts +69 -0
  26. package/dist/src/diagnostics/diagnostic.js +104 -0
  27. package/dist/src/diagnostics/diagnostic.js.map +1 -0
  28. package/dist/src/diagnostics/source.d.ts +43 -0
  29. package/dist/src/diagnostics/source.js +73 -0
  30. package/dist/src/diagnostics/source.js.map +1 -0
  31. package/dist/src/driver/cache.d.ts +37 -0
  32. package/dist/src/driver/cache.js +82 -0
  33. package/dist/src/driver/cache.js.map +1 -0
  34. package/dist/src/driver/compiler.d.ts +41 -0
  35. package/dist/src/driver/compiler.js +128 -0
  36. package/dist/src/driver/compiler.js.map +1 -0
  37. package/dist/src/driver/index.d.ts +4 -0
  38. package/dist/src/driver/index.js +5 -0
  39. package/dist/src/driver/index.js.map +1 -0
  40. package/dist/src/driver/paths.d.ts +4 -0
  41. package/dist/src/driver/paths.js +22 -0
  42. package/dist/src/driver/paths.js.map +1 -0
  43. package/dist/src/driver/toolchain.d.ts +43 -0
  44. package/dist/src/driver/toolchain.js +76 -0
  45. package/dist/src/driver/toolchain.js.map +1 -0
  46. package/dist/src/extensions/node.d.ts +9 -0
  47. package/dist/src/extensions/node.js +20 -0
  48. package/dist/src/extensions/node.js.map +1 -0
  49. package/dist/src/extensions/registry.d.ts +45 -0
  50. package/dist/src/extensions/registry.js +76 -0
  51. package/dist/src/extensions/registry.js.map +1 -0
  52. package/dist/src/index.d.ts +18 -0
  53. package/dist/src/index.js +19 -0
  54. package/dist/src/index.js.map +1 -0
  55. package/dist/src/lexer/scanner.d.ts +48 -0
  56. package/dist/src/lexer/scanner.js +650 -0
  57. package/dist/src/lexer/scanner.js.map +1 -0
  58. package/dist/src/lexer/token.d.ts +170 -0
  59. package/dist/src/lexer/token.js +250 -0
  60. package/dist/src/lexer/token.js.map +1 -0
  61. package/dist/src/parser/parser.d.ts +127 -0
  62. package/dist/src/parser/parser.js +2334 -0
  63. package/dist/src/parser/parser.js.map +1 -0
  64. package/dist/tests/binder/binder.test.d.ts +1 -0
  65. package/dist/tests/binder/binder.test.js +89 -0
  66. package/dist/tests/binder/binder.test.js.map +1 -0
  67. package/dist/tests/cli/main.test.d.ts +1 -0
  68. package/dist/tests/cli/main.test.js +68 -0
  69. package/dist/tests/cli/main.test.js.map +1 -0
  70. package/dist/tests/cli/process.test.d.ts +9 -0
  71. package/dist/tests/cli/process.test.js +57 -0
  72. package/dist/tests/cli/process.test.js.map +1 -0
  73. package/dist/tests/codegen/llvm.test.d.ts +1 -0
  74. package/dist/tests/codegen/llvm.test.js +93 -0
  75. package/dist/tests/codegen/llvm.test.js.map +1 -0
  76. package/dist/tests/driver/cache.test.d.ts +1 -0
  77. package/dist/tests/driver/cache.test.js +66 -0
  78. package/dist/tests/driver/cache.test.js.map +1 -0
  79. package/dist/tests/driver/compiler.test.d.ts +1 -0
  80. package/dist/tests/driver/compiler.test.js +80 -0
  81. package/dist/tests/driver/compiler.test.js.map +1 -0
  82. package/dist/tests/driver/toolchain.test.d.ts +1 -0
  83. package/dist/tests/driver/toolchain.test.js +60 -0
  84. package/dist/tests/driver/toolchain.test.js.map +1 -0
  85. package/dist/tests/e2e/compile.test.d.ts +5 -0
  86. package/dist/tests/e2e/compile.test.js +93 -0
  87. package/dist/tests/e2e/compile.test.js.map +1 -0
  88. package/dist/tests/extensions/registry.test.d.ts +1 -0
  89. package/dist/tests/extensions/registry.test.js +47 -0
  90. package/dist/tests/extensions/registry.test.js.map +1 -0
  91. package/dist/tests/helpers.d.ts +23 -0
  92. package/dist/tests/helpers.js +41 -0
  93. package/dist/tests/helpers.js.map +1 -0
  94. package/dist/tests/lexer/scanner.test.d.ts +1 -0
  95. package/dist/tests/lexer/scanner.test.js +95 -0
  96. package/dist/tests/lexer/scanner.test.js.map +1 -0
  97. package/dist/tests/parser/parser.test.d.ts +1 -0
  98. package/dist/tests/parser/parser.test.js +137 -0
  99. package/dist/tests/parser/parser.test.js.map +1 -0
  100. package/package.json +49 -0
  101. package/runtime/ext_node.c +42 -0
  102. package/runtime/rt.h +177 -0
  103. package/runtime/xt_runtime.c +682 -0
  104. package/scripts/build-runtime.mjs +34 -0
  105. package/src/ast/factory.ts +37 -0
  106. package/src/ast/nodes.ts +1111 -0
  107. package/src/ast/visitor.ts +60 -0
  108. package/src/binder/binder.ts +549 -0
  109. package/src/cli/main.ts +210 -0
  110. package/src/codegen/llvm.ts +1324 -0
  111. package/src/codegen/values.ts +36 -0
  112. package/src/diagnostics/diagnostic.ts +132 -0
  113. package/src/diagnostics/source.ts +97 -0
  114. package/src/driver/cache.ts +96 -0
  115. package/src/driver/compiler.ts +197 -0
  116. package/src/driver/index.ts +4 -0
  117. package/src/driver/paths.ts +24 -0
  118. package/src/driver/toolchain.ts +103 -0
  119. package/src/extensions/node.ts +23 -0
  120. package/src/extensions/registry.ts +101 -0
  121. package/src/index.ts +33 -0
  122. package/src/lexer/scanner.ts +650 -0
  123. package/src/lexer/token.ts +266 -0
  124. package/src/parser/parser.ts +2396 -0
@@ -0,0 +1,650 @@
1
+ import { DiagnosticCode } from "../diagnostics/diagnostic.js";
2
+ import { KEYWORDS, TokenKind } from "./token.js";
3
+ var Char;
4
+ (function (Char) {
5
+ Char[Char["Null"] = 0] = "Null";
6
+ Char[Char["Tab"] = 9] = "Tab";
7
+ Char[Char["LineFeed"] = 10] = "LineFeed";
8
+ Char[Char["VerticalTab"] = 11] = "VerticalTab";
9
+ Char[Char["FormFeed"] = 12] = "FormFeed";
10
+ Char[Char["CarriageReturn"] = 13] = "CarriageReturn";
11
+ Char[Char["Space"] = 32] = "Space";
12
+ Char[Char["Exclamation"] = 33] = "Exclamation";
13
+ Char[Char["DoubleQuote"] = 34] = "DoubleQuote";
14
+ Char[Char["Hash"] = 35] = "Hash";
15
+ Char[Char["Dollar"] = 36] = "Dollar";
16
+ Char[Char["Percent"] = 37] = "Percent";
17
+ Char[Char["Ampersand"] = 38] = "Ampersand";
18
+ Char[Char["SingleQuote"] = 39] = "SingleQuote";
19
+ Char[Char["OpenParen"] = 40] = "OpenParen";
20
+ Char[Char["CloseParen"] = 41] = "CloseParen";
21
+ Char[Char["Asterisk"] = 42] = "Asterisk";
22
+ Char[Char["Plus"] = 43] = "Plus";
23
+ Char[Char["Comma"] = 44] = "Comma";
24
+ Char[Char["Minus"] = 45] = "Minus";
25
+ Char[Char["Dot"] = 46] = "Dot";
26
+ Char[Char["Slash"] = 47] = "Slash";
27
+ Char[Char["Zero"] = 48] = "Zero";
28
+ Char[Char["Nine"] = 57] = "Nine";
29
+ Char[Char["Colon"] = 58] = "Colon";
30
+ Char[Char["Semicolon"] = 59] = "Semicolon";
31
+ Char[Char["LessThan"] = 60] = "LessThan";
32
+ Char[Char["Equals"] = 61] = "Equals";
33
+ Char[Char["GreaterThan"] = 62] = "GreaterThan";
34
+ Char[Char["Question"] = 63] = "Question";
35
+ Char[Char["At"] = 64] = "At";
36
+ Char[Char["UpperA"] = 65] = "UpperA";
37
+ Char[Char["UpperB"] = 66] = "UpperB";
38
+ Char[Char["UpperE"] = 69] = "UpperE";
39
+ Char[Char["UpperF"] = 70] = "UpperF";
40
+ Char[Char["UpperO"] = 79] = "UpperO";
41
+ Char[Char["UpperX"] = 88] = "UpperX";
42
+ Char[Char["UpperZ"] = 90] = "UpperZ";
43
+ Char[Char["OpenBracket"] = 91] = "OpenBracket";
44
+ Char[Char["Backslash"] = 92] = "Backslash";
45
+ Char[Char["CloseBracket"] = 93] = "CloseBracket";
46
+ Char[Char["Caret"] = 94] = "Caret";
47
+ Char[Char["Underscore"] = 95] = "Underscore";
48
+ Char[Char["Backtick"] = 96] = "Backtick";
49
+ Char[Char["LowerA"] = 97] = "LowerA";
50
+ Char[Char["LowerB"] = 98] = "LowerB";
51
+ Char[Char["LowerE"] = 101] = "LowerE";
52
+ Char[Char["LowerF"] = 102] = "LowerF";
53
+ Char[Char["LowerN"] = 110] = "LowerN";
54
+ Char[Char["LowerO"] = 111] = "LowerO";
55
+ Char[Char["LowerR"] = 114] = "LowerR";
56
+ Char[Char["LowerT"] = 116] = "LowerT";
57
+ Char[Char["LowerU"] = 117] = "LowerU";
58
+ Char[Char["LowerX"] = 120] = "LowerX";
59
+ Char[Char["LowerZ"] = 122] = "LowerZ";
60
+ Char[Char["OpenBrace"] = 123] = "OpenBrace";
61
+ Char[Char["Bar"] = 124] = "Bar";
62
+ Char[Char["CloseBrace"] = 125] = "CloseBrace";
63
+ Char[Char["Tilde"] = 126] = "Tilde";
64
+ Char[Char["NonBreakingSpace"] = 160] = "NonBreakingSpace";
65
+ Char[Char["LineSeparator"] = 8232] = "LineSeparator";
66
+ Char[Char["ParagraphSeparator"] = 8233] = "ParagraphSeparator";
67
+ Char[Char["ByteOrderMark"] = 65279] = "ByteOrderMark";
68
+ })(Char || (Char = {}));
69
+ function isLineBreak(ch) {
70
+ return ch === Char.LineFeed || ch === Char.CarriageReturn || ch === Char.LineSeparator || ch === Char.ParagraphSeparator;
71
+ }
72
+ function isWhiteSpace(ch) {
73
+ return (ch === Char.Space ||
74
+ ch === Char.Tab ||
75
+ ch === Char.VerticalTab ||
76
+ ch === Char.FormFeed ||
77
+ ch === Char.NonBreakingSpace ||
78
+ ch === Char.ByteOrderMark ||
79
+ (ch > 0x1680 && WHITESPACE_UNICODE.has(ch)));
80
+ }
81
+ const WHITESPACE_UNICODE = new Set([
82
+ 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x202f, 0x205f,
83
+ 0x3000,
84
+ ]);
85
+ function isDigit(ch) {
86
+ return ch >= Char.Zero && ch <= Char.Nine;
87
+ }
88
+ function isHexDigit(ch) {
89
+ return isDigit(ch) || (ch >= Char.LowerA && ch <= Char.LowerF) || (ch >= Char.UpperA && ch <= Char.UpperF);
90
+ }
91
+ function isIdentifierStart(ch) {
92
+ return ((ch >= Char.LowerA && ch <= Char.LowerZ) ||
93
+ (ch >= Char.UpperA && ch <= Char.UpperZ) ||
94
+ ch === Char.Dollar ||
95
+ ch === Char.Underscore ||
96
+ ch > 0x7f);
97
+ }
98
+ function isIdentifierPart(ch) {
99
+ return isIdentifierStart(ch) || isDigit(ch) || ch === Char.Backslash || ch > 0x7f;
100
+ }
101
+ /**
102
+ * Hand-written scanner for the TypeScript language. It produces a flat token
103
+ * stream consumed by the parser. Comments and trivia are skipped, but line
104
+ * breaks are tracked so the parser can implement ASI (automatic semicolon
105
+ * insertion) correctly.
106
+ */
107
+ export class Scanner {
108
+ text;
109
+ pos = 0;
110
+ diagnostics;
111
+ source;
112
+ _token = {
113
+ kind: TokenKind.EndOfFile,
114
+ start: 0,
115
+ end: 0,
116
+ text: "",
117
+ precededByLineBreak: false,
118
+ };
119
+ constructor(source, diagnostics) {
120
+ this.source = source;
121
+ this.text = source.text;
122
+ this.diagnostics = diagnostics;
123
+ }
124
+ get token() {
125
+ return this._token;
126
+ }
127
+ get position() {
128
+ return this.pos;
129
+ }
130
+ /**
131
+ * Reset the scanner read head. Used by the parser to re-scan the `}` that
132
+ * terminates a template substitution as template text instead of a brace.
133
+ */
134
+ seek(offset) {
135
+ this.pos = Math.max(0, Math.min(offset, this.text.length));
136
+ }
137
+ /** Advance to the next token. */
138
+ nextToken() {
139
+ this._token = this.scan();
140
+ return this._token;
141
+ }
142
+ /** Scan everything, useful for lexer tests. */
143
+ tokenize() {
144
+ const tokens = [];
145
+ for (;;) {
146
+ const token = this.nextToken();
147
+ tokens.push(token);
148
+ if (token.kind === TokenKind.EndOfFile)
149
+ break;
150
+ }
151
+ return tokens;
152
+ }
153
+ error(code, message, start, end = this.pos) {
154
+ this.diagnostics.error(code, message, { start, end }, this.source.fileName);
155
+ }
156
+ scan() {
157
+ let precededByLineBreak = false;
158
+ // Skip trivia.
159
+ for (;;) {
160
+ const ch = this.text.charCodeAt(this.pos);
161
+ if (Number.isNaN(ch))
162
+ break; // EOF
163
+ if (ch === Char.LineFeed || ch === Char.CarriageReturn) {
164
+ precededByLineBreak = true;
165
+ this.pos++;
166
+ continue;
167
+ }
168
+ if (isLineBreak(ch)) {
169
+ precededByLineBreak = true;
170
+ this.pos++;
171
+ continue;
172
+ }
173
+ if (isWhiteSpace(ch)) {
174
+ this.pos++;
175
+ continue;
176
+ }
177
+ if (ch === Char.Slash && this.text.charCodeAt(this.pos + 1) === Char.Slash) {
178
+ this.pos += 2;
179
+ while (this.pos < this.text.length && !isLineBreak(this.text.charCodeAt(this.pos)))
180
+ this.pos++;
181
+ continue;
182
+ }
183
+ if (ch === Char.Slash && this.text.charCodeAt(this.pos + 1) === Char.Asterisk) {
184
+ const start = this.pos;
185
+ this.pos += 2;
186
+ let closed = false;
187
+ while (this.pos < this.text.length) {
188
+ if (this.text.charCodeAt(this.pos) === Char.Asterisk && this.text.charCodeAt(this.pos + 1) === Char.Slash) {
189
+ this.pos += 2;
190
+ closed = true;
191
+ break;
192
+ }
193
+ if (isLineBreak(this.text.charCodeAt(this.pos)))
194
+ precededByLineBreak = true;
195
+ this.pos++;
196
+ }
197
+ if (!closed)
198
+ this.error(DiagnosticCode.UnterminatedComment, "Unterminated block comment", start);
199
+ continue;
200
+ }
201
+ break;
202
+ }
203
+ const start = this.pos;
204
+ const ch = this.text.charCodeAt(this.pos);
205
+ if (Number.isNaN(ch)) {
206
+ return this.makeToken(TokenKind.EndOfFile, start, start, "", precededByLineBreak);
207
+ }
208
+ // Identifiers / keywords.
209
+ if (isIdentifierStart(ch)) {
210
+ return this.scanIdentifier(start, precededByLineBreak);
211
+ }
212
+ // Numeric literals.
213
+ if (isDigit(ch)) {
214
+ return this.scanNumber(start, precededByLineBreak);
215
+ }
216
+ if (ch === Char.Dot && isDigit(this.text.charCodeAt(this.pos + 1))) {
217
+ return this.scanNumber(start, precededByLineBreak);
218
+ }
219
+ // String literals.
220
+ if (ch === Char.SingleQuote || ch === Char.DoubleQuote) {
221
+ return this.scanString(start, precededByLineBreak, ch);
222
+ }
223
+ // Template literals.
224
+ if (ch === Char.Backtick) {
225
+ return this.scanTemplate(start, precededByLineBreak, /* isHead */ true);
226
+ }
227
+ if (ch === Char.Hash) {
228
+ this.pos++;
229
+ const name = this.scanIdentifier(this.pos, precededByLineBreak);
230
+ return this.makeToken(TokenKind.PrivateIdentifier, start, name.end, this.text.slice(start, name.end), precededByLineBreak);
231
+ }
232
+ return this.scanPunctuation(start, precededByLineBreak);
233
+ }
234
+ makeToken(kind, start, end, text, precededByLineBreak, value) {
235
+ return { kind, start, end, text, value, precededByLineBreak };
236
+ }
237
+ scanIdentifier(start, precededByLineBreak) {
238
+ this.pos++;
239
+ while (this.pos < this.text.length) {
240
+ const ch = this.text.charCodeAt(this.pos);
241
+ if (isIdentifierPart(ch)) {
242
+ this.pos++;
243
+ }
244
+ else if (ch === Char.Backslash && this.text.charCodeAt(this.pos + 1) === Char.LowerU) {
245
+ this.pos += 2;
246
+ const hex = this.text.slice(this.pos, this.pos + 4);
247
+ this.pos += 4;
248
+ if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
249
+ this.error(DiagnosticCode.InvalidEscape, "Invalid unicode escape in identifier", this.pos - 4, this.pos);
250
+ }
251
+ }
252
+ else {
253
+ break;
254
+ }
255
+ }
256
+ const text = this.text.slice(start, this.pos);
257
+ const keyword = KEYWORDS.get(text);
258
+ const kind = keyword ?? TokenKind.Identifier;
259
+ return this.makeToken(kind, start, this.pos, text, precededByLineBreak);
260
+ }
261
+ scanNumber(start, precededByLineBreak) {
262
+ const text = this.text;
263
+ let isBigInt = false;
264
+ // Radix prefixes.
265
+ if (text.charCodeAt(this.pos) === Char.Zero) {
266
+ const next = text.charCodeAt(this.pos + 1);
267
+ if (next === Char.LowerX || next === Char.UpperX) {
268
+ this.pos += 2;
269
+ while (isHexDigit(text.charCodeAt(this.pos)) || text.charCodeAt(this.pos) === Char.Underscore)
270
+ this.pos++;
271
+ isBigInt = text.charCodeAt(this.pos) === Char.LowerN;
272
+ if (isBigInt)
273
+ this.pos++;
274
+ return this.finishNumber(start, precededByLineBreak, isBigInt);
275
+ }
276
+ if (next === Char.LowerO || next === Char.UpperO || next === Char.LowerB || next === Char.UpperB) {
277
+ this.pos += 2;
278
+ while (isDigit(text.charCodeAt(this.pos)) || text.charCodeAt(this.pos) === Char.Underscore)
279
+ this.pos++;
280
+ isBigInt = text.charCodeAt(this.pos) === Char.LowerN;
281
+ if (isBigInt)
282
+ this.pos++;
283
+ return this.finishNumber(start, precededByLineBreak, isBigInt);
284
+ }
285
+ }
286
+ while (isDigit(text.charCodeAt(this.pos)) || text.charCodeAt(this.pos) === Char.Underscore)
287
+ this.pos++;
288
+ if (text.charCodeAt(this.pos) === Char.Dot) {
289
+ this.pos++;
290
+ while (isDigit(text.charCodeAt(this.pos)) || text.charCodeAt(this.pos) === Char.Underscore)
291
+ this.pos++;
292
+ }
293
+ const e = text.charCodeAt(this.pos);
294
+ if (e === Char.LowerE || e === Char.UpperE) {
295
+ const save = this.pos;
296
+ this.pos++;
297
+ const sign = text.charCodeAt(this.pos);
298
+ if (sign === Char.Plus || sign === Char.Minus)
299
+ this.pos++;
300
+ if (isDigit(text.charCodeAt(this.pos))) {
301
+ while (isDigit(text.charCodeAt(this.pos)) || text.charCodeAt(this.pos) === Char.Underscore)
302
+ this.pos++;
303
+ }
304
+ else {
305
+ // Not an exponent, roll back.
306
+ this.pos = save;
307
+ }
308
+ }
309
+ isBigInt = text.charCodeAt(this.pos) === Char.LowerN;
310
+ if (isBigInt)
311
+ this.pos++;
312
+ return this.finishNumber(start, precededByLineBreak, isBigInt);
313
+ }
314
+ finishNumber(start, precededByLineBreak, isBigInt) {
315
+ let raw = this.text.slice(start, this.pos);
316
+ const cleaned = raw.replace(/_/g, "");
317
+ if (isBigInt) {
318
+ raw = raw.slice(0, -1).replace(/_/g, "");
319
+ try {
320
+ return this.makeToken(TokenKind.BigIntLiteral, start, this.pos, raw, precededByLineBreak, BigInt(raw));
321
+ }
322
+ catch {
323
+ this.error(DiagnosticCode.InvalidNumber, `Invalid BigInt literal '${raw}'`, start, this.pos);
324
+ return this.makeToken(TokenKind.BigIntLiteral, start, this.pos, raw, precededByLineBreak, 0n);
325
+ }
326
+ }
327
+ let value;
328
+ if (/^0[xX]/.test(cleaned))
329
+ value = parseInt(cleaned.slice(2), 16);
330
+ else if (/^0[oO]/.test(cleaned))
331
+ value = parseInt(cleaned.slice(2), 8);
332
+ else if (/^0[bB]/.test(cleaned))
333
+ value = parseInt(cleaned.slice(2), 2);
334
+ else
335
+ value = Number(cleaned);
336
+ if (Number.isNaN(value)) {
337
+ this.error(DiagnosticCode.InvalidNumber, `Invalid numeric literal '${raw}'`, start, this.pos);
338
+ value = 0;
339
+ }
340
+ return this.makeToken(TokenKind.NumericLiteral, start, this.pos, raw, precededByLineBreak, value);
341
+ }
342
+ scanString(start, precededByLineBreak, quote) {
343
+ this.pos++;
344
+ let result = "";
345
+ while (this.pos < this.text.length) {
346
+ const ch = this.text.charCodeAt(this.pos);
347
+ if (ch === quote) {
348
+ this.pos++;
349
+ return this.makeToken(TokenKind.StringLiteral, start, this.pos, this.text.slice(start, this.pos), precededByLineBreak, result);
350
+ }
351
+ if (ch === Char.Backslash) {
352
+ result += this.scanEscapeSequence();
353
+ continue;
354
+ }
355
+ if (isLineBreak(ch)) {
356
+ this.error(DiagnosticCode.UnterminatedString, "Unterminated string literal", start);
357
+ break;
358
+ }
359
+ result += this.text[this.pos];
360
+ this.pos++;
361
+ }
362
+ this.error(DiagnosticCode.UnterminatedString, "Unterminated string literal", start);
363
+ return this.makeToken(TokenKind.StringLiteral, start, this.pos, this.text.slice(start, this.pos), precededByLineBreak, result);
364
+ }
365
+ scanEscapeSequence() {
366
+ this.pos++; // backslash
367
+ const ch = this.text.charCodeAt(this.pos);
368
+ switch (ch) {
369
+ case Char.LowerN:
370
+ this.pos++;
371
+ return "\n";
372
+ case Char.LowerT:
373
+ this.pos++;
374
+ return "\t";
375
+ case Char.LowerR:
376
+ this.pos++;
377
+ return "\r";
378
+ case Char.LowerB:
379
+ this.pos++;
380
+ return "\b";
381
+ case Char.LowerF:
382
+ this.pos++;
383
+ return "\f";
384
+ case Char.LowerU:
385
+ this.pos++;
386
+ if (this.text.charCodeAt(this.pos) === Char.OpenBrace) {
387
+ const close = this.text.indexOf("}", this.pos);
388
+ const hex = this.text.slice(this.pos + 1, close);
389
+ this.pos = close + 1;
390
+ return String.fromCodePoint(parseInt(hex, 16) || 0);
391
+ }
392
+ else {
393
+ const hex = this.text.slice(this.pos, this.pos + 4);
394
+ this.pos += 4;
395
+ return String.fromCharCode(parseInt(hex, 16) || 0);
396
+ }
397
+ case Char.LowerX: {
398
+ const hex = this.text.slice(this.pos + 1, this.pos + 3);
399
+ this.pos += 3;
400
+ return String.fromCharCode(parseInt(hex, 16) || 0);
401
+ }
402
+ case Char.Zero:
403
+ // \0 is only a null escape when not followed by a digit.
404
+ if (!isDigit(this.text.charCodeAt(this.pos + 1))) {
405
+ this.pos++;
406
+ return "\0";
407
+ }
408
+ this.pos++;
409
+ return "\0";
410
+ default:
411
+ this.pos++;
412
+ return this.text[this.pos - 1] ?? "";
413
+ }
414
+ }
415
+ /** Scans a template literal chunk starting at a backtick or after `}`. */
416
+ scanTemplate(start, precededByLineBreak, isHead) {
417
+ if (isHead)
418
+ this.pos++; // opening backtick
419
+ let result = "";
420
+ for (;;) {
421
+ if (this.pos >= this.text.length) {
422
+ this.error(DiagnosticCode.UnterminatedTemplate, "Unterminated template literal", start);
423
+ return this.makeToken(TokenKind.NoSubstitutionTemplateLiteral, start, this.pos, this.text.slice(start, this.pos), precededByLineBreak, result);
424
+ }
425
+ const ch = this.text.charCodeAt(this.pos);
426
+ if (ch === Char.Backtick) {
427
+ this.pos++;
428
+ return this.makeToken(TokenKind.NoSubstitutionTemplateLiteral, start, this.pos, this.text.slice(start, this.pos), precededByLineBreak, result);
429
+ }
430
+ if (ch === Char.Dollar && this.text.charCodeAt(this.pos + 1) === Char.OpenBrace) {
431
+ this.pos += 2;
432
+ return this.makeToken(TokenKind.TemplateHead, start, this.pos, this.text.slice(start, this.pos), precededByLineBreak, result);
433
+ }
434
+ if (ch === Char.Backslash) {
435
+ result += this.scanEscapeSequence();
436
+ continue;
437
+ }
438
+ result += this.text[this.pos];
439
+ this.pos++;
440
+ }
441
+ }
442
+ /** Called by the parser after a template substitution expression. */
443
+ continueTemplate(offset) {
444
+ this.pos = Math.max(0, Math.min(offset, this.text.length));
445
+ this._token = this.scanTemplate(offset, false, /* isHead */ false);
446
+ return this._token;
447
+ }
448
+ /**
449
+ * True when a `/` in this position starts a regular expression rather than a
450
+ * division. The decision is made from the previous significant token.
451
+ */
452
+ regexAllowed() {
453
+ switch (this._token.kind) {
454
+ case TokenKind.Identifier:
455
+ case TokenKind.PrivateIdentifier:
456
+ case TokenKind.NumericLiteral:
457
+ case TokenKind.BigIntLiteral:
458
+ case TokenKind.StringLiteral:
459
+ case TokenKind.NoSubstitutionTemplateLiteral:
460
+ case TokenKind.TemplateTail:
461
+ case TokenKind.RegularExpressionLiteral:
462
+ case TokenKind.CloseParen:
463
+ case TokenKind.CloseBracket:
464
+ case TokenKind.TrueKeyword:
465
+ case TokenKind.FalseKeyword:
466
+ case TokenKind.NullKeyword:
467
+ case TokenKind.UndefinedKeyword:
468
+ case TokenKind.ThisKeyword:
469
+ case TokenKind.PlusPlus:
470
+ case TokenKind.MinusMinus:
471
+ return false;
472
+ default:
473
+ return true;
474
+ }
475
+ }
476
+ /** Scan a `/pattern/flags` literal, starting at the leading slash. */
477
+ scanRegex(start, precededByLineBreak) {
478
+ this.pos++; // opening slash
479
+ let inClass = false;
480
+ for (;;) {
481
+ if (this.pos >= this.text.length) {
482
+ this.error(DiagnosticCode.InvalidCharacter, "Unterminated regular expression", start);
483
+ break;
484
+ }
485
+ const ch = this.text.charCodeAt(this.pos);
486
+ if (ch === Char.Backslash) {
487
+ this.pos += 2;
488
+ continue;
489
+ }
490
+ if (ch === Char.LineFeed || ch === Char.CarriageReturn)
491
+ break;
492
+ if (ch === 91 /* [ */)
493
+ inClass = true;
494
+ else if (ch === 93 /* ] */)
495
+ inClass = false;
496
+ else if (ch === Char.Slash && !inClass) {
497
+ this.pos++;
498
+ break;
499
+ }
500
+ this.pos++;
501
+ }
502
+ // Flags.
503
+ while (this.pos < this.text.length && isIdentifierPart(this.text.charCodeAt(this.pos)))
504
+ this.pos++;
505
+ return this.makeToken(TokenKind.RegularExpressionLiteral, start, this.pos, this.text.slice(start, this.pos), precededByLineBreak);
506
+ }
507
+ scanPunctuation(start, precededByLineBreak) {
508
+ const text = this.text;
509
+ const ch = text.charCodeAt(this.pos);
510
+ const next = text.charCodeAt(this.pos + 1);
511
+ const third = text.charCodeAt(this.pos + 2);
512
+ const fourth = text.charCodeAt(this.pos + 3);
513
+ const emit = (kind, length) => {
514
+ this.pos += length;
515
+ return this.makeToken(kind, start, this.pos, text.slice(start, this.pos), precededByLineBreak);
516
+ };
517
+ switch (ch) {
518
+ case Char.OpenBrace:
519
+ return emit(TokenKind.OpenBrace, 1);
520
+ case Char.CloseBrace:
521
+ return emit(TokenKind.CloseBrace, 1);
522
+ case Char.OpenParen:
523
+ return emit(TokenKind.OpenParen, 1);
524
+ case Char.CloseParen:
525
+ return emit(TokenKind.CloseParen, 1);
526
+ case Char.OpenBracket:
527
+ return emit(TokenKind.OpenBracket, 1);
528
+ case Char.CloseBracket:
529
+ return emit(TokenKind.CloseBracket, 1);
530
+ case Char.Semicolon:
531
+ return emit(TokenKind.Semicolon, 1);
532
+ case Char.Comma:
533
+ return emit(TokenKind.Comma, 1);
534
+ case Char.At:
535
+ return emit(TokenKind.At, 1);
536
+ case Char.Tilde:
537
+ return emit(TokenKind.Tilde, 1);
538
+ case Char.Colon:
539
+ return emit(TokenKind.Colon, 1);
540
+ case Char.Dot:
541
+ if (next === Char.Dot && third === Char.Dot)
542
+ return emit(TokenKind.DotDotDot, 3);
543
+ return emit(TokenKind.Dot, 1);
544
+ case Char.Question:
545
+ if (next === Char.Question) {
546
+ if (third === Char.Equals)
547
+ return emit(TokenKind.QuestionQuestionEquals, 3);
548
+ return emit(TokenKind.QuestionQuestion, 2);
549
+ }
550
+ if (next === Char.Dot && !isDigit(third))
551
+ return emit(TokenKind.QuestionDot, 2);
552
+ return emit(TokenKind.Question, 1);
553
+ case Char.Equals:
554
+ if (next === Char.Equals && third === Char.Equals)
555
+ return emit(TokenKind.EqualsEqualsEquals, 3);
556
+ if (next === Char.Equals)
557
+ return emit(TokenKind.EqualsEquals, 2);
558
+ if (next === Char.GreaterThan)
559
+ return emit(TokenKind.EqualsGreaterThan, 2);
560
+ return emit(TokenKind.Equals, 1);
561
+ case Char.Exclamation:
562
+ if (next === Char.Equals && third === Char.Equals)
563
+ return emit(TokenKind.ExclamationEqualsEquals, 3);
564
+ if (next === Char.Equals)
565
+ return emit(TokenKind.ExclamationEquals, 2);
566
+ return emit(TokenKind.Exclamation, 1);
567
+ case Char.Plus:
568
+ if (next === Char.Plus)
569
+ return emit(TokenKind.PlusPlus, 2);
570
+ if (next === Char.Equals)
571
+ return emit(TokenKind.PlusEquals, 2);
572
+ return emit(TokenKind.Plus, 1);
573
+ case Char.Minus:
574
+ if (next === Char.Minus)
575
+ return emit(TokenKind.MinusMinus, 2);
576
+ if (next === Char.Equals)
577
+ return emit(TokenKind.MinusEquals, 2);
578
+ return emit(TokenKind.Minus, 1);
579
+ case Char.Asterisk:
580
+ if (next === Char.Asterisk) {
581
+ if (third === Char.Equals)
582
+ return emit(TokenKind.AsteriskAsteriskEquals, 3);
583
+ return emit(TokenKind.AsteriskAsterisk, 2);
584
+ }
585
+ if (next === Char.Equals)
586
+ return emit(TokenKind.AsteriskEquals, 2);
587
+ return emit(TokenKind.Asterisk, 1);
588
+ case Char.Slash:
589
+ if (next === Char.Equals)
590
+ return emit(TokenKind.SlashEquals, 2);
591
+ if (this.regexAllowed())
592
+ return this.scanRegex(start, precededByLineBreak);
593
+ return emit(TokenKind.Slash, 1);
594
+ case Char.Percent:
595
+ if (next === Char.Equals)
596
+ return emit(TokenKind.PercentEquals, 2);
597
+ return emit(TokenKind.Percent, 1);
598
+ case Char.LessThan:
599
+ if (next === Char.LessThan) {
600
+ if (third === Char.Equals)
601
+ return emit(TokenKind.LessThanLessThanEquals, 3);
602
+ return emit(TokenKind.LessThanLessThan, 2);
603
+ }
604
+ if (next === Char.Equals)
605
+ return emit(TokenKind.LessThanEquals, 2);
606
+ return emit(TokenKind.LessThan, 1);
607
+ case Char.GreaterThan:
608
+ if (next === Char.GreaterThan) {
609
+ if (third === Char.GreaterThan) {
610
+ if (fourth === Char.Equals)
611
+ return emit(TokenKind.GreaterThanGreaterThanGreaterThanEquals, 4);
612
+ return emit(TokenKind.GreaterThanGreaterThanGreaterThan, 3);
613
+ }
614
+ if (third === Char.Equals)
615
+ return emit(TokenKind.GreaterThanGreaterThanEquals, 3);
616
+ return emit(TokenKind.GreaterThanGreaterThan, 2);
617
+ }
618
+ if (next === Char.Equals)
619
+ return emit(TokenKind.GreaterThanEquals, 2);
620
+ return emit(TokenKind.GreaterThan, 1);
621
+ case Char.Ampersand:
622
+ if (next === Char.Ampersand) {
623
+ if (third === Char.Equals)
624
+ return emit(TokenKind.AmpersandAmpersandEquals, 3);
625
+ return emit(TokenKind.AmpersandAmpersand, 2);
626
+ }
627
+ if (next === Char.Equals)
628
+ return emit(TokenKind.AmpersandEquals, 2);
629
+ return emit(TokenKind.Ampersand, 1);
630
+ case Char.Bar:
631
+ if (next === Char.Bar) {
632
+ if (third === Char.Equals)
633
+ return emit(TokenKind.BarBarEquals, 3);
634
+ return emit(TokenKind.BarBar, 2);
635
+ }
636
+ if (next === Char.Equals)
637
+ return emit(TokenKind.BarEquals, 2);
638
+ return emit(TokenKind.Bar, 1);
639
+ case Char.Caret:
640
+ if (next === Char.Equals)
641
+ return emit(TokenKind.CaretEquals, 2);
642
+ return emit(TokenKind.Caret, 1);
643
+ default:
644
+ this.pos++;
645
+ this.error(DiagnosticCode.InvalidCharacter, `Invalid character '${text[start]}'`, start, this.pos);
646
+ return this.makeToken(TokenKind.Identifier, start, this.pos, text[start] ?? "", precededByLineBreak);
647
+ }
648
+ }
649
+ }
650
+ //# sourceMappingURL=scanner.js.map