@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,555 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Flux Self-Hosted Code Generator
|
|
3
|
+
// src/self/codegen.flux — written in Flux, compiled by stage-0
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
import { Lexer, lexerize, T } from './lexer'
|
|
7
|
+
import { Parser, makeParser } from './parser'
|
|
8
|
+
|
|
9
|
+
fn extractFormatSpec(raw):
|
|
10
|
+
val ci = raw.lastIndexOf(':')
|
|
11
|
+
if ci < 1: return null
|
|
12
|
+
val spec = raw.slice(ci + 1).trim()
|
|
13
|
+
if spec.length > 0 and /[.<>^,dbeEfFgGoOxXs%bcn]/.test(spec) and /^([.<>^0\-+ #,]*[0-9]*\.?[0-9]*[dbeEfFgGoOxXs%bcn]?[,]?)$/.test(spec):
|
|
14
|
+
return { expr: raw.slice(0, ci).trim(), fmt: spec }
|
|
15
|
+
return null
|
|
16
|
+
|
|
17
|
+
val FMT_HELPER = `
|
|
18
|
+
function _fmt(v, s) {
|
|
19
|
+
if (s === ',') return (+v).toLocaleString();
|
|
20
|
+
if (s === '%') return ((+v)*100).toFixed(0)+'%';
|
|
21
|
+
var m = s.match(/^([0-9,]*)?\.([0-9]+)([fdgGeEb%x])$/);
|
|
22
|
+
if (m) {
|
|
23
|
+
var d=+m[2], t=m[3], comma=s[0]===',';
|
|
24
|
+
if (t==='f'||t==='d') return comma ? (+v).toLocaleString(void 0,{minimumFractionDigits:d,maximumFractionDigits:d}) : (+v).toFixed(d);
|
|
25
|
+
if (t==='e'||t==='E') return (+v).toExponential(d);
|
|
26
|
+
if (t==='%') return ((+v)*100).toFixed(d)+'%';
|
|
27
|
+
if (t==='b') return Math.round(+v).toString(2);
|
|
28
|
+
if (t==='x') return Math.round(+v).toString(16);
|
|
29
|
+
}
|
|
30
|
+
var m2 = s.match(/^([0-9]*)d$/); if (m2) return Math.round(+v).toString();
|
|
31
|
+
return String(v);
|
|
32
|
+
}`
|
|
33
|
+
|
|
34
|
+
fn buildClassRegistry(ast):
|
|
35
|
+
val reg = {}
|
|
36
|
+
for node in ast.body:
|
|
37
|
+
val n = node.type == 'ExportDecl' ? node.decl : node
|
|
38
|
+
if n.type == 'ClassDecl':
|
|
39
|
+
reg[n.name] = { fields: n.fields, superClass: n.superClass }
|
|
40
|
+
return reg
|
|
41
|
+
|
|
42
|
+
fn getAllFields(name, reg, visited):
|
|
43
|
+
val vis = visited ?? new Set([])
|
|
44
|
+
if not name or not reg[name] or vis.has(name): return []
|
|
45
|
+
vis.add(name)
|
|
46
|
+
val parent = getAllFields(reg[name].superClass, reg, vis)
|
|
47
|
+
return [...parent, ...reg[name].fields]
|
|
48
|
+
|
|
49
|
+
export class CodeGenerator:
|
|
50
|
+
ind: string
|
|
51
|
+
level: int
|
|
52
|
+
lines: any[]
|
|
53
|
+
clsReg: any
|
|
54
|
+
smBuilder: any
|
|
55
|
+
_needsFmt: bool
|
|
56
|
+
_loopDepth: int
|
|
57
|
+
|
|
58
|
+
fn i():
|
|
59
|
+
var s = ''
|
|
60
|
+
var n = self.level
|
|
61
|
+
while n > 0:
|
|
62
|
+
s += self.ind
|
|
63
|
+
n = n - 1
|
|
64
|
+
return s
|
|
65
|
+
|
|
66
|
+
fn emit(s):
|
|
67
|
+
self.lines.push(self.i() + s)
|
|
68
|
+
|
|
69
|
+
fn emitRaw(s):
|
|
70
|
+
self.lines.push(s)
|
|
71
|
+
|
|
72
|
+
fn blank():
|
|
73
|
+
self.lines.push('')
|
|
74
|
+
|
|
75
|
+
fn indIn():
|
|
76
|
+
self.level = self.level + 1
|
|
77
|
+
|
|
78
|
+
fn indOut():
|
|
79
|
+
if self.level > 0: self.level = self.level - 1
|
|
80
|
+
|
|
81
|
+
fn generate(ast):
|
|
82
|
+
self.clsReg = buildClassRegistry(ast)
|
|
83
|
+
self.lines = []
|
|
84
|
+
self.level = 0
|
|
85
|
+
self._needsFmt = false
|
|
86
|
+
self.emit('// Generated by Flux Transpiler v3.1.0 (self-hosted)')
|
|
87
|
+
self.emit('"use strict";')
|
|
88
|
+
self.blank()
|
|
89
|
+
for node in ast.body: self.genStmt(node)
|
|
90
|
+
if self._needsFmt:
|
|
91
|
+
self.lines.splice(2, 0, FMT_HELPER)
|
|
92
|
+
return { code: self.lines.join('\n'), smBuilder: self.smBuilder }
|
|
93
|
+
|
|
94
|
+
fn genStmt(node):
|
|
95
|
+
if node.type == 'VarDecl': self.genVar(node)
|
|
96
|
+
else if node.type == 'DestructureDecl': self.genDestructure(node)
|
|
97
|
+
else if node.type == 'FnDecl': self.genFn(node, '')
|
|
98
|
+
else if node.type == 'ClassDecl': self.genClass(node)
|
|
99
|
+
else if node.type == 'IfStmt': self.genIf(node)
|
|
100
|
+
else if node.type == 'ForInStmt': self.genFor(node)
|
|
101
|
+
else if node.type == 'WhileStmt': self.genWhile(node)
|
|
102
|
+
else if node.type == 'MatchStmt': self.genMatch(node)
|
|
103
|
+
else if node.type == 'ReturnStmt': self.genReturn(node)
|
|
104
|
+
else if node.type == 'TryCatchStmt': self.genTryCatch(node)
|
|
105
|
+
else if node.type == 'ThrowStmt': self.genThrow(node)
|
|
106
|
+
else if node.type == 'DoWhileStmt': self.genDoWhile(node)
|
|
107
|
+
else if node.type == 'BreakStmt': self.emit('break;')
|
|
108
|
+
else if node.type == 'ContinueStmt': self.emit('continue;')
|
|
109
|
+
else if node.type == 'ImportDecl': self.genImport(node)
|
|
110
|
+
else if node.type == 'ExportDecl': self.genExport(node)
|
|
111
|
+
else if node.type == 'TypeDecl': self.genTypeDecl(node)
|
|
112
|
+
else if node.type == 'InterfaceDecl': self.genInterfaceDecl(node)
|
|
113
|
+
else if node.type == 'EnumDecl': self.genEnumDecl(node)
|
|
114
|
+
else if node.type == 'ExprStmt': self.emit(self.genExpr(node.expr) + ';')
|
|
115
|
+
else:
|
|
116
|
+
throw new Error("Unknown statement: {node.type}")
|
|
117
|
+
|
|
118
|
+
fn genVar(node):
|
|
119
|
+
val kw = node.kind == 'val' ? 'const' : 'let'
|
|
120
|
+
val init = node.init ? ' = ' + self.genExpr(node.init) : ''
|
|
121
|
+
self.emit(kw + ' ' + node.name + init + ';')
|
|
122
|
+
|
|
123
|
+
fn genObjPair(p):
|
|
124
|
+
if p.spread: return '...' + self.genExpr(p.value)
|
|
125
|
+
val isIdent = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(p.key)
|
|
126
|
+
val keyStr = isIdent ? p.key : '"' + p.key + '"'
|
|
127
|
+
if isIdent and p.value and p.value.type == 'Identifier' and p.value.name == p.key:
|
|
128
|
+
return p.key
|
|
129
|
+
return keyStr + ': ' + self.genExpr(p.value)
|
|
130
|
+
|
|
131
|
+
fn genDestructProp(p):
|
|
132
|
+
if p.rest: return '...' + p.key
|
|
133
|
+
var s = p.alias != p.key ? p.key + ': ' + p.alias : p.key
|
|
134
|
+
if p.defaultVal: s = s + ' = ' + self.genExpr(p.defaultVal)
|
|
135
|
+
return s
|
|
136
|
+
|
|
137
|
+
fn genDestructItem(p):
|
|
138
|
+
if not p: return ''
|
|
139
|
+
if p.rest: return '...' + p.name
|
|
140
|
+
var s = p.name
|
|
141
|
+
if p.defaultVal: s = s + ' = ' + self.genExpr(p.defaultVal)
|
|
142
|
+
return s
|
|
143
|
+
|
|
144
|
+
fn genDestructure(node):
|
|
145
|
+
val kw = node.kind == 'val' ? 'const' : 'let'
|
|
146
|
+
val init = self.genExpr(node.init)
|
|
147
|
+
if node.patternType == 'object':
|
|
148
|
+
val props = node.pattern.map(p -> self.genDestructProp(p)).join(', ')
|
|
149
|
+
self.emit(kw + ' { ' + props + ' } = ' + init + ';')
|
|
150
|
+
else:
|
|
151
|
+
val items = node.pattern.map(p -> self.genDestructItem(p)).join(', ')
|
|
152
|
+
self.emit(kw + ' [' + items + '] = ' + init + ';')
|
|
153
|
+
|
|
154
|
+
fn genFn(node, prefix):
|
|
155
|
+
val asyncKw = node.async ? 'async ' : ''
|
|
156
|
+
val name = node.name ?? ''
|
|
157
|
+
val params = node.params.map(p ->
|
|
158
|
+
p.rest ? '...' + p.name :
|
|
159
|
+
p.defaultVal ? p.name + ' = ' + self.genExpr(p.defaultVal) :
|
|
160
|
+
p.name
|
|
161
|
+
).join(', ')
|
|
162
|
+
if node.inline:
|
|
163
|
+
self.emit(prefix + asyncKw + 'function ' + name + '(' + params + ') { return ' + self.genExpr(node.body) + '; }')
|
|
164
|
+
else:
|
|
165
|
+
self.emit(prefix + asyncKw + 'function ' + name + '(' + params + ') {')
|
|
166
|
+
self.indIn()
|
|
167
|
+
for s in node.body: self.genStmt(s)
|
|
168
|
+
self.indOut()
|
|
169
|
+
self.emit('}')
|
|
170
|
+
|
|
171
|
+
fn genClass(node):
|
|
172
|
+
val ext = node.superClass ? ' extends ' + node.superClass : ''
|
|
173
|
+
self.emit('class ' + node.name + ext + ' {')
|
|
174
|
+
self.indIn()
|
|
175
|
+
val allFields = getAllFields(node.name, self.clsReg, null)
|
|
176
|
+
if allFields.length > 0:
|
|
177
|
+
val params = allFields.map(f -> f.name).join(', ')
|
|
178
|
+
self.emit('constructor(' + params + ') {')
|
|
179
|
+
self.indIn()
|
|
180
|
+
if node.superClass and self.clsReg[node.superClass]:
|
|
181
|
+
val parentFields = getAllFields(node.superClass, self.clsReg, null)
|
|
182
|
+
if parentFields.length > 0:
|
|
183
|
+
self.emit('super(' + parentFields.map(f -> f.name).join(', ') + ');')
|
|
184
|
+
for f in node.fields: self.emit('this.' + f.name + ' = ' + f.name + ';')
|
|
185
|
+
self.indOut()
|
|
186
|
+
self.emit('}')
|
|
187
|
+
self.blank()
|
|
188
|
+
for m in node.methods:
|
|
189
|
+
val asyncKw = m.async ? 'async ' : ''
|
|
190
|
+
val staticKw = (m.modifiers and m.modifiers.has('static')) ? 'static ' : ''
|
|
191
|
+
val params = m.params.map(p ->
|
|
192
|
+
p.rest ? '...' + p.name :
|
|
193
|
+
p.defaultVal ? p.name + ' = ' + self.genExpr(p.defaultVal) :
|
|
194
|
+
p.name
|
|
195
|
+
).join(', ')
|
|
196
|
+
if m.inline:
|
|
197
|
+
self.emit(staticKw + asyncKw + m.name + '(' + params + ') { return ' + self.genExpr(m.body) + '; }')
|
|
198
|
+
else:
|
|
199
|
+
self.emit(staticKw + asyncKw + m.name + '(' + params + ') {')
|
|
200
|
+
self.indIn()
|
|
201
|
+
for s in m.body: self.genStmt(s)
|
|
202
|
+
self.indOut()
|
|
203
|
+
self.emit('}')
|
|
204
|
+
self.blank()
|
|
205
|
+
self.indOut()
|
|
206
|
+
self.emit('}')
|
|
207
|
+
self.blank()
|
|
208
|
+
|
|
209
|
+
fn genIf(node):
|
|
210
|
+
self.emit('if (' + self.genExpr(node.cond) + ') {')
|
|
211
|
+
self.indIn()
|
|
212
|
+
for s in node.then: self.genStmt(s)
|
|
213
|
+
self.indOut()
|
|
214
|
+
self.emit('}')
|
|
215
|
+
for ei in node.elseifs:
|
|
216
|
+
self.emitRaw(self.i() + 'else if (' + self.genExpr(ei.cond) + ') {')
|
|
217
|
+
self.indIn()
|
|
218
|
+
for s in ei.body: self.genStmt(s)
|
|
219
|
+
self.indOut()
|
|
220
|
+
self.emit('}')
|
|
221
|
+
if node.else_:
|
|
222
|
+
self.emitRaw(self.i() + 'else {')
|
|
223
|
+
self.indIn()
|
|
224
|
+
for s in node.else_: self.genStmt(s)
|
|
225
|
+
self.indOut()
|
|
226
|
+
self.emit('}')
|
|
227
|
+
|
|
228
|
+
fn genFor(node):
|
|
229
|
+
val varName = node["var"]
|
|
230
|
+
val iter = node.iter
|
|
231
|
+
if iter.type == 'RangeExpr':
|
|
232
|
+
val s = self.genExpr(iter.start)
|
|
233
|
+
val e = self.genExpr(iter.end)
|
|
234
|
+
self.emit('for (let ' + varName + ' = ' + s + '; ' + varName + ' < ' + e + '; ' + varName + '++) {')
|
|
235
|
+
else if node.isAwait:
|
|
236
|
+
self.emit('for await (const ' + varName + ' of ' + self.genExpr(iter) + ') {')
|
|
237
|
+
else:
|
|
238
|
+
self.emit('for (const ' + varName + ' of ' + self.genExpr(iter) + ') {')
|
|
239
|
+
self._loopDepth = self._loopDepth + 1
|
|
240
|
+
self.indIn()
|
|
241
|
+
for s in node.body: self.genStmt(s)
|
|
242
|
+
self.indOut()
|
|
243
|
+
self._loopDepth = self._loopDepth - 1
|
|
244
|
+
self.emit('}')
|
|
245
|
+
|
|
246
|
+
fn genWhile(node):
|
|
247
|
+
self.emit('while (' + self.genExpr(node.cond) + ') {')
|
|
248
|
+
self._loopDepth = self._loopDepth + 1
|
|
249
|
+
self.indIn()
|
|
250
|
+
for s in node.body: self.genStmt(s)
|
|
251
|
+
self.indOut()
|
|
252
|
+
self._loopDepth = self._loopDepth - 1
|
|
253
|
+
self.emit('}')
|
|
254
|
+
|
|
255
|
+
fn genMatch(node):
|
|
256
|
+
val subj = self.genExpr(node.subject)
|
|
257
|
+
val arms = node.arms
|
|
258
|
+
var hasOpenIf = false
|
|
259
|
+
for arm in arms:
|
|
260
|
+
val pat = arm.pattern
|
|
261
|
+
var cond = ""
|
|
262
|
+
val bindings = []
|
|
263
|
+
if pat.type == 'WildcardPat':
|
|
264
|
+
cond = ""
|
|
265
|
+
else if pat.type == 'RangePat':
|
|
266
|
+
val lo = self.genExpr(pat.start)
|
|
267
|
+
val hi = self.genExpr(pat.end)
|
|
268
|
+
cond = subj + ' >= ' + lo + ' && ' + subj + ' <= ' + hi
|
|
269
|
+
else if pat.type == 'VariantPat':
|
|
270
|
+
cond = subj + '?.__type === "' + pat.variant + '"'
|
|
271
|
+
var bi = 0
|
|
272
|
+
for b in pat.bindings:
|
|
273
|
+
bindings.push('const ' + b + ' = ' + subj + '.__args[' + bi + '];')
|
|
274
|
+
bi = bi + 1
|
|
275
|
+
else:
|
|
276
|
+
val patExpr = self.genExpr(pat.value)
|
|
277
|
+
if pat.value.type == 'Identifier' and /^[A-Z]/.test(pat.value.name):
|
|
278
|
+
cond = '(' + subj + ' === ' + patExpr + ' || ' + subj + '?.__type === "' + pat.value.name + '")'
|
|
279
|
+
else:
|
|
280
|
+
cond = subj + ' === ' + patExpr
|
|
281
|
+
if arm.guard:
|
|
282
|
+
val guardSrc = self.genExpr(arm.guard)
|
|
283
|
+
if bindings.length > 0:
|
|
284
|
+
val rebindings = bindings.map(bx -> bx.replace('const ', 'var ')).join(' ')
|
|
285
|
+
val iife = '(function(){ ' + rebindings + ' return (' + guardSrc + '); }())'
|
|
286
|
+
cond = cond ? '(' + cond + ') && ' + iife : iife
|
|
287
|
+
else:
|
|
288
|
+
cond = cond ? '(' + cond + ') && (' + guardSrc + ')' : guardSrc
|
|
289
|
+
if not hasOpenIf and cond:
|
|
290
|
+
self.emit('if (' + cond + ') {')
|
|
291
|
+
hasOpenIf = true
|
|
292
|
+
else if not hasOpenIf and not cond:
|
|
293
|
+
self.emit('if (true) {')
|
|
294
|
+
hasOpenIf = true
|
|
295
|
+
else if hasOpenIf and cond:
|
|
296
|
+
self.emitRaw(self.i() + 'else if (' + cond + ') {')
|
|
297
|
+
else:
|
|
298
|
+
self.emitRaw(self.i() + 'else {')
|
|
299
|
+
self.indIn()
|
|
300
|
+
for b in bindings: self.emit(b)
|
|
301
|
+
if arm.inline:
|
|
302
|
+
val exprSrc = self.genExpr(arm.body[0].expr)
|
|
303
|
+
if self._loopDepth > 0:
|
|
304
|
+
self.emit(exprSrc + ';')
|
|
305
|
+
else:
|
|
306
|
+
self.emit('return ' + exprSrc + ';')
|
|
307
|
+
else:
|
|
308
|
+
for s in arm.body: self.genStmt(s)
|
|
309
|
+
self.indOut()
|
|
310
|
+
self.emit('}')
|
|
311
|
+
|
|
312
|
+
fn genInterfaceDecl(node):
|
|
313
|
+
self.blank()
|
|
314
|
+
self.emit('// interface ' + node.name)
|
|
315
|
+
self.blank()
|
|
316
|
+
|
|
317
|
+
fn genEnumDecl(node):
|
|
318
|
+
self.blank()
|
|
319
|
+
val pairs = node.members.map(m -> m.name + ': ' + self.genExpr(m.value)).join(', ')
|
|
320
|
+
self.emit('const ' + node.name + ' = Object.freeze({ ' + pairs + ' });')
|
|
321
|
+
self.blank()
|
|
322
|
+
|
|
323
|
+
fn genTypeDecl(node):
|
|
324
|
+
self.blank()
|
|
325
|
+
self.emit('// ADT type: ' + node.name)
|
|
326
|
+
for v in node.variants:
|
|
327
|
+
if v.fields.length == 0:
|
|
328
|
+
self.emit('const ' + v.name + ' = Object.freeze({ __type: "' + v.name + '", __args: [] });')
|
|
329
|
+
else:
|
|
330
|
+
val params = v.fields.join(', ')
|
|
331
|
+
val argsArr = '[' + v.fields.join(', ') + ']'
|
|
332
|
+
val fieldsObj = v.fields.map(f -> f + ': ' + f).join(', ')
|
|
333
|
+
self.emit('function ' + v.name + '(' + params + ') { return Object.freeze({ __type: "' + v.name + '", __args: ' + argsArr + ', ' + fieldsObj + ' }); }')
|
|
334
|
+
self.blank()
|
|
335
|
+
|
|
336
|
+
fn genReturn(node):
|
|
337
|
+
if node.value: self.emit('return ' + self.genExpr(node.value) + ';')
|
|
338
|
+
else: self.emit('return;')
|
|
339
|
+
|
|
340
|
+
fn genTryCatch(node):
|
|
341
|
+
self.emit('try {')
|
|
342
|
+
self.indIn()
|
|
343
|
+
for s in node.tryBody: self.genStmt(s)
|
|
344
|
+
self.indOut()
|
|
345
|
+
self.emit('}')
|
|
346
|
+
if node.catchBody:
|
|
347
|
+
val param = node.catchParam ? '(' + node.catchParam + ')' : '(_err)'
|
|
348
|
+
self.emitRaw(self.i() + 'catch ' + param + ' {')
|
|
349
|
+
self.indIn()
|
|
350
|
+
for s in node.catchBody: self.genStmt(s)
|
|
351
|
+
self.indOut()
|
|
352
|
+
self.emit('}')
|
|
353
|
+
if node.finallyBody:
|
|
354
|
+
self.emitRaw(self.i() + 'finally {')
|
|
355
|
+
self.indIn()
|
|
356
|
+
for s in node.finallyBody: self.genStmt(s)
|
|
357
|
+
self.indOut()
|
|
358
|
+
self.emit('}')
|
|
359
|
+
|
|
360
|
+
fn genThrow(node):
|
|
361
|
+
self.emit('throw ' + self.genExpr(node.value) + ';')
|
|
362
|
+
|
|
363
|
+
fn genDoWhile(node):
|
|
364
|
+
self.emit('do {')
|
|
365
|
+
self.indIn()
|
|
366
|
+
for s in node.body: self.genStmt(s)
|
|
367
|
+
self.indOut()
|
|
368
|
+
self.emit('} while (' + self.genExpr(node.cond) + ');')
|
|
369
|
+
|
|
370
|
+
fn genImport(node):
|
|
371
|
+
val src = String(node.source)
|
|
372
|
+
if node.namespaceName:
|
|
373
|
+
self.emit('const ' + node.namespaceName + ' = require("' + src + '");')
|
|
374
|
+
else if node.defaultName:
|
|
375
|
+
self.emit('const ' + node.defaultName + ' = require("' + src + '");')
|
|
376
|
+
else if node.names.length:
|
|
377
|
+
val parts = node.names.map(n -> (typeof n == 'string' ? n : (n.name != n.alias ? n.name + ': ' + n.alias : n.name))).join(', ')
|
|
378
|
+
self.emit('const { ' + parts + ' } = require("' + src + '");')
|
|
379
|
+
|
|
380
|
+
fn genExport(node):
|
|
381
|
+
if node.isDefault:
|
|
382
|
+
self.emit('module.exports = ' + self.genExpr(node.decl) + ';')
|
|
383
|
+
return
|
|
384
|
+
val decl = node.decl
|
|
385
|
+
if decl.type == 'FnDecl':
|
|
386
|
+
val asyncKw = decl.async ? 'async ' : ''
|
|
387
|
+
val params = decl.params.map(p ->
|
|
388
|
+
p.rest ? '...' + p.name :
|
|
389
|
+
p.defaultVal ? p.name + ' = ' + self.genExpr(p.defaultVal) :
|
|
390
|
+
p.name
|
|
391
|
+
).join(', ')
|
|
392
|
+
if decl.inline:
|
|
393
|
+
self.emit(asyncKw + 'function ' + decl.name + '(' + params + ') { return ' + self.genExpr(decl.body) + '; }')
|
|
394
|
+
else:
|
|
395
|
+
self.emit(asyncKw + 'function ' + decl.name + '(' + params + ') {')
|
|
396
|
+
self.indIn()
|
|
397
|
+
for s in decl.body: self.genStmt(s)
|
|
398
|
+
self.indOut()
|
|
399
|
+
self.emit('}')
|
|
400
|
+
self.emit('module.exports.' + decl.name + ' = ' + decl.name + ';')
|
|
401
|
+
else if decl.type == 'ClassDecl':
|
|
402
|
+
self.genClass(decl)
|
|
403
|
+
self.emit('module.exports.' + decl.name + ' = ' + decl.name + ';')
|
|
404
|
+
else if decl.type == 'TypeDecl':
|
|
405
|
+
self.genTypeDecl(decl)
|
|
406
|
+
for v in decl.variants: self.emit('module.exports.' + v.name + ' = ' + v.name + ';')
|
|
407
|
+
else if decl.type == 'InterfaceDecl':
|
|
408
|
+
self.genInterfaceDecl(decl)
|
|
409
|
+
else if decl.type == 'EnumDecl':
|
|
410
|
+
self.genEnumDecl(decl)
|
|
411
|
+
self.emit('module.exports.' + decl.name + ' = ' + decl.name + ';')
|
|
412
|
+
else if decl.type == 'VarDecl':
|
|
413
|
+
val kw = decl.kind == 'val' ? 'const' : 'let'
|
|
414
|
+
self.emit(kw + ' ' + decl.name + ' = ' + self.genExpr(decl.init) + ';')
|
|
415
|
+
self.emit('module.exports.' + decl.name + ' = ' + decl.name + ';')
|
|
416
|
+
else:
|
|
417
|
+
self.genStmt(decl)
|
|
418
|
+
|
|
419
|
+
fn genExpr(node):
|
|
420
|
+
if not node: return 'undefined'
|
|
421
|
+
if node.type == 'NumberLit': return String(node.value)
|
|
422
|
+
if node.type == 'BoolLit': return String(node.value)
|
|
423
|
+
if node.type == 'NullLit': return 'null'
|
|
424
|
+
if node.type == 'SelfExpr': return 'this'
|
|
425
|
+
if node.type == 'Identifier': return node.name == 'print' ? 'console.log' : node.name
|
|
426
|
+
if node.type == 'StringLit': return JSON.stringify(node.value)
|
|
427
|
+
if node.type == 'RegexLit': return '/' + node.value.pattern + '/' + node.value.flags
|
|
428
|
+
if node.type == 'TemplateLit': return self.genTemplate(node.parts)
|
|
429
|
+
if node.type == 'BinaryExpr':
|
|
430
|
+
return '(' + self.genExpr(node.left) + ' ' + node.op + ' ' + self.genExpr(node.right) + ')'
|
|
431
|
+
if node.type == 'UnaryExpr':
|
|
432
|
+
return node.op + self.genExpr(node.operand)
|
|
433
|
+
if node.type == 'UpdateExpr':
|
|
434
|
+
if node.prefix: return node.op + self.genExpr(node.operand)
|
|
435
|
+
return self.genExpr(node.operand) + node.op
|
|
436
|
+
if node.type == 'TernaryExpr':
|
|
437
|
+
return '(' + self.genExpr(node.cond) + ' ? ' + self.genExpr(node.then) + ' : ' + self.genExpr(node.else_) + ')'
|
|
438
|
+
if node.type == 'AssignExpr':
|
|
439
|
+
return self.genExpr(node.target) + ' ' + node.op + ' ' + self.genExpr(node.value)
|
|
440
|
+
if node.type == 'AwaitExpr':
|
|
441
|
+
return 'await ' + self.genExpr(node.operand)
|
|
442
|
+
if node.type == 'TypeofExpr':
|
|
443
|
+
return 'typeof ' + self.genExpr(node.operand)
|
|
444
|
+
if node.type == 'SpreadExpr':
|
|
445
|
+
return '...' + self.genExpr(node.expr)
|
|
446
|
+
if node.type == 'CallExpr':
|
|
447
|
+
val callee = self.genExpr(node.callee)
|
|
448
|
+
val args = node.args.map(a -> self.genExpr(a)).join(', ')
|
|
449
|
+
return callee + '(' + args + ')'
|
|
450
|
+
if node.type == 'MemberExpr':
|
|
451
|
+
val objSrc = self.genExpr(node.obj)
|
|
452
|
+
val wrapped = node.obj.type == 'NumberLit' ? '(' + objSrc + ')' : objSrc
|
|
453
|
+
return wrapped + '.' + node.prop
|
|
454
|
+
if node.type == 'OptMemberExpr':
|
|
455
|
+
return self.genExpr(node.obj) + '?.' + node.prop
|
|
456
|
+
if node.type == 'OptIndexExpr':
|
|
457
|
+
return self.genExpr(node.obj) + '?.[' + self.genExpr(node.idx) + ']'
|
|
458
|
+
if node.type == 'OptCallExpr':
|
|
459
|
+
val args = node.args.map(a -> self.genExpr(a)).join(', ')
|
|
460
|
+
return self.genExpr(node.callee) + '?.(' + args + ')'
|
|
461
|
+
if node.type == 'IndexExpr':
|
|
462
|
+
return self.genExpr(node.obj) + '[' + self.genExpr(node.idx) + ']'
|
|
463
|
+
if node.type == 'NewExpr':
|
|
464
|
+
val args = node.args.map(a -> self.genExpr(a)).join(', ')
|
|
465
|
+
return 'new ' + node.callee + '(' + args + ')'
|
|
466
|
+
if node.type == 'LambdaExpr':
|
|
467
|
+
val params = node.params.map(p -> p.rest ? '...' + p.name : p.name).join(', ')
|
|
468
|
+
return '(' + params + ') => ' + self.genExpr(node.body)
|
|
469
|
+
if node.type == 'FnDecl':
|
|
470
|
+
val asyncKw = node.async ? 'async ' : ''
|
|
471
|
+
val params = node.params.map(p ->
|
|
472
|
+
p.rest ? '...' + p.name :
|
|
473
|
+
p.defaultVal ? p.name + ' = ' + self.genExpr(p.defaultVal) :
|
|
474
|
+
p.name
|
|
475
|
+
).join(', ')
|
|
476
|
+
if node.inline:
|
|
477
|
+
return asyncKw + 'function(' + params + ') { return ' + self.genExpr(node.body) + '; }'
|
|
478
|
+
val saved = self.lines.length
|
|
479
|
+
val savedLevel = self.level
|
|
480
|
+
self.emit(asyncKw + 'function(' + params + ') {')
|
|
481
|
+
self.indIn()
|
|
482
|
+
for s in node.body: self.genStmt(s)
|
|
483
|
+
self.indOut()
|
|
484
|
+
self.emit('}')
|
|
485
|
+
val block = self.lines.splice(saved).map(l -> l.trimStart()).join(' ')
|
|
486
|
+
self.level = savedLevel
|
|
487
|
+
return block
|
|
488
|
+
if node.type == 'MatchStmt':
|
|
489
|
+
val saved = self.lines.length
|
|
490
|
+
val savedLevel = self.level
|
|
491
|
+
val savedLoop = self._loopDepth
|
|
492
|
+
self._loopDepth = 0
|
|
493
|
+
self.emit('(() => {')
|
|
494
|
+
self.indIn()
|
|
495
|
+
self.genMatch(node)
|
|
496
|
+
self.indOut()
|
|
497
|
+
self.emit('})()')
|
|
498
|
+
self._loopDepth = savedLoop
|
|
499
|
+
val block = self.lines.splice(saved).map(l -> l.trimStart()).join(' ')
|
|
500
|
+
self.level = savedLevel
|
|
501
|
+
return block
|
|
502
|
+
if node.type == 'ArrayExpr':
|
|
503
|
+
return '[' + node.items.map(i -> self.genExpr(i)).join(', ') + ']'
|
|
504
|
+
if node.type == 'ObjectExpr':
|
|
505
|
+
val pairs = node.pairs.map(p -> self.genObjPair(p)).join(', ')
|
|
506
|
+
return '{ ' + pairs + ' }'
|
|
507
|
+
if node.type == 'RangeExpr':
|
|
508
|
+
return 'Array.from({ length: ' + self.genExpr(node.end) + ' - ' + self.genExpr(node.start) + ' }, (_, i) => i + ' + self.genExpr(node.start) + ')'
|
|
509
|
+
if node.type == 'PipeExpr':
|
|
510
|
+
return self.genPipe(node)
|
|
511
|
+
if node.type == 'CastExpr': return self.genExpr(node.expr)
|
|
512
|
+
if node.type == 'AsConstExpr': return 'Object.freeze(' + self.genExpr(node.expr) + ')'
|
|
513
|
+
if node.type == 'SatisfiesExpr': return self.genExpr(node.expr)
|
|
514
|
+
if node.type == 'IsExpr': return self.genExpr(node.expr)
|
|
515
|
+
if node.type == 'NonNullExpr': return self.genExpr(node.expr)
|
|
516
|
+
throw new Error("Unknown expression: {node.type}")
|
|
517
|
+
|
|
518
|
+
fn genTemplate(parts):
|
|
519
|
+
var result = '`'
|
|
520
|
+
for p in parts:
|
|
521
|
+
if p.type == 'text':
|
|
522
|
+
result += p.value.replace(/`/g, '\\`').replace(/\$/g, '\\$')
|
|
523
|
+
else:
|
|
524
|
+
val fmtInfo = extractFormatSpec(p.value)
|
|
525
|
+
val exprSrc = fmtInfo ? fmtInfo.expr : p.value
|
|
526
|
+
val fmt = fmtInfo ? fmtInfo.fmt : null
|
|
527
|
+
try:
|
|
528
|
+
val tokens = lexerize(exprSrc).tokenize()
|
|
529
|
+
val expr = makeParser(tokens).parseExpr()
|
|
530
|
+
val gen = self.genExpr(expr)
|
|
531
|
+
if fmt:
|
|
532
|
+
self._needsFmt = true
|
|
533
|
+
result += '$' + '{_fmt(' + gen + ', ' + JSON.stringify(fmt) + ')}'
|
|
534
|
+
else:
|
|
535
|
+
result += '$' + '{' + gen + '}'
|
|
536
|
+
catch(err):
|
|
537
|
+
result += '$' + '{' + p.value + '}'
|
|
538
|
+
result += '`'
|
|
539
|
+
return result
|
|
540
|
+
|
|
541
|
+
fn genPipe(node):
|
|
542
|
+
val left = self.genExpr(node.left)
|
|
543
|
+
val right = node.right
|
|
544
|
+
if right.type == 'Identifier':
|
|
545
|
+
return self.genExpr(right) + '(' + left + ')'
|
|
546
|
+
if right.type == 'CallExpr':
|
|
547
|
+
val fn_ = self.genExpr(right.callee)
|
|
548
|
+
val rest = right.args.map(a -> self.genExpr(a)).join(', ')
|
|
549
|
+
return rest ? fn_ + '(' + left + ', ' + rest + ')' : fn_ + '(' + left + ')'
|
|
550
|
+
return '(' + self.genExpr(right) + ')(' + left + ')'
|
|
551
|
+
|
|
552
|
+
export fn makeCodeGen(opts):
|
|
553
|
+
val ind = opts?.indent ?? ' '
|
|
554
|
+
val smb = opts?.smBuilder ?? null
|
|
555
|
+
return new CodeGenerator(ind, 0, [], {}, smb, false, 0)
|