@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.
- package/CHANGELOG.md +103 -0
- package/README.md +1089 -0
- package/bin/flux.js +1397 -0
- package/dist/flux.cjs.js +6664 -0
- package/dist/flux.esm.js +6674 -0
- package/dist/flux.min.js +263 -0
- package/index.d.ts +202 -0
- package/index.js +26 -0
- package/package.json +77 -0
- package/scripts/build.js +76 -0
- package/src/bundler.js +216 -0
- package/src/checker.js +322 -0
- package/src/codegen.js +785 -0
- package/src/css-preprocessor.js +399 -0
- package/src/formatter.js +140 -0
- package/src/jsx.js +480 -0
- package/src/lexer.js +518 -0
- package/src/linter.js +758 -0
- package/src/mangler.js +280 -0
- package/src/parser.js +1671 -0
- package/src/self/bundler.flux +167 -0
- package/src/self/bundler.js +187 -0
- package/src/self/checker.flux +249 -0
- package/src/self/checker.js +338 -0
- package/src/self/codegen.flux +555 -0
- package/src/self/codegen.js +784 -0
- package/src/self/css-preprocessor.flux +373 -0
- package/src/self/css-preprocessor.js +387 -0
- package/src/self/formatter.flux +93 -0
- package/src/self/formatter.js +114 -0
- package/src/self/jsx.flux +430 -0
- package/src/self/jsx.js +396 -0
- package/src/self/lexer.flux +529 -0
- package/src/self/lexer.js +709 -0
- package/src/self/lexer.stage2.js +700 -0
- package/src/self/linter.flux +515 -0
- package/src/self/linter.js +804 -0
- package/src/self/mangler.flux +253 -0
- package/src/self/mangler.js +348 -0
- package/src/self/parser.flux +1146 -0
- package/src/self/parser.js +1571 -0
- package/src/self/sourcemap.flux +66 -0
- package/src/self/sourcemap.js +72 -0
- package/src/self/stdlib.flux +356 -0
- package/src/self/stdlib.js +396 -0
- package/src/self/test-runner.flux +201 -0
- package/src/self/test-runner.js +132 -0
- package/src/self/transpiler.flux +123 -0
- package/src/self/transpiler.js +83 -0
- package/src/self/type-checker.flux +821 -0
- package/src/self/type-checker.js +1106 -0
- package/src/sourcemap.js +82 -0
- package/src/stdlib.js +436 -0
- package/src/test-runner.js +239 -0
- package/src/transpiler.js +172 -0
- 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)
|