@jalvin/compiler 2.0.37 → 2.0.39

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 (56) hide show
  1. package/dist/codegen.d.ts +4 -56
  2. package/dist/codegen.d.ts.map +1 -1
  3. package/dist/codegen.js +297 -884
  4. package/dist/codegen.js.map +1 -1
  5. package/dist/index.d.ts +1 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -4
  8. package/dist/index.js.map +1 -1
  9. package/dist/typechecker.d.ts.map +1 -1
  10. package/dist/typechecker.js +1 -3
  11. package/dist/typechecker.js.map +1 -1
  12. package/package.json +1 -1
  13. package/dist/codegen/index.d.ts +0 -179
  14. package/dist/codegen/index.d.ts.map +0 -1
  15. package/dist/codegen/index.js +0 -2207
  16. package/dist/codegen/index.js.map +0 -1
  17. package/dist/codegen_freestanding_c.d.ts +0 -9
  18. package/dist/codegen_freestanding_c.d.ts.map +0 -1
  19. package/dist/codegen_freestanding_c.js +0 -321
  20. package/dist/codegen_freestanding_c.js.map +0 -1
  21. package/dist/lexer/chars.d.ts +0 -5
  22. package/dist/lexer/chars.d.ts.map +0 -1
  23. package/dist/lexer/chars.js +0 -20
  24. package/dist/lexer/chars.js.map +0 -1
  25. package/dist/lexer/index.d.ts +0 -37
  26. package/dist/lexer/index.d.ts.map +0 -1
  27. package/dist/lexer/index.js +0 -630
  28. package/dist/lexer/index.js.map +0 -1
  29. package/dist/lexer/tokens.d.ts +0 -135
  30. package/dist/lexer/tokens.d.ts.map +0 -1
  31. package/dist/lexer/tokens.js +0 -89
  32. package/dist/lexer/tokens.js.map +0 -1
  33. package/dist/parser/constants.d.ts +0 -3
  34. package/dist/parser/constants.d.ts.map +0 -1
  35. package/dist/parser/constants.js +0 -7
  36. package/dist/parser/constants.js.map +0 -1
  37. package/dist/parser/helpers.d.ts +0 -2
  38. package/dist/parser/helpers.d.ts.map +0 -1
  39. package/dist/parser/helpers.js +0 -9
  40. package/dist/parser/helpers.js.map +0 -1
  41. package/dist/parser/index.d.ts +0 -118
  42. package/dist/parser/index.d.ts.map +0 -1
  43. package/dist/parser/index.js +0 -2387
  44. package/dist/parser/index.js.map +0 -1
  45. package/dist/typechecker/globals.d.ts +0 -2
  46. package/dist/typechecker/globals.d.ts.map +0 -1
  47. package/dist/typechecker/globals.js +0 -15
  48. package/dist/typechecker/globals.js.map +0 -1
  49. package/dist/typechecker/index.d.ts +0 -146
  50. package/dist/typechecker/index.d.ts.map +0 -1
  51. package/dist/typechecker/index.js +0 -2288
  52. package/dist/typechecker/index.js.map +0 -1
  53. package/dist/typechecker/types.d.ts +0 -66
  54. package/dist/typechecker/types.d.ts.map +0 -1
  55. package/dist/typechecker/types.js +0 -39
  56. package/dist/typechecker/types.js.map +0 -1
@@ -1,37 +0,0 @@
1
- import { DiagnosticBag } from "../diagnostics.js";
2
- import { type Token } from "./tokens.js";
3
- export { ASI_SET, KEYWORDS, TokenKind, type Token } from "./tokens.js";
4
- export declare class Lexer {
5
- private pos;
6
- private line;
7
- private col;
8
- private readonly src;
9
- private readonly file;
10
- private readonly diag;
11
- constructor(src: string, file: string, diag: DiagnosticBag);
12
- tokenize(): Token[];
13
- private nextToken;
14
- private lexIdentOrKeyword;
15
- private lexNumber;
16
- private lexString;
17
- private lexRawString;
18
- private parseEscape;
19
- private lexSymbol;
20
- private skipLineComment;
21
- private skipBlockComment;
22
- /**
23
- * Returns true when the next meaningful token after the current newline is a
24
- * dot-continuation (`.member` or `?.member`), in which case ASI must NOT be
25
- * inserted so that multi-line method chains work correctly.
26
- *
27
- * Scans forward from `this.pos + 1` skipping whitespace and comments.
28
- * `.` followed by another `.` (range `..`) does NOT count as continuation.
29
- */
30
- private peekIsDotContinuation;
31
- private advance;
32
- private peek;
33
- private spanAt;
34
- private makeSpan;
35
- }
36
- export declare function lex(src: string, file: string, diag: DiagnosticBag): Token[];
37
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lexer/index.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,aAAa,EAMd,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAgC,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAMvE,qBAAa,KAAK;IAChB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;gBAEzB,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa;IAM1D,QAAQ,IAAI,KAAK,EAAE;IAqDnB,OAAO,CAAC,SAAS;IAyBjB,OAAO,CAAC,iBAAiB;IAiCzB,OAAO,CAAC,SAAS;IA8FjB,OAAO,CAAC,SAAS;IAgFjB,OAAO,CAAC,YAAY;IA8BpB,OAAO,CAAC,WAAW;IAkDnB,OAAO,CAAC,SAAS;IAyFjB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,gBAAgB;IAuBxB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAqC7B,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,MAAM;IAYd,OAAO,CAAC,QAAQ;CAWjB;AAMD,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,KAAK,EAAE,CAE3E"}
@@ -1,630 +0,0 @@
1
- "use strict";
2
- // ─────────────────────────────────────────────────────────────────────────────
3
- // Jalvin Lexer
4
- //
5
- // Tokenises a .jalvin source file. Key behaviours:
6
- // • Automatic semicolon insertion (like Go) after certain tokens
7
- // when a newline is encountered.
8
- // • String templates: `"Hello $name"` and `"Hello ${expr}"`.
9
- // • Triple-quoted raw strings: `"""..."""`.
10
- // • Coroutine keywords: launch, async, suspend, await.
11
- // • `component` keyword for UI declarations.
12
- // • `Bibi` is just an identifier — treated normally by the lexer.
13
- // ─────────────────────────────────────────────────────────────────────────────
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.Lexer = exports.KEYWORDS = exports.ASI_SET = void 0;
16
- exports.lex = lex;
17
- const diagnostics_js_1 = require("../diagnostics.js");
18
- const chars_js_1 = require("./chars.js");
19
- const tokens_js_1 = require("./tokens.js");
20
- var tokens_js_2 = require("./tokens.js");
21
- Object.defineProperty(exports, "ASI_SET", { enumerable: true, get: function () { return tokens_js_2.ASI_SET; } });
22
- Object.defineProperty(exports, "KEYWORDS", { enumerable: true, get: function () { return tokens_js_2.KEYWORDS; } });
23
- // ---------------------------------------------------------------------------
24
- // Lexer
25
- // ---------------------------------------------------------------------------
26
- class Lexer {
27
- pos = 0;
28
- line = 0;
29
- col = 0;
30
- src;
31
- file;
32
- diag;
33
- constructor(src, file, diag) {
34
- this.src = src;
35
- this.file = file;
36
- this.diag = diag;
37
- }
38
- tokenize() {
39
- const tokens = [];
40
- let prevKind = null;
41
- while (this.pos < this.src.length) {
42
- const ch = this.src[this.pos];
43
- // ── Whitespace ───────────────────────────────────────────────────────
44
- if (ch === " " || ch === "\t" || ch === "\r") {
45
- this.advance();
46
- continue;
47
- }
48
- // ── Newline → potential semicolon ────────────────────────────────────
49
- if (ch === "\n") {
50
- if (prevKind !== null && tokens_js_1.ASI_SET.has(prevKind) && !this.peekIsDotContinuation()) {
51
- const span = this.spanAt(this.pos, this.pos);
52
- tokens.push({ kind: "Semicolon" /* TokenKind.Semicolon */, span, text: "\n" });
53
- prevKind = "Semicolon" /* TokenKind.Semicolon */;
54
- }
55
- this.advance();
56
- continue;
57
- }
58
- // ── Comments ─────────────────────────────────────────────────────────
59
- if (ch === "/" && this.peek(1) === "/") {
60
- this.skipLineComment();
61
- continue;
62
- }
63
- if (ch === "/" && this.peek(1) === "*") {
64
- this.skipBlockComment();
65
- continue;
66
- }
67
- const tok = this.nextToken();
68
- if (tok) {
69
- tokens.push(tok);
70
- prevKind = tok.kind;
71
- }
72
- }
73
- // EOF
74
- tokens.push({
75
- kind: "EOF" /* TokenKind.EOF */,
76
- span: this.spanAt(this.pos, this.pos),
77
- text: "",
78
- });
79
- return tokens;
80
- }
81
- // ── Token dispatch ─────────────────────────────────────────────────────────
82
- nextToken() {
83
- const start = this.pos;
84
- const ch = this.src[start];
85
- if (ch === undefined)
86
- return null;
87
- // Identifiers & keywords
88
- if ((0, chars_js_1.isIdentStart)(ch))
89
- return this.lexIdentOrKeyword();
90
- // Numbers
91
- if ((0, chars_js_1.isDigit)(ch))
92
- return this.lexNumber();
93
- // Strings
94
- if (ch === '"') {
95
- if (this.peek(1) === '"' && this.peek(2) === '"') {
96
- return this.lexRawString();
97
- }
98
- return this.lexString();
99
- }
100
- // Operators & punctuation
101
- return this.lexSymbol();
102
- }
103
- // ── Identifier / keyword ───────────────────────────────────────────────────
104
- lexIdentOrKeyword() {
105
- const start = this.pos;
106
- const startLine = this.line;
107
- const startCol = this.col;
108
- while (this.pos < this.src.length && (0, chars_js_1.isIdentContinue)(this.src[this.pos])) {
109
- this.advance();
110
- }
111
- const text = this.src.slice(start, this.pos);
112
- const span = this.makeSpan(start, startLine, startCol);
113
- if (text === "_") {
114
- return { kind: "Underscore" /* TokenKind.Underscore */, span, text };
115
- }
116
- const kwKind = Object.prototype.hasOwnProperty.call(tokens_js_1.KEYWORDS, text) ? tokens_js_1.KEYWORDS[text] : undefined;
117
- if (kwKind !== undefined) {
118
- switch (kwKind) {
119
- case "BooleanLiteral" /* TokenKind.BooleanLiteral */:
120
- return { kind: kwKind, span, text, value: text === "true" };
121
- case "NullLiteral" /* TokenKind.NullLiteral */:
122
- return { kind: kwKind, span, text, value: null };
123
- default:
124
- return { kind: kwKind, span, text };
125
- }
126
- }
127
- return { kind: "Identifier" /* TokenKind.Identifier */, span, text };
128
- }
129
- // ── Number literals ────────────────────────────────────────────────────────
130
- lexNumber() {
131
- const start = this.pos;
132
- const startLine = this.line;
133
- const startCol = this.col;
134
- let isHex = false;
135
- let isBinary = false;
136
- if (this.src[this.pos] === "0") {
137
- const next = this.peek(1);
138
- if (next === "x" || next === "X") {
139
- this.advance();
140
- this.advance();
141
- isHex = true;
142
- }
143
- else if (next === "b" || next === "B") {
144
- this.advance();
145
- this.advance();
146
- isBinary = true;
147
- }
148
- }
149
- if (isHex) {
150
- while (this.pos < this.src.length && (0, chars_js_1.isHexDigit)(this.src[this.pos])) {
151
- this.advance();
152
- }
153
- }
154
- else if (isBinary) {
155
- while (this.pos < this.src.length && (this.src[this.pos] === "0" || this.src[this.pos] === "1")) {
156
- this.advance();
157
- }
158
- }
159
- else {
160
- while (this.pos < this.src.length && ((0, chars_js_1.isDigit)(this.src[this.pos]) || this.src[this.pos] === "_")) {
161
- this.advance();
162
- }
163
- }
164
- let isFloat = false;
165
- let isDouble = false;
166
- if (!isHex && !isBinary) {
167
- if (this.src[this.pos] === "." && (0, chars_js_1.isDigit)(this.peek(1) ?? "")) {
168
- isDouble = true;
169
- this.advance(); // consume '.'
170
- while (this.pos < this.src.length && ((0, chars_js_1.isDigit)(this.src[this.pos]) || this.src[this.pos] === "_")) {
171
- this.advance();
172
- }
173
- }
174
- // Exponent
175
- if (this.src[this.pos] === "e" || this.src[this.pos] === "E") {
176
- isDouble = true;
177
- this.advance();
178
- if (this.src[this.pos] === "+" || this.src[this.pos] === "-")
179
- this.advance();
180
- while (this.pos < this.src.length && (0, chars_js_1.isDigit)(this.src[this.pos]))
181
- this.advance();
182
- }
183
- }
184
- let suffix = "";
185
- const sc = this.src[this.pos];
186
- if (sc === "L" || sc === "l") {
187
- suffix = "L";
188
- this.advance();
189
- }
190
- else if (sc === "f" || sc === "F") {
191
- suffix = "f";
192
- isFloat = true;
193
- this.advance();
194
- }
195
- else if (sc === "d" || sc === "D") {
196
- suffix = "d";
197
- isDouble = true;
198
- this.advance();
199
- }
200
- const text = this.src.slice(start, this.pos);
201
- const span = this.makeSpan(start, startLine, startCol);
202
- const clean = text.replace(/_/g, "").replace(/[LlfFdD]$/, "");
203
- if (suffix === "L") {
204
- let val;
205
- try {
206
- val = BigInt(clean);
207
- }
208
- catch {
209
- this.diag.error(span, diagnostics_js_1.E_INVALID_NUMBER_LITERAL, `Invalid long literal: ${text}`);
210
- val = 0n;
211
- }
212
- return { kind: "LongLiteral" /* TokenKind.LongLiteral */, span, text, value: val };
213
- }
214
- if (isFloat) {
215
- return { kind: "FloatLiteral" /* TokenKind.FloatLiteral */, span, text, value: parseFloat(clean) };
216
- }
217
- if (isDouble || text.includes(".") || text.toLowerCase().includes("e")) {
218
- return { kind: "DoubleLiteral" /* TokenKind.DoubleLiteral */, span, text, value: parseFloat(clean) };
219
- }
220
- const intVal = isHex
221
- ? parseInt(clean.slice(2), 16)
222
- : isBinary
223
- ? parseInt(clean.slice(2), 2)
224
- : parseInt(clean, 10);
225
- if (isNaN(intVal)) {
226
- this.diag.error(span, diagnostics_js_1.E_INVALID_NUMBER_LITERAL, `Invalid integer literal: ${text}`);
227
- return { kind: "IntLiteral" /* TokenKind.IntLiteral */, span, text, value: 0 };
228
- }
229
- return { kind: "IntLiteral" /* TokenKind.IntLiteral */, span, text, value: intVal };
230
- }
231
- // ── String literals ────────────────────────────────────────────────────────
232
- lexString() {
233
- const start = this.pos;
234
- const startLine = this.line;
235
- const startCol = this.col;
236
- this.advance(); // consume opening "
237
- let value = "";
238
- let isTemplate = false;
239
- let closed = false;
240
- const templateParts = [];
241
- while (this.pos < this.src.length) {
242
- const ch = this.src[this.pos];
243
- if (ch === "\"") {
244
- this.advance();
245
- closed = true;
246
- break;
247
- }
248
- if (ch === "\n") {
249
- break;
250
- }
251
- if (ch === "$") {
252
- if (this.peek(1) === "{") {
253
- isTemplate = true;
254
- templateParts.push(value);
255
- value = "";
256
- // We just return the string fragment; the parser handles interpolation
257
- // by re-lexing nested expressions. For simplicity we encode templates
258
- // into a single StringTemplateExpr token with the raw text.
259
- // Consume ${ block
260
- this.advance();
261
- this.advance();
262
- let depth = 1;
263
- let exprText = "";
264
- while (this.pos < this.src.length && depth > 0) {
265
- const ec = this.src[this.pos];
266
- if (ec === "{")
267
- depth++;
268
- else if (ec === "}") {
269
- depth--;
270
- if (depth === 0) {
271
- this.advance();
272
- break;
273
- }
274
- }
275
- exprText += ec;
276
- this.advance();
277
- }
278
- templateParts.push(`\${${exprText}}`);
279
- }
280
- else if ((0, chars_js_1.isIdentStart)(this.peek(1) ?? "")) {
281
- isTemplate = true;
282
- templateParts.push(value);
283
- value = "";
284
- this.advance(); // $
285
- const identStart = this.pos;
286
- while (this.pos < this.src.length && (0, chars_js_1.isIdentContinue)(this.src[this.pos]))
287
- this.advance();
288
- const ident = this.src.slice(identStart, this.pos);
289
- templateParts.push(`\${${ident}}`);
290
- }
291
- else {
292
- value += ch;
293
- this.advance();
294
- }
295
- continue;
296
- }
297
- if (ch === "\\") {
298
- const span = this.makeSpan(this.pos, this.line, this.col);
299
- value += this.parseEscape(span);
300
- continue;
301
- }
302
- value += ch;
303
- this.advance();
304
- }
305
- if (!closed) {
306
- const span = this.makeSpan(start, startLine, startCol);
307
- this.diag.error(span, diagnostics_js_1.E_UNTERMINATED_STRING, "Unterminated string literal");
308
- }
309
- const text = this.src.slice(start, this.pos);
310
- const span = this.makeSpan(start, startLine, startCol);
311
- if (isTemplate) {
312
- const raw = templateParts.join("") + value;
313
- return { kind: "StringLiteral" /* TokenKind.StringLiteral */, span, text, value: raw };
314
- }
315
- return { kind: "StringLiteral" /* TokenKind.StringLiteral */, span, text, value };
316
- }
317
- lexRawString() {
318
- const start = this.pos;
319
- const startLine = this.line;
320
- const startCol = this.col;
321
- this.advance();
322
- this.advance();
323
- this.advance(); // consume """
324
- let value = "";
325
- let closed = false;
326
- while (this.pos < this.src.length) {
327
- if (this.src[this.pos] === '"' && this.peek(1) === '"' && this.peek(2) === '"') {
328
- this.advance();
329
- this.advance();
330
- this.advance();
331
- closed = true;
332
- break;
333
- }
334
- const c = this.src[this.pos];
335
- if (c === "\n")
336
- this.line++; // no col tracking in raw strings
337
- value += c;
338
- this.advance();
339
- }
340
- if (!closed) {
341
- const span = this.makeSpan(start, startLine, startCol);
342
- this.diag.error(span, diagnostics_js_1.E_UNTERMINATED_STRING, "Unterminated triple-quoted string");
343
- }
344
- const text = this.src.slice(start, this.pos);
345
- const span = this.makeSpan(start, startLine, startCol);
346
- return { kind: "RawStringLiteral" /* TokenKind.RawStringLiteral */, span, text, value };
347
- }
348
- parseEscape(span) {
349
- this.advance(); // consume backslash
350
- const ec = this.src[this.pos];
351
- this.advance();
352
- switch (ec) {
353
- case "n": return "\n";
354
- case "t": return "\t";
355
- case "r": return "\r";
356
- case "\\": return "\\";
357
- case '"': return '"';
358
- case "'": return "'";
359
- case "0": return "\0";
360
- case "$": return "$";
361
- case "u": {
362
- if (this.src[this.pos] === "{") {
363
- this.advance(); // {
364
- let hex = "";
365
- while (this.pos < this.src.length && this.src[this.pos] !== "}") {
366
- hex += this.src[this.pos];
367
- this.advance();
368
- }
369
- this.advance(); // }
370
- const cp = parseInt(hex, 16);
371
- if (isNaN(cp)) {
372
- this.diag.error(span, diagnostics_js_1.E_INVALID_ESCAPE, `Invalid unicode escape: \\u{${hex}}`);
373
- return "";
374
- }
375
- return String.fromCodePoint(cp);
376
- }
377
- // \uXXXX
378
- let hex = "";
379
- for (let i = 0; i < 4; i++) {
380
- hex += this.src[this.pos] ?? "";
381
- this.advance();
382
- }
383
- const cp = parseInt(hex, 16);
384
- if (isNaN(cp)) {
385
- this.diag.error(span, diagnostics_js_1.E_INVALID_ESCAPE, `Invalid unicode escape: \\u${hex}`);
386
- return "";
387
- }
388
- return String.fromCharCode(cp);
389
- }
390
- default:
391
- this.diag.error(span, diagnostics_js_1.E_INVALID_ESCAPE, `Unknown escape sequence: \\${ec ?? ""}`);
392
- return ec ?? "";
393
- }
394
- }
395
- // ── Symbols & operators ────────────────────────────────────────────────────
396
- lexSymbol() {
397
- const start = this.pos;
398
- const startLine = this.line;
399
- const startCol = this.col;
400
- const ch = this.src[this.pos];
401
- const next = this.peek(1);
402
- const next2 = this.peek(2);
403
- const mk = (kind, len) => {
404
- const text = this.src.slice(start, start + len);
405
- for (let i = 0; i < len; i++)
406
- this.advance();
407
- return { kind, span: this.makeSpan(start, startLine, startCol), text };
408
- };
409
- switch (ch) {
410
- case "+":
411
- if (next === "+")
412
- return mk("PlusPlus" /* TokenKind.PlusPlus */, 2);
413
- if (next === "=")
414
- return mk("PlusEq" /* TokenKind.PlusEq */, 2);
415
- return mk("Plus" /* TokenKind.Plus */, 1);
416
- case "-":
417
- if (next === "-")
418
- return mk("MinusMinus" /* TokenKind.MinusMinus */, 2);
419
- if (next === "=")
420
- return mk("MinusEq" /* TokenKind.MinusEq */, 2);
421
- if (next === ">")
422
- return mk("Arrow" /* TokenKind.Arrow */, 2);
423
- return mk("Minus" /* TokenKind.Minus */, 1);
424
- case "*":
425
- if (next === "=")
426
- return mk("StarEq" /* TokenKind.StarEq */, 2);
427
- return mk("Star" /* TokenKind.Star */, 1);
428
- case "/":
429
- if (next === "=")
430
- return mk("SlashEq" /* TokenKind.SlashEq */, 2);
431
- return mk("Slash" /* TokenKind.Slash */, 1);
432
- case "%":
433
- if (next === "=")
434
- return mk("PercentEq" /* TokenKind.PercentEq */, 2);
435
- return mk("Percent" /* TokenKind.Percent */, 1);
436
- case "=":
437
- if (next === "=" && next2 === "=")
438
- return mk("EqEqEq" /* TokenKind.EqEqEq */, 3);
439
- if (next === "=")
440
- return mk("EqEq" /* TokenKind.EqEq */, 2);
441
- if (next === ">")
442
- return mk("FatArrow" /* TokenKind.FatArrow */, 2);
443
- return mk("Eq" /* TokenKind.Eq */, 1);
444
- case "!":
445
- if (next === "=" && next2 === "=")
446
- return mk("BangEqEq" /* TokenKind.BangEqEq */, 3);
447
- if (next === "=")
448
- return mk("BangEq" /* TokenKind.BangEq */, 2);
449
- if (next === "!")
450
- return mk("BangBang" /* TokenKind.BangBang */, 2);
451
- return mk("Bang" /* TokenKind.Bang */, 1);
452
- case "<":
453
- if (next === "=")
454
- return mk("LtEq" /* TokenKind.LtEq */, 2);
455
- return mk("Lt" /* TokenKind.Lt */, 1);
456
- case ">":
457
- if (next === "=")
458
- return mk("GtEq" /* TokenKind.GtEq */, 2);
459
- return mk("Gt" /* TokenKind.Gt */, 1);
460
- case "&":
461
- if (next === "&")
462
- return mk("AmpAmp" /* TokenKind.AmpAmp */, 2);
463
- return mk("Amp" /* TokenKind.Amp */, 1);
464
- case "|":
465
- if (next === "|")
466
- return mk("PipePipe" /* TokenKind.PipePipe */, 2);
467
- return mk("Pipe" /* TokenKind.Pipe */, 1);
468
- case "?":
469
- if (next === ":")
470
- return mk("QuestionColon" /* TokenKind.QuestionColon */, 2);
471
- if (next === ".")
472
- return mk("QuestionDot" /* TokenKind.QuestionDot */, 2);
473
- return mk("Question" /* TokenKind.Question */, 1);
474
- case ".":
475
- if (next === "." && next2 === "<")
476
- return mk("DotDotLt" /* TokenKind.DotDotLt */, 3);
477
- if (next === ".")
478
- return mk("DotDot" /* TokenKind.DotDot */, 2);
479
- return mk("Dot" /* TokenKind.Dot */, 1);
480
- case ":":
481
- if (next === ":")
482
- return mk("ColonColon" /* TokenKind.ColonColon */, 2);
483
- return mk("Colon" /* TokenKind.Colon */, 1);
484
- case "{": return mk("LBrace" /* TokenKind.LBrace */, 1);
485
- case "}": return mk("RBrace" /* TokenKind.RBrace */, 1);
486
- case "(": return mk("LParen" /* TokenKind.LParen */, 1);
487
- case ")": return mk("RParen" /* TokenKind.RParen */, 1);
488
- case "[": return mk("LBracket" /* TokenKind.LBracket */, 1);
489
- case "]": return mk("RBracket" /* TokenKind.RBracket */, 1);
490
- case ",": return mk("Comma" /* TokenKind.Comma */, 1);
491
- case ";": return mk("Semicolon" /* TokenKind.Semicolon */, 1);
492
- case "@": return mk("At" /* TokenKind.At */, 1);
493
- case "#": return mk("Hash" /* TokenKind.Hash */, 1);
494
- case "^": return mk("Caret" /* TokenKind.Caret */, 1);
495
- case "~": return mk("Tilde" /* TokenKind.Tilde */, 1);
496
- default: {
497
- const span = this.makeSpan(start, startLine, startCol);
498
- this.diag.error(span, diagnostics_js_1.E_UNEXPECTED_CHAR, `Unexpected character: '${ch}'`);
499
- this.advance();
500
- return null;
501
- }
502
- }
503
- }
504
- // ── Comment skipping ───────────────────────────────────────────────────────
505
- skipLineComment() {
506
- while (this.pos < this.src.length && this.src[this.pos] !== "\n") {
507
- this.advance();
508
- }
509
- }
510
- skipBlockComment() {
511
- const start = this.pos;
512
- const startLine = this.line;
513
- const startCol = this.col;
514
- this.advance();
515
- this.advance(); // /*
516
- let depth = 1;
517
- while (this.pos < this.src.length) {
518
- const c = this.src[this.pos];
519
- if (c === "/" && this.peek(1) === "*") {
520
- depth++;
521
- this.advance();
522
- this.advance();
523
- continue;
524
- }
525
- if (c === "*" && this.peek(1) === "/") {
526
- depth--;
527
- this.advance();
528
- this.advance();
529
- if (depth === 0)
530
- return;
531
- continue;
532
- }
533
- this.advance();
534
- }
535
- const span = this.makeSpan(start, startLine, startCol);
536
- this.diag.error(span, diagnostics_js_1.E_UNTERMINATED_BLOCK_COMMENT, "Unterminated block comment");
537
- }
538
- // ── Utilities ──────────────────────────────────────────────────────────────
539
- /**
540
- * Returns true when the next meaningful token after the current newline is a
541
- * dot-continuation (`.member` or `?.member`), in which case ASI must NOT be
542
- * inserted so that multi-line method chains work correctly.
543
- *
544
- * Scans forward from `this.pos + 1` skipping whitespace and comments.
545
- * `.` followed by another `.` (range `..`) does NOT count as continuation.
546
- */
547
- peekIsDotContinuation() {
548
- let i = this.pos + 1; // start after current '\n'
549
- while (i < this.src.length) {
550
- const c = this.src[i];
551
- // Skip horizontal whitespace and additional newlines
552
- if (c === " " || c === "\t" || c === "\r" || c === "\n") {
553
- i++;
554
- continue;
555
- }
556
- // Skip line comment
557
- if (c === "/" && this.src[i + 1] === "/") {
558
- while (i < this.src.length && this.src[i] !== "\n")
559
- i++;
560
- continue;
561
- }
562
- // Skip block comment
563
- if (c === "/" && this.src[i + 1] === "*") {
564
- i += 2;
565
- while (i < this.src.length - 1) {
566
- if (this.src[i] === "*" && this.src[i + 1] === "/") {
567
- i += 2;
568
- break;
569
- }
570
- i++;
571
- }
572
- continue;
573
- }
574
- // Single '.' that is NOT part of '..' (range) is a chain continuation
575
- if (c === ".") {
576
- return this.src[i + 1] !== ".";
577
- }
578
- // '?.' is a safe-call chain continuation
579
- if (c === "?" && this.src[i + 1] === ".") {
580
- return true;
581
- }
582
- // Any other character — not a chain continuation
583
- return false;
584
- }
585
- return false;
586
- }
587
- advance() {
588
- if (this.src[this.pos] === "\n") {
589
- this.line++;
590
- this.col = 0;
591
- }
592
- else {
593
- this.col++;
594
- }
595
- this.pos++;
596
- }
597
- peek(offset) {
598
- return this.src[this.pos + offset];
599
- }
600
- spanAt(startPos, endPos) {
601
- return {
602
- file: this.file,
603
- startLine: this.line,
604
- startCol: this.col,
605
- endLine: this.line,
606
- endCol: this.col,
607
- startOffset: startPos,
608
- endOffset: endPos,
609
- };
610
- }
611
- makeSpan(startOffset, startLine, startCol) {
612
- return {
613
- file: this.file,
614
- startLine,
615
- startCol,
616
- endLine: this.line,
617
- endCol: this.col,
618
- startOffset,
619
- endOffset: this.pos,
620
- };
621
- }
622
- }
623
- exports.Lexer = Lexer;
624
- // ---------------------------------------------------------------------------
625
- // Public helper: lex a source file
626
- // ---------------------------------------------------------------------------
627
- function lex(src, file, diag) {
628
- return new Lexer(src, file, diag).tokenize();
629
- }
630
- //# sourceMappingURL=index.js.map