@xnoxs/flux-lang 3.1.1

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/CHANGELOG.md +103 -0
  2. package/README.md +1089 -0
  3. package/bin/flux.js +1397 -0
  4. package/dist/flux.cjs.js +6664 -0
  5. package/dist/flux.esm.js +6674 -0
  6. package/dist/flux.min.js +263 -0
  7. package/index.d.ts +202 -0
  8. package/index.js +26 -0
  9. package/package.json +77 -0
  10. package/scripts/build.js +76 -0
  11. package/src/bundler.js +216 -0
  12. package/src/checker.js +322 -0
  13. package/src/codegen.js +785 -0
  14. package/src/css-preprocessor.js +399 -0
  15. package/src/formatter.js +140 -0
  16. package/src/jsx.js +480 -0
  17. package/src/lexer.js +518 -0
  18. package/src/linter.js +758 -0
  19. package/src/mangler.js +280 -0
  20. package/src/parser.js +1671 -0
  21. package/src/self/bundler.flux +167 -0
  22. package/src/self/bundler.js +187 -0
  23. package/src/self/checker.flux +249 -0
  24. package/src/self/checker.js +338 -0
  25. package/src/self/codegen.flux +555 -0
  26. package/src/self/codegen.js +784 -0
  27. package/src/self/css-preprocessor.flux +373 -0
  28. package/src/self/css-preprocessor.js +387 -0
  29. package/src/self/formatter.flux +93 -0
  30. package/src/self/formatter.js +114 -0
  31. package/src/self/jsx.flux +430 -0
  32. package/src/self/jsx.js +396 -0
  33. package/src/self/lexer.flux +529 -0
  34. package/src/self/lexer.js +709 -0
  35. package/src/self/lexer.stage2.js +700 -0
  36. package/src/self/linter.flux +515 -0
  37. package/src/self/linter.js +804 -0
  38. package/src/self/mangler.flux +253 -0
  39. package/src/self/mangler.js +348 -0
  40. package/src/self/parser.flux +1146 -0
  41. package/src/self/parser.js +1571 -0
  42. package/src/self/sourcemap.flux +66 -0
  43. package/src/self/sourcemap.js +72 -0
  44. package/src/self/stdlib.flux +356 -0
  45. package/src/self/stdlib.js +396 -0
  46. package/src/self/test-runner.flux +201 -0
  47. package/src/self/test-runner.js +132 -0
  48. package/src/self/transpiler.flux +123 -0
  49. package/src/self/transpiler.js +83 -0
  50. package/src/self/type-checker.flux +821 -0
  51. package/src/self/type-checker.js +1106 -0
  52. package/src/sourcemap.js +82 -0
  53. package/src/stdlib.js +436 -0
  54. package/src/test-runner.js +239 -0
  55. package/src/transpiler.js +172 -0
  56. package/src/type-checker.js +1206 -0
@@ -0,0 +1,1146 @@
1
+ // ============================================================
2
+ // Flux Self-Hosted Parser
3
+ // src/self/parser.flux — written in Flux, compiled by stage-0
4
+ // ============================================================
5
+
6
+ import { T } from './lexer'
7
+
8
+ fn makeParseError(msg, tok):
9
+ val line = tok?.line ?? '?'
10
+ val col = tok?.col ?? '?'
11
+ val err = new Error("[Parser {line}:{col}] {msg}")
12
+ err.name = 'ParseError'
13
+ err.tok = tok
14
+ return err
15
+
16
+ export class Parser:
17
+ tokens: any[]
18
+ pos: int
19
+
20
+ fn peek(n = 0):
21
+ return self.tokens[self.pos + n] ?? { type: 'EOF', value: null, line: 0, col: 0 }
22
+
23
+ fn check(typ):
24
+ return self.peek().type == typ
25
+
26
+ fn at(a, b = null, c = null, d = null, e = null, f = null):
27
+ val t = self.peek().type
28
+ return t == a or (b != null and t == b) or (c != null and t == c) or (d != null and t == d) or (e != null and t == e) or (f != null and t == f)
29
+
30
+ fn eat(typ):
31
+ val tok = self.peek()
32
+ if tok.type != typ:
33
+ throw makeParseError("Expected '{typ}', got '{tok.type}' ({JSON.stringify(tok.value)})", tok)
34
+ self.pos = self.pos + 1
35
+ return tok
36
+
37
+ fn maybe(typ):
38
+ if self.check(typ):
39
+ self.pos = self.pos + 1
40
+ return true
41
+ return false
42
+
43
+ fn skip():
44
+ val t = self.tokens[self.pos]
45
+ self.pos = self.pos + 1
46
+ return t
47
+
48
+ fn skipNewlines():
49
+ while self.check(T.NEWLINE): self.pos = self.pos + 1
50
+
51
+ fn err(msg):
52
+ throw makeParseError(msg, self.peek())
53
+
54
+ fn parseBlock():
55
+ self.eat(T.COLON)
56
+ if self.check(T.NEWLINE):
57
+ self.pos = self.pos + 1
58
+ self.eat(T.INDENT)
59
+ val body = self.parseStmtList()
60
+ self.maybe(T.DEDENT)
61
+ return body
62
+ val stmt = self.parseOneStmt()
63
+ return [stmt]
64
+
65
+ fn parseStmtList():
66
+ val stmts = []
67
+ while not self.check(T.DEDENT) and not self.check(T.EOF):
68
+ self.skipNewlines()
69
+ if self.check(T.DEDENT) or self.check(T.EOF): break
70
+ stmts.push(self.parseOneStmt())
71
+ return stmts
72
+
73
+ fn parse():
74
+ self.skipNewlines()
75
+ val body = []
76
+ while not self.check(T.EOF):
77
+ self.skipNewlines()
78
+ if self.check(T.EOF): break
79
+ body.push(self.parseOneStmt())
80
+ return { type: 'Program', body }
81
+
82
+ fn parseOneStmt():
83
+ val tok = self.peek()
84
+ if tok.type == T.VAR or tok.type == T.VAL: return self.parseVarDecl()
85
+ if tok.type == T.FN: return self.parseFnDecl(false)
86
+ if tok.type == T.ASYNC: return self.parseAsyncFn()
87
+ if tok.type == T.CLASS: return self.parseClassDecl()
88
+ if tok.type == T.IF: return self.parseIf()
89
+ if tok.type == T.FOR: return self.parseFor()
90
+ if tok.type == T.WHILE: return self.parseWhile()
91
+ if tok.type == T.DO: return self.parseDoWhile()
92
+ if tok.type == T.MATCH: return self.parseMatch()
93
+ if tok.type == T.RETURN: return self.parseReturn()
94
+ if tok.type == T.BREAK:
95
+ self.skip()
96
+ self.skipNewlines()
97
+ return { type: 'BreakStmt', loc: tok }
98
+ if tok.type == T.CONTINUE:
99
+ self.skip()
100
+ self.skipNewlines()
101
+ return { type: 'ContinueStmt', loc: tok }
102
+ if tok.type == T.IMPORT: return self.parseImport()
103
+ if tok.type == T.EXPORT: return self.parseExport()
104
+ if tok.type == T.TRY: return self.parseTryCatch()
105
+ if tok.type == T.THROW: return self.parseThrow()
106
+ if tok.type == T.TYPE: return self.parseTypeDecl()
107
+ if tok.type == T.INTERFACE: return self.parseInterfaceDecl()
108
+ if tok.type == T.ENUM: return self.parseEnumDecl()
109
+ return self.parseExprStmt()
110
+
111
+ fn parseVarDecl():
112
+ val kind = self.peek().type == T.VAR ? 'var' : 'val'
113
+ val loc = self.skip()
114
+ if self.check(T.LBRACE):
115
+ val pattern = self.parseObjectDestructurePattern()
116
+ self.eat(T.EQ)
117
+ val init = self.parseExpr()
118
+ self.skipNewlines()
119
+ return { type: 'DestructureDecl', kind, patternType: 'object', pattern, init, loc }
120
+ if self.check(T.LBRACKET):
121
+ val pattern = self.parseArrayDestructurePattern()
122
+ self.eat(T.EQ)
123
+ val init = self.parseExpr()
124
+ self.skipNewlines()
125
+ return { type: 'DestructureDecl', kind, patternType: 'array', pattern, init, loc }
126
+ val name = self.eat(T.IDENT).value
127
+ var typeAnn = null
128
+ if self.maybe(T.COLON): typeAnn = self.parseTypeAnn()
129
+ var init = null
130
+ if self.maybe(T.EQ): init = self.parseExpr()
131
+ self.skipNewlines()
132
+ return { type: 'VarDecl', kind, name, typeAnn, init, loc }
133
+
134
+ fn parseObjectDestructurePattern():
135
+ self.eat(T.LBRACE)
136
+ val props = []
137
+ while not self.check(T.RBRACE) and not self.check(T.EOF):
138
+ var rest = false
139
+ if self.check(T.DOTDOTDOT):
140
+ self.pos = self.pos + 1
141
+ rest = true
142
+ val key = self.eat(T.IDENT).value
143
+ if rest:
144
+ props.push({ key, alias: key, rest: true })
145
+ break
146
+ var alias = key
147
+ if self.maybe(T.COLON): alias = self.eat(T.IDENT).value
148
+ var defaultVal = null
149
+ if self.maybe(T.EQ): defaultVal = self.parseExpr()
150
+ props.push({ key, alias, defaultVal, rest: false })
151
+ if not self.maybe(T.COMMA): break
152
+ self.eat(T.RBRACE)
153
+ return props
154
+
155
+ fn parseArrayDestructurePattern():
156
+ self.eat(T.LBRACKET)
157
+ val items = []
158
+ while not self.check(T.RBRACKET) and not self.check(T.EOF):
159
+ if self.check(T.COMMA):
160
+ items.push(null)
161
+ self.pos = self.pos + 1
162
+ continue
163
+ var rest = false
164
+ if self.check(T.DOTDOTDOT):
165
+ self.pos = self.pos + 1
166
+ rest = true
167
+ val name = self.eat(T.IDENT).value
168
+ var defaultVal = null
169
+ if self.maybe(T.EQ): defaultVal = self.parseExpr()
170
+ items.push({ name, defaultVal, rest })
171
+ if rest: break
172
+ if not self.maybe(T.COMMA): break
173
+ self.eat(T.RBRACKET)
174
+ return items
175
+
176
+ fn parseTypeAnn():
177
+ var name = self.parseIntersectionType()
178
+ while self.check(T.PIPEB):
179
+ self.pos = self.pos + 1
180
+ name = name + ' | ' + self.parseIntersectionType()
181
+ return name
182
+
183
+ fn parseIntersectionType():
184
+ var name = self.parseSingleType()
185
+ while self.check(T.AMPERSAND):
186
+ self.pos = self.pos + 1
187
+ name = name + ' & ' + self.parseSingleType()
188
+ return name
189
+
190
+ fn parseSingleType():
191
+ val tok = self.peek()
192
+ if tok.type == T.LBRACKET:
193
+ self.pos = self.pos + 1
194
+ val parts = []
195
+ while not self.check(T.RBRACKET) and not self.check(T.EOF):
196
+ parts.push(self.parseTypeAnn())
197
+ if not self.maybe(T.COMMA): break
198
+ self.eat(T.RBRACKET)
199
+ return '[' + parts.join(', ') + ']'
200
+ if tok.type == T.LBRACE:
201
+ self.pos = self.pos + 1
202
+ val pairs = []
203
+ while not self.check(T.RBRACE) and not self.check(T.EOF):
204
+ if self.check(T.LBRACKET):
205
+ self.pos = self.pos + 1
206
+ val iname = self.eat(T.IDENT).value
207
+ self.eat(T.COLON)
208
+ val iktype = self.parseTypeAnn()
209
+ self.eat(T.RBRACKET)
210
+ self.eat(T.COLON)
211
+ val ivtype = self.parseTypeAnn()
212
+ pairs.push("[{iname}: {iktype}]: {ivtype}")
213
+ else:
214
+ val key = self.at(T.IDENT, T.STRING) ? self.skip().value : self.eat(T.IDENT).value
215
+ var optional = false
216
+ if self.check(T.QUESTION):
217
+ self.pos = self.pos + 1
218
+ optional = true
219
+ self.eat(T.COLON)
220
+ val valType = self.parseTypeAnn()
221
+ val optStr = optional ? '?' : ''
222
+ pairs.push("{key}{optStr}: {valType}")
223
+ self.maybe(T.COMMA)
224
+ self.eat(T.RBRACE)
225
+ return '{ ' + pairs.join(', ') + ' }'
226
+ if tok.type == T.LPAREN:
227
+ self.pos = self.pos + 1
228
+ val inner = self.parseTypeAnn()
229
+ self.eat(T.RPAREN)
230
+ return '(' + inner + ')'
231
+ if tok.type == T.IDENT and tok.value == 'keyof':
232
+ self.pos = self.pos + 1
233
+ return 'keyof ' + self.parseSingleType()
234
+ if tok.type == T.TYPEOF:
235
+ self.pos = self.pos + 1
236
+ return 'typeof ' + self.eat(T.IDENT).value
237
+ if tok.type == T.READONLY:
238
+ self.pos = self.pos + 1
239
+ return 'readonly ' + self.parseSingleType()
240
+ if tok.type == T.IDENT and tok.value == 'infer':
241
+ self.pos = self.pos + 1
242
+ return 'infer ' + self.eat(T.IDENT).value
243
+ if tok.type == T.FN:
244
+ self.pos = self.pos + 1
245
+ val paramTypes = []
246
+ if self.check(T.LPAREN):
247
+ self.pos = self.pos + 1
248
+ while not self.check(T.RPAREN) and not self.check(T.EOF):
249
+ var pt = ''
250
+ if self.check(T.IDENT) and self.peek(1).type == T.COLON:
251
+ self.pos = self.pos + 2
252
+ pt = self.parseTypeAnn()
253
+ else:
254
+ pt = self.parseTypeAnn()
255
+ paramTypes.push(pt)
256
+ if not self.maybe(T.COMMA): break
257
+ self.eat(T.RPAREN)
258
+ var retType = 'Void'
259
+ if self.check(T.ARROW):
260
+ self.pos = self.pos + 1
261
+ retType = self.parseTypeAnn()
262
+ return 'fn(' + paramTypes.join(', ') + ') -> ' + retType
263
+ var name = ''
264
+ if tok.type == T.IDENT or tok.type == T.CONST or tok.type == T.TYPE:
265
+ name = self.skip().value
266
+ else:
267
+ name = self.eat(T.IDENT).value
268
+ if self.check(T.EXTENDS):
269
+ self.pos = self.pos + 1
270
+ val constraint = self.parseSingleType()
271
+ self.eat(T.QUESTION)
272
+ val thenType = self.parseTypeAnn()
273
+ self.eat(T.COLON)
274
+ val elseType = self.parseTypeAnn()
275
+ return "{name} extends {constraint} ? {thenType} : {elseType}"
276
+ if self.check(T.LT):
277
+ self.pos = self.pos + 1
278
+ val params = [self.parseTypeAnn()]
279
+ while self.maybe(T.COMMA): params.push(self.parseTypeAnn())
280
+ self.eat(T.GT)
281
+ name = name + '<' + params.join(', ') + '>'
282
+ while self.check(T.LBRACKET) and self.peek(1).type == T.RBRACKET:
283
+ self.pos = self.pos + 2
284
+ name = name + '[]'
285
+ if self.check(T.QUESTION) and self.peek(1).type != T.DOT:
286
+ self.pos = self.pos + 1
287
+ name = name + '?'
288
+ return name
289
+
290
+ fn isTypeAnnBeforeColon():
291
+ val saved = self.pos
292
+ try:
293
+ val tok0 = self.peek()
294
+ if tok0.type == T.LBRACKET or tok0.type == T.LBRACE or tok0.type == T.LPAREN:
295
+ var depth = 0
296
+ var i = 0
297
+ while self.tokens[self.pos + i] and self.tokens[self.pos + i].type != T.EOF:
298
+ val tt = self.tokens[self.pos + i].type
299
+ if tt == T.LBRACKET or tt == T.LBRACE or tt == T.LPAREN or tt == T.LT: depth = depth + 1
300
+ if tt == T.RBRACKET or tt == T.RBRACE or tt == T.RPAREN or tt == T.GT: depth = depth - 1
301
+ i = i + 1
302
+ if depth == 0: break
303
+ if self.tokens[self.pos + i] and self.tokens[self.pos + i].type == T.QUESTION: i = i + 1
304
+ val nextType = self.tokens[self.pos + i]?.type
305
+ self.pos = saved
306
+ return nextType == T.COLON
307
+ if tok0.type != T.IDENT and tok0.type != T.TYPEOF and tok0.type != T.READONLY and tok0.type != T.FN:
308
+ self.pos = saved
309
+ return false
310
+ self.parseTypeAnn()
311
+ val result = self.check(T.NEWLINE) or self.check(T.EOF)
312
+ self.pos = saved
313
+ return result
314
+ catch(e):
315
+ self.pos = saved
316
+ return false
317
+
318
+ fn isColonReturnType():
319
+ val saved = self.pos
320
+ try:
321
+ self.pos = self.pos + 1
322
+ if not self.at(T.IDENT, T.LBRACKET, T.LBRACE, T.LPAREN, T.FN, T.READONLY, T.TYPEOF):
323
+ self.pos = saved
324
+ return false
325
+ self.parseTypeAnn()
326
+ val result = self.check(T.NEWLINE) or self.check(T.EOF)
327
+ self.pos = saved
328
+ return result
329
+ catch(e):
330
+ self.pos = saved
331
+ return false
332
+
333
+ fn parseTypeDecl():
334
+ val loc = self.eat(T.TYPE)
335
+ val name = self.eat(T.IDENT).value
336
+ val typeParams = []
337
+ if self.check(T.LT):
338
+ self.pos = self.pos + 1
339
+ while not self.check(T.GT) and not self.check(T.EOF):
340
+ typeParams.push(self.eat(T.IDENT).value)
341
+ if not self.maybe(T.COMMA): break
342
+ self.eat(T.GT)
343
+ self.eat(T.EQ)
344
+ val variants = []
345
+ var running = true
346
+ while running:
347
+ val vname = self.eat(T.IDENT).value
348
+ val fields = []
349
+ val fieldTypes = {}
350
+ if self.check(T.LPAREN):
351
+ self.eat(T.LPAREN)
352
+ while not self.check(T.RPAREN) and not self.check(T.EOF):
353
+ val ftok = self.peek()
354
+ var fname = ''
355
+ if ftok.type == T.IDENT:
356
+ fname = self.skip().value
357
+ else:
358
+ fname = self.skip().value
359
+ if self.maybe(T.COLON):
360
+ fieldTypes[fname] = self.parseTypeAnn()
361
+ fields.push(fname)
362
+ if not self.maybe(T.COMMA): break
363
+ self.eat(T.RPAREN)
364
+ variants.push({ name: vname, fields, fieldTypes })
365
+ if not self.check(T.PIPEB): running = false
366
+ else: self.pos = self.pos + 1
367
+ self.skipNewlines()
368
+ return { type: 'TypeDecl', name, variants, loc }
369
+
370
+ fn parseInterfaceDecl():
371
+ val loc = self.eat(T.INTERFACE)
372
+ val name = self.eat(T.IDENT).value
373
+ val typeParams = []
374
+ if self.check(T.LT):
375
+ self.pos = self.pos + 1
376
+ while not self.check(T.GT) and not self.check(T.EOF):
377
+ typeParams.push(self.eat(T.IDENT).value)
378
+ if not self.maybe(T.COMMA): break
379
+ self.eat(T.GT)
380
+ val superInterfaces = []
381
+ if self.maybe(T.EXTENDS):
382
+ superInterfaces.push(self.eat(T.IDENT).value)
383
+ while self.maybe(T.COMMA): superInterfaces.push(self.eat(T.IDENT).value)
384
+ self.eat(T.COLON)
385
+ if self.check(T.NEWLINE): self.pos = self.pos + 1
386
+ self.eat(T.INDENT)
387
+ val members = []
388
+ while not self.check(T.DEDENT) and not self.check(T.EOF):
389
+ self.skipNewlines()
390
+ if self.check(T.DEDENT) or self.check(T.EOF): break
391
+ val mods = self.parseAccessModifiers()
392
+ if self.check(T.FN):
393
+ self.eat(T.FN)
394
+ val mname = self.eat(T.IDENT).value
395
+ val params = self.parseParamList()
396
+ var retType = null
397
+ if self.maybe(T.ARROW): retType = self.parseTypeAnn()
398
+ self.skipNewlines()
399
+ members.push({ kind: 'method', name: mname, params, retType, modifiers: mods, isAsync: false })
400
+ else if self.check(T.IDENT):
401
+ val fname = self.eat(T.IDENT).value
402
+ var optional = false
403
+ if self.check(T.QUESTION):
404
+ self.pos = self.pos + 1
405
+ optional = true
406
+ self.eat(T.COLON)
407
+ val ftype = self.parseTypeAnn()
408
+ self.skipNewlines()
409
+ members.push({ kind: 'field', name: fname, typeAnn: ftype, optional, modifiers: mods })
410
+ else:
411
+ self.skip()
412
+ self.maybe(T.DEDENT)
413
+ return { type: 'InterfaceDecl', name, typeParams, superInterfaces, members, loc }
414
+
415
+ fn parseEnumDecl():
416
+ val loc = self.eat(T.ENUM)
417
+ val name = self.eat(T.IDENT).value
418
+ self.eat(T.COLON)
419
+ if self.check(T.NEWLINE):
420
+ self.pos = self.pos + 1
421
+ self.eat(T.INDENT)
422
+ val members = []
423
+ var autoIndex = 0
424
+ while not self.check(T.DEDENT) and not self.check(T.EOF):
425
+ self.skipNewlines()
426
+ if self.check(T.DEDENT) or self.check(T.EOF): break
427
+ val mname = self.eat(T.IDENT).value
428
+ var value = { type: 'NumberLit', value: autoIndex }
429
+ if self.maybe(T.EQ):
430
+ val parsed = self.parseExpr()
431
+ value = parsed
432
+ if parsed.type == 'NumberLit': autoIndex = parsed.value
433
+ else:
434
+ value = { type: 'NumberLit', value: autoIndex }
435
+ autoIndex = autoIndex + 1
436
+ self.skipNewlines()
437
+ members.push({ name: mname, value })
438
+ self.maybe(T.DEDENT)
439
+ return { type: 'EnumDecl', name, members, loc }
440
+
441
+ fn parseIf():
442
+ val loc = self.eat(T.IF)
443
+ val cond = self.parseExpr()
444
+ val then = self.parseBlock()
445
+ val elseifs = []
446
+ var else_ = null
447
+ self.skipNewlines()
448
+ while self.check(T.ELSE):
449
+ self.pos = self.pos + 1
450
+ if self.check(T.IF):
451
+ self.pos = self.pos + 1
452
+ val eic = self.parseExpr()
453
+ val eib = self.parseBlock()
454
+ elseifs.push({ cond: eic, body: eib })
455
+ self.skipNewlines()
456
+ else:
457
+ else_ = self.parseBlock()
458
+ break
459
+ return { type: 'IfStmt', cond, then, elseifs, else_, loc }
460
+
461
+ fn parseFor():
462
+ val loc = self.eat(T.FOR)
463
+ var isAwait = false
464
+ if self.check(T.AWAIT):
465
+ self.pos = self.pos + 1
466
+ isAwait = true
467
+ val varName = self.eat(T.IDENT).value
468
+ self.eat(T.IN)
469
+ val iter = self.parseExpr()
470
+ val body = self.parseBlock()
471
+ return { type: 'ForInStmt', "var": varName, iter, body, isAwait, loc }
472
+
473
+ fn parseWhile():
474
+ val loc = self.eat(T.WHILE)
475
+ val cond = self.parseExpr()
476
+ val body = self.parseBlock()
477
+ return { type: 'WhileStmt', cond, body, loc }
478
+
479
+ fn parseDoWhile():
480
+ val loc = self.eat(T.DO)
481
+ val body = self.parseBlock()
482
+ self.skipNewlines()
483
+ self.eat(T.WHILE)
484
+ val cond = self.parseExpr()
485
+ self.skipNewlines()
486
+ return { type: 'DoWhileStmt', body, cond, loc }
487
+
488
+ fn parseMatch():
489
+ val loc = self.eat(T.MATCH)
490
+ val subject = self.parseExpr()
491
+ self.eat(T.COLON)
492
+ if self.check(T.NEWLINE): self.pos = self.pos + 1
493
+ self.eat(T.INDENT)
494
+ val arms = []
495
+ while not self.check(T.DEDENT) and not self.check(T.EOF):
496
+ self.skipNewlines()
497
+ if self.check(T.DEDENT) or self.check(T.EOF): break
498
+ self.eat(T.WHEN)
499
+ val pattern = self.parsePattern()
500
+ var guard = null
501
+ if self.check(T.IF):
502
+ self.pos = self.pos + 1
503
+ guard = self.parseExpr()
504
+ if self.check(T.ARROW):
505
+ self.pos = self.pos + 1
506
+ val expr = self.parseExpr()
507
+ self.skipNewlines()
508
+ arms.push({ pattern, guard, body: [{ type: 'ExprStmt', expr }], inline: true })
509
+ else if self.check(T.COLON):
510
+ val isInline = self.peek(1).type != T.NEWLINE
511
+ val body = self.parseBlock()
512
+ val inlineArm = isInline and body.length == 1 and body[0].type == 'ExprStmt'
513
+ arms.push({ pattern, guard, body, inline: inlineArm })
514
+ self.maybe(T.DEDENT)
515
+ return { type: 'MatchStmt', subject, arms, loc }
516
+
517
+ fn parsePattern():
518
+ if self.check(T.WILDCARD):
519
+ self.skip()
520
+ return { type: 'WildcardPat' }
521
+ if self.check(T.IDENT) and self.peek(1).type == T.LPAREN:
522
+ val vname = self.eat(T.IDENT).value
523
+ self.eat(T.LPAREN)
524
+ val bindings = []
525
+ while not self.check(T.RPAREN) and not self.check(T.EOF):
526
+ if self.check(T.WILDCARD):
527
+ bindings.push('_')
528
+ self.pos = self.pos + 1
529
+ else:
530
+ bindings.push(self.eat(T.IDENT).value)
531
+ if not self.maybe(T.COMMA): break
532
+ self.eat(T.RPAREN)
533
+ return { type: 'VariantPat', variant: vname, bindings }
534
+ var left = self.parsePrimary()
535
+ while self.check(T.DOT):
536
+ self.pos = self.pos + 1
537
+ val prop = self.skip().value
538
+ left = { type: 'MemberExpr', obj: left, prop }
539
+ if self.check(T.DOTDOT):
540
+ self.pos = self.pos + 1
541
+ val right = self.parsePrimary()
542
+ return { type: 'RangePat', start: left, end: right }
543
+ return { type: 'LiteralPat', value: left }
544
+
545
+ fn parseReturn():
546
+ val loc = self.eat(T.RETURN)
547
+ var value = null
548
+ if not self.at(T.NEWLINE, T.EOF, T.DEDENT):
549
+ value = self.parseExpr()
550
+ self.skipNewlines()
551
+ return { type: 'ReturnStmt', value, loc }
552
+
553
+ fn parseTryCatch():
554
+ val loc = self.eat(T.TRY)
555
+ val tryBody = self.parseBlock()
556
+ var catchParam = null
557
+ var catchBody = null
558
+ var finallyBody = null
559
+ self.skipNewlines()
560
+ if self.check(T.CATCH):
561
+ self.pos = self.pos + 1
562
+ if self.check(T.LPAREN):
563
+ self.pos = self.pos + 1
564
+ catchParam = self.eat(T.IDENT).value
565
+ if self.maybe(T.COLON): self.parseTypeAnn()
566
+ self.eat(T.RPAREN)
567
+ catchBody = self.parseBlock()
568
+ self.skipNewlines()
569
+ if self.check(T.FINALLY):
570
+ self.pos = self.pos + 1
571
+ finallyBody = self.parseBlock()
572
+ return { type: 'TryCatchStmt', tryBody, catchParam, catchBody, finallyBody, loc }
573
+
574
+ fn parseThrow():
575
+ val loc = self.eat(T.THROW)
576
+ val value = self.parseExpr()
577
+ self.skipNewlines()
578
+ return { type: 'ThrowStmt', value, loc }
579
+
580
+ fn parseImport():
581
+ self.eat(T.IMPORT)
582
+ if self.check(T.STAR):
583
+ self.pos = self.pos + 1
584
+ self.eat(T.AS)
585
+ val namespaceName = self.eat(T.IDENT).value
586
+ self.eat(T.FROM)
587
+ val source = self.eat(T.STRING).value
588
+ self.skipNewlines()
589
+ return { type: 'ImportDecl', names: [], defaultName: null, namespaceName, source }
590
+ if self.check(T.IDENT):
591
+ val defaultName = self.eat(T.IDENT).value
592
+ self.eat(T.FROM)
593
+ val source = self.eat(T.STRING).value
594
+ self.skipNewlines()
595
+ return { type: 'ImportDecl', names: [], defaultName, source }
596
+ val names = []
597
+ if self.maybe(T.LBRACE):
598
+ while not self.check(T.RBRACE) and not self.check(T.EOF):
599
+ val name = self.eat(T.IDENT).value
600
+ var alias = name
601
+ if self.check(T.AS):
602
+ self.pos = self.pos + 1
603
+ alias = self.eat(T.IDENT).value
604
+ names.push({ name, alias })
605
+ if not self.maybe(T.COMMA): break
606
+ self.eat(T.RBRACE)
607
+ self.eat(T.FROM)
608
+ val source = self.eat(T.STRING).value
609
+ self.skipNewlines()
610
+ return { type: 'ImportDecl', names, defaultName: null, source }
611
+
612
+ fn parseExport():
613
+ self.eat(T.EXPORT)
614
+ if self.check(T.DEFAULT):
615
+ self.pos = self.pos + 1
616
+ if self.check(T.ASYNC):
617
+ self.pos = self.pos + 1
618
+ val decl = self.parseFnDecl(true)
619
+ return { type: 'ExportDecl', isDefault: true, decl }
620
+ if self.check(T.FN):
621
+ val decl = self.parseFnDecl(false)
622
+ return { type: 'ExportDecl', isDefault: true, decl }
623
+ val value = self.parseExpr()
624
+ self.skipNewlines()
625
+ return { type: 'ExportDecl', isDefault: true, decl: value }
626
+ if self.check(T.ASYNC):
627
+ self.pos = self.pos + 1
628
+ if not self.check(T.FN): self.err('Expected fn after async')
629
+ val decl = self.parseFnDecl(true)
630
+ return { type: 'ExportDecl', isDefault: false, decl }
631
+ val decl = self.parseOneStmt()
632
+ return { type: 'ExportDecl', isDefault: false, decl }
633
+
634
+ fn parseFnDecl(isAsync = false):
635
+ val loc = self.eat(T.FN)
636
+ var name = null
637
+ if self.check(T.IDENT) or self.check(T.NEW) or self.check(T.FROM) or self.check(T.AS) or self.check(T.DEFAULT) or self.check(T.IS) or self.check(T.IN) or self.check(T.TYPE):
638
+ name = self.skip().value
639
+ val params = self.parseParamList()
640
+ var retType = null
641
+ if self.check(T.ARROW):
642
+ self.pos = self.pos + 1
643
+ if self.isTypeAnnBeforeColon():
644
+ retType = self.parseTypeAnn()
645
+ val body = self.parseBlock()
646
+ return { type: 'FnDecl', name, params, retType, body, inline: false, async: isAsync, loc }
647
+ val body = self.parseExpr()
648
+ self.skipNewlines()
649
+ return { type: 'FnDecl', name, params, retType: null, body, inline: true, async: isAsync, loc }
650
+ if self.check(T.COLON):
651
+ if self.isColonReturnType():
652
+ self.pos = self.pos + 1
653
+ retType = self.parseTypeAnn()
654
+ if self.check(T.NEWLINE): self.pos = self.pos + 1
655
+ if self.check(T.INDENT):
656
+ self.pos = self.pos + 1
657
+ val body = self.parseStmtList()
658
+ self.maybe(T.DEDENT)
659
+ return { type: 'FnDecl', name, params, retType, body, inline: false, async: isAsync, loc }
660
+ val stmt = self.parseOneStmt()
661
+ return { type: 'FnDecl', name, params, retType, body: [stmt], inline: false, async: isAsync, loc }
662
+ val body = self.parseBlock()
663
+ return { type: 'FnDecl', name, params, retType: null, body, inline: false, async: isAsync, loc }
664
+ self.err('Expected -> or : after function signature')
665
+
666
+ fn parseAsyncFn():
667
+ self.eat(T.ASYNC)
668
+ if not self.check(T.FN): self.err('Expected fn after async')
669
+ return self.parseFnDecl(true)
670
+
671
+ fn parseParamList():
672
+ self.eat(T.LPAREN)
673
+ val params = []
674
+ while not self.check(T.RPAREN) and not self.check(T.EOF):
675
+ var rest = false
676
+ if self.check(T.DOTDOTDOT):
677
+ self.pos = self.pos + 1
678
+ rest = true
679
+ val name = self.eat(T.IDENT).value
680
+ var optional = false
681
+ var typeAnn = null
682
+ if not rest and self.check(T.QUESTION):
683
+ self.pos = self.pos + 1
684
+ optional = true
685
+ if not rest and self.maybe(T.COLON): typeAnn = self.parseTypeAnn()
686
+ var defaultVal = null
687
+ if not rest and self.maybe(T.EQ): defaultVal = self.parseExpr()
688
+ params.push({ name, typeAnn, optional, defaultVal, rest })
689
+ if rest: break
690
+ if not self.maybe(T.COMMA): break
691
+ self.eat(T.RPAREN)
692
+ return params
693
+
694
+ fn parseAccessModifiers():
695
+ val mods = new Set([])
696
+ var running = true
697
+ while running:
698
+ val t = self.peek().type
699
+ if t == T.PRIVATE or t == T.PUBLIC or t == T.PROTECTED or t == T.READONLY or t == T.STATIC or t == T.ABSTRACT or t == T.OVERRIDE:
700
+ mods.add(self.skip().value)
701
+ else:
702
+ running = false
703
+ return mods
704
+
705
+ fn parseClassDecl():
706
+ val loc = self.eat(T.CLASS)
707
+ val name = self.eat(T.IDENT).value
708
+ var superClass = null
709
+ val interfaces = []
710
+ val typeParams = []
711
+ if self.check(T.LT):
712
+ self.pos = self.pos + 1
713
+ typeParams.push(self.eat(T.IDENT).value)
714
+ while self.maybe(T.COMMA): typeParams.push(self.eat(T.IDENT).value)
715
+ self.eat(T.GT)
716
+ if self.maybe(T.EXTENDS): superClass = self.eat(T.IDENT).value
717
+ if self.maybe(T.IMPLEMENTS):
718
+ interfaces.push(self.eat(T.IDENT).value)
719
+ while self.maybe(T.COMMA): interfaces.push(self.eat(T.IDENT).value)
720
+ self.eat(T.COLON)
721
+ if self.check(T.NEWLINE):
722
+ self.pos = self.pos + 1
723
+ self.eat(T.INDENT)
724
+ val fields = []
725
+ val methods = []
726
+ while not self.check(T.DEDENT) and not self.check(T.EOF):
727
+ self.skipNewlines()
728
+ if self.check(T.DEDENT) or self.check(T.EOF): break
729
+ val mods = self.parseAccessModifiers()
730
+ if self.check(T.FN):
731
+ val m = self.parseFnDecl(false)
732
+ m.modifiers = mods
733
+ methods.push(m)
734
+ else if self.check(T.ASYNC):
735
+ val m = self.parseAsyncFn()
736
+ m.modifiers = mods
737
+ methods.push(m)
738
+ else if self.check(T.STATIC) and self.peek(1).type == T.FN:
739
+ self.skip()
740
+ val m = self.parseFnDecl(false)
741
+ m.modifiers = mods
742
+ m.modifiers.add('static')
743
+ methods.push(m)
744
+ else if self.check(T.IDENT):
745
+ val fname = self.eat(T.IDENT).value
746
+ var optional = false
747
+ if self.check(T.QUESTION):
748
+ self.pos = self.pos + 1
749
+ optional = true
750
+ self.eat(T.COLON)
751
+ val ftype = self.parseTypeAnn()
752
+ self.skipNewlines()
753
+ fields.push({ name: fname, typeAnn: ftype, optional, modifiers: mods })
754
+ else:
755
+ self.skip()
756
+ self.maybe(T.DEDENT)
757
+ return { type: 'ClassDecl', name, typeParams, superClass, interfaces, fields, methods, loc }
758
+
759
+ fn parseExprStmt():
760
+ val expr = self.parseExpr()
761
+ self.skipNewlines()
762
+ return { type: 'ExprStmt', expr }
763
+
764
+ fn parseExpr():
765
+ return self.parsePipe()
766
+
767
+ fn parsePipe():
768
+ var left = self.parseAssign()
769
+ var running = true
770
+ while running:
771
+ if self.check(T.PIPE):
772
+ self.pos = self.pos + 1
773
+ val right = self.parseAssign()
774
+ left = { type: 'PipeExpr', left, right }
775
+ else if self.check(T.NEWLINE):
776
+ var i = 1
777
+ while self.peek(i).type == T.NEWLINE: i = i + 1
778
+ if self.peek(i).type == T.PIPE:
779
+ while self.check(T.NEWLINE): self.pos = self.pos + 1
780
+ self.pos = self.pos + 1
781
+ val right = self.parseAssign()
782
+ left = { type: 'PipeExpr', left, right }
783
+ else:
784
+ running = false
785
+ else:
786
+ running = false
787
+ return left
788
+
789
+ fn parseAssign():
790
+ val left = self.parseTernary()
791
+ val t = self.peek().type
792
+ var op = ""
793
+ if t == T.EQ: op = '='
794
+ else if t == T.PLUSEQ: op = '+='
795
+ else if t == T.MINUSEQ: op = '-='
796
+ else if t == T.STAREQ: op = '*='
797
+ else if t == T.SLASHEQ: op = '/='
798
+ else if t == T.PERCENTEQ: op = '%='
799
+ if op:
800
+ self.pos = self.pos + 1
801
+ return { type: 'AssignExpr', target: left, op, value: self.parseAssign() }
802
+ return left
803
+
804
+ fn parseTernary():
805
+ val cond = self.parseNullish()
806
+ if self.maybe(T.QUESTION):
807
+ val then = self.parseNullish()
808
+ self.eat(T.COLON)
809
+ val else_ = self.parseTernary()
810
+ return { type: 'TernaryExpr', cond, then, else_ }
811
+ return cond
812
+
813
+ fn parseNullish():
814
+ var l = self.parseOr()
815
+ while self.check(T.NULLISH):
816
+ self.pos = self.pos + 1
817
+ val r = self.parseOr()
818
+ l = { type: 'BinaryExpr', op: '??', left: l, right: r }
819
+ return l
820
+
821
+ fn parseOr():
822
+ var l = self.parseAnd()
823
+ while self.check(T.OR) or self.check(T.OROR):
824
+ self.pos = self.pos + 1
825
+ val r = self.parseAnd()
826
+ l = { type: 'BinaryExpr', op: '||', left: l, right: r }
827
+ return l
828
+
829
+ fn parseAnd():
830
+ var l = self.parseBitOr()
831
+ while self.check(T.AND) or self.check(T.ANDAND):
832
+ self.pos = self.pos + 1
833
+ val r = self.parseBitOr()
834
+ l = { type: 'BinaryExpr', op: '&&', left: l, right: r }
835
+ return l
836
+
837
+ fn parseBitOr():
838
+ var l = self.parseBitXor()
839
+ while self.check(T.PIPEB):
840
+ self.pos = self.pos + 1
841
+ val r = self.parseBitXor()
842
+ l = { type: 'BinaryExpr', op: '|', left: l, right: r }
843
+ return l
844
+
845
+ fn parseBitXor():
846
+ var l = self.parseBitAnd()
847
+ while self.check(T.CARET):
848
+ self.pos = self.pos + 1
849
+ val r = self.parseBitAnd()
850
+ l = { type: 'BinaryExpr', op: '^', left: l, right: r }
851
+ return l
852
+
853
+ fn parseBitAnd():
854
+ var l = self.parseEq()
855
+ while self.check(T.AMPERSAND):
856
+ self.pos = self.pos + 1
857
+ val r = self.parseEq()
858
+ l = { type: 'BinaryExpr', op: '&', left: l, right: r }
859
+ return l
860
+
861
+ fn parseEq():
862
+ var l = self.parseRel()
863
+ while self.at(T.EQEQ, T.NEQ, T.EQEQEQ, T.NEQEQ):
864
+ val op = self.skip().value
865
+ val r = self.parseRel()
866
+ l = { type: 'BinaryExpr', op, left: l, right: r }
867
+ return l
868
+
869
+ fn parseRel():
870
+ var l = self.parseShift()
871
+ while self.at(T.LT, T.LTE, T.GT, T.GTE) or self.check(T.IN):
872
+ val op = self.skip().value
873
+ val r = self.parseShift()
874
+ l = { type: 'BinaryExpr', op, left: l, right: r }
875
+ return l
876
+
877
+ fn parseShift():
878
+ var l = self.parseRange()
879
+ while self.at(T.LSHIFT, T.RSHIFT):
880
+ val op = self.skip().value
881
+ val r = self.parseRange()
882
+ l = { type: 'BinaryExpr', op, left: l, right: r }
883
+ return l
884
+
885
+ fn parseRange():
886
+ val l = self.parseAdd()
887
+ if self.check(T.DOTDOT):
888
+ self.pos = self.pos + 1
889
+ val r = self.parseAdd()
890
+ return { type: 'RangeExpr', start: l, end: r }
891
+ return l
892
+
893
+ fn parseAdd():
894
+ var l = self.parseMul()
895
+ while self.at(T.PLUS, T.MINUS):
896
+ val op = self.skip().value
897
+ val r = self.parseMul()
898
+ l = { type: 'BinaryExpr', op, left: l, right: r }
899
+ return l
900
+
901
+ fn parseMul():
902
+ var l = self.parsePow()
903
+ while self.at(T.STAR, T.SLASH, T.PERCENT):
904
+ val op = self.skip().value
905
+ val r = self.parsePow()
906
+ l = { type: 'BinaryExpr', op, left: l, right: r }
907
+ return l
908
+
909
+ fn parsePow():
910
+ val l = self.parseUnary()
911
+ if self.check(T.STARSTAR):
912
+ self.pos = self.pos + 1
913
+ return { type: 'BinaryExpr', op: '**', left: l, right: self.parsePow() }
914
+ return l
915
+
916
+ fn parseUnary():
917
+ if self.check(T.MINUS):
918
+ self.pos = self.pos + 1
919
+ return { type: 'UnaryExpr', op: '-', operand: self.parseUnary() }
920
+ if self.check(T.NOT):
921
+ self.pos = self.pos + 1
922
+ return { type: 'UnaryExpr', op: '!', operand: self.parseUnary() }
923
+ if self.check(T.BANG):
924
+ self.pos = self.pos + 1
925
+ return { type: 'UnaryExpr', op: '!', operand: self.parseUnary() }
926
+ if self.check(T.TILDE):
927
+ self.pos = self.pos + 1
928
+ return { type: 'UnaryExpr', op: '~', operand: self.parseUnary() }
929
+ if self.check(T.PLUSPLUS):
930
+ self.pos = self.pos + 1
931
+ return { type: 'UpdateExpr', op: '++', prefix: true, operand: self.parseUnary() }
932
+ if self.check(T.MINUSMINUS):
933
+ self.pos = self.pos + 1
934
+ return { type: 'UpdateExpr', op: '--', prefix: true, operand: self.parseUnary() }
935
+ if self.check(T.AWAIT):
936
+ self.pos = self.pos + 1
937
+ return { type: 'AwaitExpr', operand: self.parseUnary() }
938
+ if self.check(T.TYPEOF):
939
+ self.pos = self.pos + 1
940
+ return { type: 'TypeofExpr', operand: self.parseUnary() }
941
+ return self.parseLambdaOrPostfix()
942
+
943
+ fn parseLambdaOrPostfix():
944
+ val saved = self.pos
945
+ if self.check(T.IDENT) or self.check(T.WILDCARD):
946
+ val name = self.skip().value ?? '_'
947
+ if self.check(T.ARROW):
948
+ self.pos = self.pos + 1
949
+ val body = self.parseExpr()
950
+ return { type: 'LambdaExpr', params: [{ name }], body }
951
+ self.pos = saved
952
+ return self.parsePostfix()
953
+
954
+ fn parsePostfix():
955
+ var expr = self.parsePrimary()
956
+ var running = true
957
+ while running:
958
+ if self.check(T.PLUSPLUS):
959
+ self.pos = self.pos + 1
960
+ expr = { type: 'UpdateExpr', op: '++', prefix: false, operand: expr }
961
+ else if self.check(T.MINUSMINUS):
962
+ self.pos = self.pos + 1
963
+ expr = { type: 'UpdateExpr', op: '--', prefix: false, operand: expr }
964
+ else if self.check(T.DOT):
965
+ self.pos = self.pos + 1
966
+ val propTok = self.peek()
967
+ val prop = self.skip().value
968
+ expr = { type: 'MemberExpr', obj: expr, prop }
969
+ else if self.check(T.QUESTIONDOT):
970
+ self.pos = self.pos + 1
971
+ if self.check(T.LPAREN):
972
+ val args = self.parseArgList()
973
+ expr = { type: 'OptCallExpr', callee: expr, args }
974
+ else if self.check(T.LBRACKET):
975
+ self.pos = self.pos + 1
976
+ val idx = self.parseExpr()
977
+ self.eat(T.RBRACKET)
978
+ expr = { type: 'OptIndexExpr', obj: expr, idx }
979
+ else:
980
+ val prop = self.skip().value
981
+ expr = { type: 'OptMemberExpr', obj: expr, prop }
982
+ else if self.check(T.INSTANCEOF):
983
+ self.pos = self.pos + 1
984
+ val right = self.eat(T.IDENT).value
985
+ expr = { type: 'BinaryExpr', op: 'instanceof', left: expr, right: { type: 'Identifier', name: right } }
986
+ else if self.check(T.AS):
987
+ self.pos = self.pos + 1
988
+ if self.check(T.CONST):
989
+ self.pos = self.pos + 1
990
+ expr = { type: 'AsConstExpr', expr }
991
+ else:
992
+ val castType = self.parseTypeAnn()
993
+ expr = { type: 'CastExpr', expr, castType }
994
+ else if self.check(T.SATISFIES):
995
+ self.pos = self.pos + 1
996
+ val satType = self.parseTypeAnn()
997
+ expr = { type: 'SatisfiesExpr', expr, satType }
998
+ else if self.check(T.IS):
999
+ self.pos = self.pos + 1
1000
+ val isType = self.parseTypeAnn()
1001
+ expr = { type: 'IsExpr', expr, isType }
1002
+ else if self.check(T.BANG):
1003
+ self.pos = self.pos + 1
1004
+ expr = { type: 'NonNullExpr', expr }
1005
+ else if self.check(T.LBRACKET):
1006
+ self.pos = self.pos + 1
1007
+ val idx = self.parseExpr()
1008
+ self.eat(T.RBRACKET)
1009
+ expr = { type: 'IndexExpr', obj: expr, idx }
1010
+ else if self.check(T.LPAREN):
1011
+ val args = self.parseArgList()
1012
+ if self.check(T.ARROW):
1013
+ self.pos = self.pos + 1
1014
+ val body = self.parseExpr()
1015
+ val lambdaParams = args.map(a -> ({ name: a.type == 'Identifier' ? a.name : '_' }))
1016
+ return { type: 'LambdaExpr', params: lambdaParams, body }
1017
+ expr = { type: 'CallExpr', callee: expr, args }
1018
+ else:
1019
+ running = false
1020
+ return expr
1021
+
1022
+ fn parseArgList():
1023
+ self.eat(T.LPAREN)
1024
+ val args = []
1025
+ while not self.check(T.RPAREN) and not self.check(T.EOF):
1026
+ if self.check(T.DOTDOTDOT):
1027
+ self.pos = self.pos + 1
1028
+ args.push({ type: 'SpreadExpr', expr: self.parseExpr() })
1029
+ else:
1030
+ args.push(self.parseExpr())
1031
+ if not self.maybe(T.COMMA): break
1032
+ self.eat(T.RPAREN)
1033
+ return args
1034
+
1035
+ fn parsePrimary():
1036
+ val tok = self.peek()
1037
+ if tok.type == T.NUMBER:
1038
+ self.pos = self.pos + 1
1039
+ return { type: 'NumberLit', value: tok.value, loc: tok }
1040
+ if tok.type == T.BOOL:
1041
+ self.pos = self.pos + 1
1042
+ return { type: 'BoolLit', value: tok.value, loc: tok }
1043
+ if tok.type == T.NULL:
1044
+ self.pos = self.pos + 1
1045
+ return { type: 'NullLit', loc: tok }
1046
+ if tok.type == T.SELF:
1047
+ self.pos = self.pos + 1
1048
+ return { type: 'SelfExpr', loc: tok }
1049
+ if tok.type == T.WILDCARD:
1050
+ self.pos = self.pos + 1
1051
+ return { type: 'Identifier', name: '_', loc: tok }
1052
+ if tok.type == T.IDENT:
1053
+ self.pos = self.pos + 1
1054
+ return { type: 'Identifier', name: tok.value, loc: tok }
1055
+ if tok.type == T.STRING:
1056
+ self.pos = self.pos + 1
1057
+ if tok.value and tok.value.template:
1058
+ return { type: 'TemplateLit', parts: tok.value.parts, loc: tok }
1059
+ return { type: 'StringLit', value: tok.value, loc: tok }
1060
+ if tok.type == T.REGEX:
1061
+ self.pos = self.pos + 1
1062
+ return { type: 'RegexLit', value: tok.value, loc: tok }
1063
+ if tok.type == T.NEW:
1064
+ self.pos = self.pos + 1
1065
+ val callee = self.eat(T.IDENT).value
1066
+ val args = self.parseArgList()
1067
+ return { type: 'NewExpr', callee, args }
1068
+ if tok.type == T.MATCH:
1069
+ return self.parseMatch()
1070
+ if tok.type == T.FN:
1071
+ self.pos = self.pos + 1
1072
+ val params = self.parseParamList()
1073
+ if self.check(T.ARROW):
1074
+ self.pos = self.pos + 1
1075
+ if self.isTypeAnnBeforeColon():
1076
+ val retType = self.parseTypeAnn()
1077
+ val body = self.parseBlock()
1078
+ return { type: 'FnDecl', name: null, params, retType, body, inline: false, async: false, loc: tok }
1079
+ val body = self.parseExpr()
1080
+ return { type: 'FnDecl', name: null, params, retType: null, body, inline: true, async: false, loc: tok }
1081
+ if self.check(T.COLON):
1082
+ val body = self.parseBlock()
1083
+ return { type: 'FnDecl', name: null, params, retType: null, body, inline: false, async: false, loc: tok }
1084
+ self.err('Expected -> or : after anonymous fn')
1085
+ if tok.type == T.LPAREN:
1086
+ self.pos = self.pos + 1
1087
+ if self.check(T.RPAREN):
1088
+ self.pos = self.pos + 1
1089
+ if self.check(T.ARROW):
1090
+ self.pos = self.pos + 1
1091
+ val body = self.parseExpr()
1092
+ return { type: 'LambdaExpr', params: [], body }
1093
+ return { type: 'NullLit' }
1094
+ val first = self.parseExpr()
1095
+ if self.check(T.RPAREN):
1096
+ self.pos = self.pos + 1
1097
+ if self.check(T.ARROW):
1098
+ self.pos = self.pos + 1
1099
+ val body = self.parseExpr()
1100
+ val pname = first.type == 'Identifier' ? first.name : '_'
1101
+ return { type: 'LambdaExpr', params: [{ name: pname }], body }
1102
+ return first
1103
+ val items = [first]
1104
+ while self.maybe(T.COMMA): items.push(self.parseExpr())
1105
+ self.eat(T.RPAREN)
1106
+ if self.check(T.ARROW):
1107
+ self.pos = self.pos + 1
1108
+ val body = self.parseExpr()
1109
+ val lambdaParams = items.map(i -> ({ name: i.type == 'Identifier' ? i.name : '_' }))
1110
+ return { type: 'LambdaExpr', params: lambdaParams, body }
1111
+ return items[0]
1112
+ if tok.type == T.LBRACKET:
1113
+ self.pos = self.pos + 1
1114
+ val items = []
1115
+ while not self.check(T.RBRACKET) and not self.check(T.EOF):
1116
+ if self.check(T.DOTDOTDOT):
1117
+ self.pos = self.pos + 1
1118
+ items.push({ type: 'SpreadExpr', expr: self.parseExpr() })
1119
+ else:
1120
+ items.push(self.parseExpr())
1121
+ if not self.maybe(T.COMMA): break
1122
+ self.eat(T.RBRACKET)
1123
+ return { type: 'ArrayExpr', items }
1124
+ if tok.type == T.LBRACE:
1125
+ self.pos = self.pos + 1
1126
+ val pairs = []
1127
+ while not self.check(T.RBRACE) and not self.check(T.EOF):
1128
+ if self.check(T.DOTDOTDOT):
1129
+ self.pos = self.pos + 1
1130
+ pairs.push({ spread: true, value: self.parseExpr() })
1131
+ if not self.maybe(T.COMMA): break
1132
+ continue
1133
+ val key = self.check(T.STRING) ? self.eat(T.STRING).value : (self.check(T.IDENT) ? self.skip().value : self.skip().value)
1134
+ if not self.check(T.COLON):
1135
+ pairs.push({ key, value: { type: 'Identifier', name: key } })
1136
+ else:
1137
+ self.eat(T.COLON)
1138
+ val v = self.parseExpr()
1139
+ pairs.push({ key, value: v })
1140
+ if not self.maybe(T.COMMA): break
1141
+ self.eat(T.RBRACE)
1142
+ return { type: 'ObjectExpr', pairs }
1143
+ self.err("Unexpected token: {tok.type} ({JSON.stringify(tok.value)})")
1144
+
1145
+ export fn makeParser(tokens):
1146
+ return new Parser(tokens, 0)