gofront 0.0.6 → 0.0.8
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/README.md +104 -33
- package/package.json +12 -5
- package/src/codegen/expressions.js +603 -9
- package/src/codegen/source-map.js +8 -5
- package/src/codegen/statements.js +30 -26
- package/src/codegen.js +119 -8
- package/src/compiler.js +2 -1
- package/src/dev-server.js +1 -0
- package/src/index.js +1 -1
- package/src/parser.js +0 -10
- package/src/resolver.js +29 -0
- package/src/typechecker/expressions.js +38 -9
- package/src/typechecker/stdlib.js +1067 -0
- package/src/typechecker/types.js +13 -33
- package/src/typechecker.js +25 -601
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import { ERROR, isComplex } from "../typechecker/types.js";
|
|
4
4
|
|
|
5
|
-
const globalError = ERROR;
|
|
6
|
-
|
|
7
5
|
const INT_TYPE_NAMES = new Set([
|
|
8
6
|
"int",
|
|
9
7
|
"uint",
|
|
@@ -147,6 +145,15 @@ export const expressionGenMethods = {
|
|
|
147
145
|
return "Number.MIN_SAFE_INTEGER";
|
|
148
146
|
}
|
|
149
147
|
}
|
|
148
|
+
// io constants
|
|
149
|
+
if (expr.expr.kind === "Ident" && expr.expr.name === "io") {
|
|
150
|
+
switch (expr.field) {
|
|
151
|
+
case "EOF":
|
|
152
|
+
return '"EOF"';
|
|
153
|
+
case "Discard":
|
|
154
|
+
return "{ WriteString(s) { return s.length; }, Write(b) { return b.length; } }";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
150
157
|
// os constants/vars
|
|
151
158
|
if (expr.expr.kind === "Ident" && expr.expr.name === "os") {
|
|
152
159
|
switch (expr.field) {
|
|
@@ -154,7 +161,7 @@ export const expressionGenMethods = {
|
|
|
154
161
|
return "process.argv";
|
|
155
162
|
}
|
|
156
163
|
}
|
|
157
|
-
// time constants (nanosecond durations)
|
|
164
|
+
// time constants (nanosecond durations and layout strings)
|
|
158
165
|
if (expr.expr.kind === "Ident" && expr.expr.name === "time") {
|
|
159
166
|
switch (expr.field) {
|
|
160
167
|
case "Millisecond":
|
|
@@ -165,6 +172,68 @@ export const expressionGenMethods = {
|
|
|
165
172
|
return "60000000000";
|
|
166
173
|
case "Hour":
|
|
167
174
|
return "3600000000000";
|
|
175
|
+
case "RFC3339":
|
|
176
|
+
return '"2006-01-02T15:04:05Z07:00"';
|
|
177
|
+
case "RFC3339Nano":
|
|
178
|
+
return '"2006-01-02T15:04:05.999999999Z07:00"';
|
|
179
|
+
case "DateOnly":
|
|
180
|
+
return '"2006-01-02"';
|
|
181
|
+
case "TimeOnly":
|
|
182
|
+
return '"15:04:05"';
|
|
183
|
+
case "DateTime":
|
|
184
|
+
return '"2006-01-02 15:04:05"';
|
|
185
|
+
case "UTC":
|
|
186
|
+
case "Local":
|
|
187
|
+
return "null";
|
|
188
|
+
case "January":
|
|
189
|
+
return "1";
|
|
190
|
+
case "February":
|
|
191
|
+
return "2";
|
|
192
|
+
case "March":
|
|
193
|
+
return "3";
|
|
194
|
+
case "April":
|
|
195
|
+
return "4";
|
|
196
|
+
case "May":
|
|
197
|
+
return "5";
|
|
198
|
+
case "June":
|
|
199
|
+
return "6";
|
|
200
|
+
case "July":
|
|
201
|
+
return "7";
|
|
202
|
+
case "August":
|
|
203
|
+
return "8";
|
|
204
|
+
case "September":
|
|
205
|
+
return "9";
|
|
206
|
+
case "October":
|
|
207
|
+
return "10";
|
|
208
|
+
case "November":
|
|
209
|
+
return "11";
|
|
210
|
+
case "December":
|
|
211
|
+
return "12";
|
|
212
|
+
case "Sunday":
|
|
213
|
+
return "0";
|
|
214
|
+
case "Monday":
|
|
215
|
+
return "1";
|
|
216
|
+
case "Tuesday":
|
|
217
|
+
return "2";
|
|
218
|
+
case "Wednesday":
|
|
219
|
+
return "3";
|
|
220
|
+
case "Thursday":
|
|
221
|
+
return "4";
|
|
222
|
+
case "Friday":
|
|
223
|
+
return "5";
|
|
224
|
+
case "Saturday":
|
|
225
|
+
return "6";
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// utf8 constants
|
|
229
|
+
if (expr.expr.kind === "Ident" && expr.expr.name === "utf8") {
|
|
230
|
+
switch (expr.field) {
|
|
231
|
+
case "RuneError":
|
|
232
|
+
return "0xFFFD";
|
|
233
|
+
case "MaxRune":
|
|
234
|
+
return "0x10FFFF";
|
|
235
|
+
case "UTFMax":
|
|
236
|
+
return "4";
|
|
168
237
|
}
|
|
169
238
|
}
|
|
170
239
|
const base = this.genExpr(expr.expr);
|
|
@@ -184,7 +253,11 @@ export const expressionGenMethods = {
|
|
|
184
253
|
}
|
|
185
254
|
|
|
186
255
|
case "IndexExpr": {
|
|
187
|
-
const
|
|
256
|
+
const exprType = expr.expr._type;
|
|
257
|
+
const wrapField = this._namedWrapperField(exprType, expr.expr);
|
|
258
|
+
const base = wrapField
|
|
259
|
+
? `${this.genExpr(expr.expr)}.${wrapField}`
|
|
260
|
+
: this.genExpr(expr.expr);
|
|
188
261
|
const idx = this.genExpr(expr.index);
|
|
189
262
|
if (expr._mapValueType && !expr._lvalue) {
|
|
190
263
|
const zero = this.zeroValueForType(expr._mapValueType);
|
|
@@ -196,7 +269,6 @@ export const expressionGenMethods = {
|
|
|
196
269
|
return `(${base}[${idx}] ?? ${zero})`;
|
|
197
270
|
}
|
|
198
271
|
// String indexing returns a byte (charCodeAt), not a JS character
|
|
199
|
-
const exprType = expr.expr._type;
|
|
200
272
|
const isStr =
|
|
201
273
|
(exprType?.kind === "basic" && exprType.name === "string") ||
|
|
202
274
|
(exprType?.kind === "untyped" && exprType.base === "string");
|
|
@@ -212,6 +284,7 @@ export const expressionGenMethods = {
|
|
|
212
284
|
const hi = expr.high ? this.genExpr(expr.high) : "";
|
|
213
285
|
if (!lo && !hi) return `${base}.slice()`;
|
|
214
286
|
if (!hi) return `${base}.slice(${lo})`;
|
|
287
|
+
if (!lo) return `${base}.slice(0, ${hi})`;
|
|
215
288
|
return `${base}.slice(${lo}, ${hi})`;
|
|
216
289
|
}
|
|
217
290
|
|
|
@@ -284,6 +357,10 @@ export const expressionGenMethods = {
|
|
|
284
357
|
this._usesError = true;
|
|
285
358
|
return `__error(${inner})`;
|
|
286
359
|
}
|
|
360
|
+
// Named wrapper type: NodeFunc(fn) → new NodeFunc(fn)
|
|
361
|
+
if (target && this.namedWrapperNames.has(target)) {
|
|
362
|
+
return `new ${target}(${inner})`;
|
|
363
|
+
}
|
|
287
364
|
switch (target) {
|
|
288
365
|
case "string": {
|
|
289
366
|
// Go string(65) → "A" (Unicode code point), not "65"
|
|
@@ -339,6 +416,16 @@ export const expressionGenMethods = {
|
|
|
339
416
|
},
|
|
340
417
|
|
|
341
418
|
genCall(expr) {
|
|
419
|
+
// Named type constructor call: Greeter(fn), NodeFunc(fn) → new Greeter(fn)
|
|
420
|
+
if (expr._isTypeConversion) {
|
|
421
|
+
const name = expr._conversionTargetType?.name;
|
|
422
|
+
const arg = this.genExpr(expr.args[0]);
|
|
423
|
+
if (name && this.namedWrapperNames.has(name)) {
|
|
424
|
+
return `new ${name}(${arg})`;
|
|
425
|
+
}
|
|
426
|
+
return arg; // non-wrapper named types: identity
|
|
427
|
+
}
|
|
428
|
+
|
|
342
429
|
// Unwrap InstantiationExpr for function calls: Foo[int](42) → Foo(42)
|
|
343
430
|
const funcExpr =
|
|
344
431
|
expr.func.kind === "InstantiationExpr" ? expr.func.expr : expr.func;
|
|
@@ -351,6 +438,10 @@ export const expressionGenMethods = {
|
|
|
351
438
|
if (expr._constLen != null) return String(expr._constLen);
|
|
352
439
|
const arg = expr.args[0];
|
|
353
440
|
const t = arg?._type;
|
|
441
|
+
const wrapField = this._namedWrapperField(t, arg);
|
|
442
|
+
if (wrapField) {
|
|
443
|
+
return `${this.genExpr(arg)}.${wrapField}.length`;
|
|
444
|
+
}
|
|
354
445
|
const js = this.genExpr(arg);
|
|
355
446
|
if (t?.kind === "map") return `Object.keys(${js}).length`;
|
|
356
447
|
this._usesLen = true;
|
|
@@ -425,7 +516,7 @@ export const expressionGenMethods = {
|
|
|
425
516
|
expr.func.kind === "SelectorExpr" &&
|
|
426
517
|
expr.func.field === "Error" &&
|
|
427
518
|
expr.func.expr._type &&
|
|
428
|
-
(expr.func.expr._type ===
|
|
519
|
+
(expr.func.expr._type === ERROR ||
|
|
429
520
|
expr.func.expr._type?.name === "error" ||
|
|
430
521
|
(expr.func.expr._type?.kind === "named" &&
|
|
431
522
|
expr.func.expr._type?.underlying?.kind === "interface"))
|
|
@@ -454,6 +545,9 @@ export const expressionGenMethods = {
|
|
|
454
545
|
if (recvName === "regexp.Regexp") {
|
|
455
546
|
return this._genRegexpMethodCall(expr.func.field, expr);
|
|
456
547
|
}
|
|
548
|
+
if (recvName === "time.Time") {
|
|
549
|
+
return this._genTimeMethodCall(expr.func.field, expr);
|
|
550
|
+
}
|
|
457
551
|
}
|
|
458
552
|
|
|
459
553
|
// Mark the callee so SelectorExpr knows it's being called, not used as a value
|
|
@@ -472,6 +566,18 @@ export const expressionGenMethods = {
|
|
|
472
566
|
},
|
|
473
567
|
|
|
474
568
|
genAppend(expr) {
|
|
569
|
+
const retType = expr._type;
|
|
570
|
+
const wrapField = this._namedWrapperField(retType, expr.args[0]);
|
|
571
|
+
if (wrapField) {
|
|
572
|
+
// Named slice wrapper: append(g, x) → new G(__append(g._items, x))
|
|
573
|
+
const sliceJS = `${this.genExpr(expr.args[0])}.${wrapField}`;
|
|
574
|
+
const elems = expr.args
|
|
575
|
+
.slice(1)
|
|
576
|
+
.map((a) => (a._spread ? `...${this.genExpr(a)}` : this.genExpr(a)));
|
|
577
|
+
if (elems.length === 0) return this.genExpr(expr.args[0]);
|
|
578
|
+
this._usesAppend = true;
|
|
579
|
+
return `new ${retType.name}(__append(${sliceJS}, ${elems.join(", ")}))`;
|
|
580
|
+
}
|
|
475
581
|
const slice = this.genExpr(expr.args[0]);
|
|
476
582
|
const elems = expr.args
|
|
477
583
|
.slice(1)
|
|
@@ -556,6 +662,34 @@ export const expressionGenMethods = {
|
|
|
556
662
|
return `new ${typeName}({ ${this._genStructFields(expr.elems)} })`;
|
|
557
663
|
}
|
|
558
664
|
|
|
665
|
+
// Named wrapper type: Group{a, b} → new Group([a, b])
|
|
666
|
+
if (typeName && this.namedWrapperNames.has(typeName)) {
|
|
667
|
+
const namedType = this.checker?.types.get(typeName);
|
|
668
|
+
const u = namedType?.underlying;
|
|
669
|
+
if (u?.kind === "map") {
|
|
670
|
+
const entries = expr.elems
|
|
671
|
+
.map((e) => {
|
|
672
|
+
if (e.kind === "KeyValueExpr") {
|
|
673
|
+
const k =
|
|
674
|
+
e.key.litKind === "STRING"
|
|
675
|
+
? JSON.stringify(e.key.value)
|
|
676
|
+
: `[${this.genExpr(e.key)}]`;
|
|
677
|
+
return `${k}: ${this.genExpr(e.value)}`;
|
|
678
|
+
}
|
|
679
|
+
return this.genExpr(e);
|
|
680
|
+
})
|
|
681
|
+
.join(", ");
|
|
682
|
+
return `new ${typeName}({ ${entries} })`;
|
|
683
|
+
}
|
|
684
|
+
// Default: slice
|
|
685
|
+
const elems = expr.elems
|
|
686
|
+
.map((e) =>
|
|
687
|
+
e.kind === "KeyValueExpr" ? this.genExpr(e.value) : this.genExpr(e),
|
|
688
|
+
)
|
|
689
|
+
.join(", ");
|
|
690
|
+
return `new ${typeName}([${elems}])`;
|
|
691
|
+
}
|
|
692
|
+
|
|
559
693
|
// Fallback: named type that's not a struct but has positional elements → treat as struct
|
|
560
694
|
if (expr.elems.some((e) => e._positionalField)) {
|
|
561
695
|
if (typeName) {
|
|
@@ -617,7 +751,8 @@ export const expressionGenMethods = {
|
|
|
617
751
|
if (typeNode.kind === "Ident") return typeNode.name;
|
|
618
752
|
if (typeNode.kind === "InstantiationExpr")
|
|
619
753
|
return this.getTypeName(typeNode.expr);
|
|
620
|
-
if (typeNode.kind === "SelectorExpr")
|
|
754
|
+
if (typeNode.kind === "SelectorExpr")
|
|
755
|
+
return `${this.getTypeName(typeNode.expr)}.${typeNode.field}`;
|
|
621
756
|
return null;
|
|
622
757
|
},
|
|
623
758
|
|
|
@@ -1002,6 +1137,36 @@ export const expressionGenMethods = {
|
|
|
1002
1137
|
return undefined;
|
|
1003
1138
|
},
|
|
1004
1139
|
|
|
1140
|
+
_genIo(fn, _a, expr) {
|
|
1141
|
+
switch (fn) {
|
|
1142
|
+
case "WriteString": {
|
|
1143
|
+
const writerArg = expr.args[0];
|
|
1144
|
+
const writerType = writerArg._type;
|
|
1145
|
+
const typeName =
|
|
1146
|
+
writerType?.name ??
|
|
1147
|
+
(writerType?.kind === "pointer" ? writerType.base?.name : null);
|
|
1148
|
+
const w = this.genExpr(writerArg);
|
|
1149
|
+
const s = this.genExpr(expr.args[1]);
|
|
1150
|
+
const isPtr = writerType?.kind === "pointer";
|
|
1151
|
+
const base = isPtr ? `${w}.value` : w;
|
|
1152
|
+
if (typeName === "strings.Builder") {
|
|
1153
|
+
return `((b,s) => { b._buf += s; return [s.length, null]; })(${base}, ${s})`;
|
|
1154
|
+
}
|
|
1155
|
+
if (typeName === "bytes.Buffer") {
|
|
1156
|
+
return `((b,s) => { b._buf.push(...new TextEncoder().encode(s)); return [s.length, null]; })(${base}, ${s})`;
|
|
1157
|
+
}
|
|
1158
|
+
// Generic: auto-dereference pointer, then dispatch on concrete writer type.
|
|
1159
|
+
// strings.Builder has { _buf: string }, bytes.Buffer has { _buf: [] }.
|
|
1160
|
+
return `((b,s) => { const w = b?.value ?? b; if (typeof w.WriteString === "function") return [w.WriteString(s), null]; if (typeof w._buf === "string") { w._buf += s; return [s.length, null]; } if (Array.isArray(w._buf)) { w._buf.push(...new TextEncoder().encode(s)); return [s.length, null]; } return [0, "io.WriteString: unsupported writer"]; })(${w}, ${s})`;
|
|
1161
|
+
}
|
|
1162
|
+
case "ReadAll": {
|
|
1163
|
+
const r = this.genExpr(expr.args[0]);
|
|
1164
|
+
return `((r) => { const w = r?.value ?? r; if (typeof w._src === "string") { const s = w._src.slice(w._pos); w._pos = w._src.length; return [[...s].map(c => c.charCodeAt(0)), null]; } if (Array.isArray(w._src)) { const b = w._src.slice(w._pos); w._pos = w._src.length; return [b, null]; } const chunks = []; const buf = new Array(4096); let err = null; while (!err) { const [n, e] = w.Read(buf); if (n > 0) chunks.push(...buf.slice(0, n)); err = e; } return [chunks, err === "EOF" ? null : err]; })(${r})`;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return undefined;
|
|
1168
|
+
},
|
|
1169
|
+
|
|
1005
1170
|
_genHtml(fn, a) {
|
|
1006
1171
|
switch (fn) {
|
|
1007
1172
|
case "EscapeString": {
|
|
@@ -1102,11 +1267,168 @@ export const expressionGenMethods = {
|
|
|
1102
1267
|
return this._genMaps(fn, a);
|
|
1103
1268
|
case "html":
|
|
1104
1269
|
return this._genHtml(fn, a);
|
|
1270
|
+
case "io":
|
|
1271
|
+
return this._genIo(fn, a, expr);
|
|
1272
|
+
case "rand":
|
|
1273
|
+
return this._genRand(fn, a);
|
|
1274
|
+
case "utf8":
|
|
1275
|
+
return this._genUtf8(fn, a);
|
|
1276
|
+
case "path":
|
|
1277
|
+
return this._genPath(fn, a, expr);
|
|
1278
|
+
case "gom":
|
|
1279
|
+
return this._genGom(fn, expr);
|
|
1105
1280
|
default:
|
|
1106
1281
|
return undefined;
|
|
1107
1282
|
}
|
|
1108
1283
|
},
|
|
1109
1284
|
|
|
1285
|
+
_genGom(fn, expr) {
|
|
1286
|
+
const a = () =>
|
|
1287
|
+
expr.args.map((e) =>
|
|
1288
|
+
e._spread ? `...${this.genExpr(e)}` : this.genExpr(e),
|
|
1289
|
+
);
|
|
1290
|
+
const elementTags = {
|
|
1291
|
+
Div: "div",
|
|
1292
|
+
Section: "section",
|
|
1293
|
+
Article: "article",
|
|
1294
|
+
Aside: "aside",
|
|
1295
|
+
Header: "header",
|
|
1296
|
+
Footer: "footer",
|
|
1297
|
+
Main: "main",
|
|
1298
|
+
Nav: "nav",
|
|
1299
|
+
Figure: "figure",
|
|
1300
|
+
H1: "h1",
|
|
1301
|
+
H2: "h2",
|
|
1302
|
+
H3: "h3",
|
|
1303
|
+
H4: "h4",
|
|
1304
|
+
H5: "h5",
|
|
1305
|
+
H6: "h6",
|
|
1306
|
+
Span: "span",
|
|
1307
|
+
A: "a",
|
|
1308
|
+
Strong: "strong",
|
|
1309
|
+
Em: "em",
|
|
1310
|
+
Code: "code",
|
|
1311
|
+
Pre: "pre",
|
|
1312
|
+
Small: "small",
|
|
1313
|
+
Mark: "mark",
|
|
1314
|
+
P: "p",
|
|
1315
|
+
Br: "br",
|
|
1316
|
+
Hr: "hr",
|
|
1317
|
+
Ul: "ul",
|
|
1318
|
+
Ol: "ol",
|
|
1319
|
+
Li: "li",
|
|
1320
|
+
Dl: "dl",
|
|
1321
|
+
Dt: "dt",
|
|
1322
|
+
Dd: "dd",
|
|
1323
|
+
Form: "form",
|
|
1324
|
+
Input: "input",
|
|
1325
|
+
Button: "button",
|
|
1326
|
+
Textarea: "textarea",
|
|
1327
|
+
Select: "select",
|
|
1328
|
+
Option: "option",
|
|
1329
|
+
Label: "label",
|
|
1330
|
+
Fieldset: "fieldset",
|
|
1331
|
+
Legend: "legend",
|
|
1332
|
+
Img: "img",
|
|
1333
|
+
Video: "video",
|
|
1334
|
+
Audio: "audio",
|
|
1335
|
+
Canvas: "canvas",
|
|
1336
|
+
Table: "table",
|
|
1337
|
+
Thead: "thead",
|
|
1338
|
+
Tbody: "tbody",
|
|
1339
|
+
Tfoot: "tfoot",
|
|
1340
|
+
Tr: "tr",
|
|
1341
|
+
Th: "th",
|
|
1342
|
+
Td: "td",
|
|
1343
|
+
};
|
|
1344
|
+
if (elementTags[fn]) {
|
|
1345
|
+
const tag = elementTags[fn];
|
|
1346
|
+
const args = a();
|
|
1347
|
+
if (args.length === 0)
|
|
1348
|
+
return `(()=>({Mount(p){const e=document.createElement("${tag}");p.appendChild(e);}}))()`;
|
|
1349
|
+
return (
|
|
1350
|
+
`((...c)=>({Mount(p){const e=document.createElement("${tag}");c.forEach(n=>n?.Mount?.(e));p.appendChild(e);}}))` +
|
|
1351
|
+
`(${args.join(",")})`
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1354
|
+
const attrHelpers = {
|
|
1355
|
+
For: "for",
|
|
1356
|
+
Name: "name",
|
|
1357
|
+
Value: "value",
|
|
1358
|
+
Target: "target",
|
|
1359
|
+
Rel: "rel",
|
|
1360
|
+
Alt: "alt",
|
|
1361
|
+
Title: "title",
|
|
1362
|
+
Lang: "lang",
|
|
1363
|
+
Action: "action",
|
|
1364
|
+
Method: "method",
|
|
1365
|
+
AutoComplete: "autocomplete",
|
|
1366
|
+
Draggable: "draggable",
|
|
1367
|
+
Role: "role",
|
|
1368
|
+
StyleAttr: "style",
|
|
1369
|
+
};
|
|
1370
|
+
if (attrHelpers[fn]) {
|
|
1371
|
+
const [v] = a();
|
|
1372
|
+
return `((v)=>({Mount(e){e.setAttribute("${attrHelpers[fn]}",v)}}))(${v})`;
|
|
1373
|
+
}
|
|
1374
|
+
if (fn === "AriaLabel") {
|
|
1375
|
+
const [v] = a();
|
|
1376
|
+
return `((v)=>({Mount(e){e.setAttribute("aria-label",v)}}))(${v})`;
|
|
1377
|
+
}
|
|
1378
|
+
const boolAttrs = {
|
|
1379
|
+
Disabled: "disabled",
|
|
1380
|
+
Checked: "checked",
|
|
1381
|
+
Selected: "selected",
|
|
1382
|
+
Readonly: "readonly",
|
|
1383
|
+
};
|
|
1384
|
+
if (boolAttrs[fn])
|
|
1385
|
+
return `({Mount(e){e.setAttribute("${boolAttrs[fn]}","")}})`;
|
|
1386
|
+
|
|
1387
|
+
const args = a();
|
|
1388
|
+
switch (fn) {
|
|
1389
|
+
case "El": {
|
|
1390
|
+
const [tag, ...children] = args;
|
|
1391
|
+
if (children.length === 0)
|
|
1392
|
+
return `((t)=>({Mount(p){const e=document.createElement(t);p.appendChild(e);}})) (${tag})`;
|
|
1393
|
+
return (
|
|
1394
|
+
`((t,...c)=>({Mount(p){const e=document.createElement(t);c.forEach(n=>n?.Mount?.(e));p.appendChild(e);}}))` +
|
|
1395
|
+
`(${tag},${children.join(",")})`
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
case "Text": {
|
|
1399
|
+
const [s] = args;
|
|
1400
|
+
return `((s)=>({Mount(p){p.appendChild(document.createTextNode(s))}}))(${s})`;
|
|
1401
|
+
}
|
|
1402
|
+
case "Attr": {
|
|
1403
|
+
const [name, value] = args;
|
|
1404
|
+
return `((n,v)=>({Mount(e){e.setAttribute(n,v)}}))(${name},${value})`;
|
|
1405
|
+
}
|
|
1406
|
+
case "Class":
|
|
1407
|
+
return `((v)=>({Mount(e){e.className=v}}))(${args[0]})`;
|
|
1408
|
+
case "Type":
|
|
1409
|
+
return `((v)=>({Mount(e){e.type=v}}))(${args[0]})`;
|
|
1410
|
+
case "Href":
|
|
1411
|
+
return `((v)=>({Mount(e){e.href=v}}))(${args[0]})`;
|
|
1412
|
+
case "Src":
|
|
1413
|
+
return `((v)=>({Mount(e){e.src=v}}))(${args[0]})`;
|
|
1414
|
+
case "Placeholder":
|
|
1415
|
+
return `((v)=>({Mount(e){e.placeholder=v}}))(${args[0]})`;
|
|
1416
|
+
case "DataAttr":
|
|
1417
|
+
return `((k,v)=>({Mount(e){e.setAttribute("data-"+k,v)}}))(${args[0]},${args[1]})`;
|
|
1418
|
+
case "If":
|
|
1419
|
+
return `((c,n)=>c?n:{Mount(){}})(${args[0]},${args[1]})`;
|
|
1420
|
+
case "Map":
|
|
1421
|
+
return `((s,f)=>{const c=s.map(f);return{_items:c,Mount(p){c.forEach(n=>n.Mount(p))}}})(${args[0]},${args[1]})`;
|
|
1422
|
+
case "Style":
|
|
1423
|
+
return `((s)=>({Mount(p){const e=document.createElement("style");e.textContent=s;p.appendChild(e);}})) (${args[0]})`;
|
|
1424
|
+
case "Mount":
|
|
1425
|
+
return `((sel,n)=>{const e=document.querySelector(sel);e.innerHTML="";n.Mount(e)})(${args[0]},${args[1]})`;
|
|
1426
|
+
case "MountTo":
|
|
1427
|
+
return `((sel,n)=>{const e=document.querySelector(sel);n.Mount(e)})(${args[0]},${args[1]})`;
|
|
1428
|
+
}
|
|
1429
|
+
return undefined;
|
|
1430
|
+
},
|
|
1431
|
+
|
|
1110
1432
|
_genFmt(fn, _a, expr) {
|
|
1111
1433
|
const fmtArgs = expr.args.map((e) => this.genExpr(e)).join(", ");
|
|
1112
1434
|
switch (fn) {
|
|
@@ -1176,6 +1498,31 @@ export const expressionGenMethods = {
|
|
|
1176
1498
|
return `(${buf} += __sprintf("%v\\n", ${restJs}))`;
|
|
1177
1499
|
return `(${buf} += __sprintf("%v", ${restJs}))`;
|
|
1178
1500
|
}
|
|
1501
|
+
case "Sscan": {
|
|
1502
|
+
const strArg = this.genExpr(expr.args[0]);
|
|
1503
|
+
const restArgs = expr.args
|
|
1504
|
+
.slice(1)
|
|
1505
|
+
.map((e) => this.genExpr(e))
|
|
1506
|
+
.join(", ");
|
|
1507
|
+
return `((str, ...ptrs) => { const tokens = str.trim().split(/\\s+/).filter(Boolean); let n = 0; for (let i = 0; i < ptrs.length && i < tokens.length; i++) { const t = tokens[i]; const p = ptrs[i]; if (typeof p.value === "number") p.value = Number(t); else if (typeof p.value === "boolean") p.value = t === "true"; else p.value = t; n++; } return [n, n < ptrs.length ? "unexpected EOF" : null]; })(${strArg}, ${restArgs})`;
|
|
1508
|
+
}
|
|
1509
|
+
case "Sscanln": {
|
|
1510
|
+
const strArg = this.genExpr(expr.args[0]);
|
|
1511
|
+
const restArgs = expr.args
|
|
1512
|
+
.slice(1)
|
|
1513
|
+
.map((e) => this.genExpr(e))
|
|
1514
|
+
.join(", ");
|
|
1515
|
+
return `((str, ...ptrs) => { const line = str.split("\\n")[0]; const tokens = line.trim().split(/\\s+/).filter(Boolean); let n = 0; for (let i = 0; i < ptrs.length && i < tokens.length; i++) { const t = tokens[i]; const p = ptrs[i]; if (typeof p.value === "number") p.value = Number(t); else if (typeof p.value === "boolean") p.value = t === "true"; else p.value = t; n++; } return [n, n < ptrs.length ? "unexpected EOF" : null]; })(${strArg}, ${restArgs})`;
|
|
1516
|
+
}
|
|
1517
|
+
case "Sscanf": {
|
|
1518
|
+
const strArg = this.genExpr(expr.args[0]);
|
|
1519
|
+
const fmtArg = this.genExpr(expr.args[1]);
|
|
1520
|
+
const restArgs = expr.args
|
|
1521
|
+
.slice(2)
|
|
1522
|
+
.map((e) => this.genExpr(e))
|
|
1523
|
+
.join(", ");
|
|
1524
|
+
return `((str, _fmt, ...ptrs) => { const tokens = str.trim().split(/\\s+/).filter(Boolean); let n = 0; for (let i = 0; i < ptrs.length && i < tokens.length; i++) { const t = tokens[i]; const p = ptrs[i]; if (typeof p.value === "number") p.value = Number(t); else if (typeof p.value === "boolean") p.value = t === "true"; else p.value = t; n++; } return [n, n < ptrs.length ? "input does not match format" : null]; })(${strArg}, ${fmtArg}, ${restArgs})`;
|
|
1525
|
+
}
|
|
1179
1526
|
default:
|
|
1180
1527
|
return undefined;
|
|
1181
1528
|
}
|
|
@@ -1224,6 +1571,56 @@ export const expressionGenMethods = {
|
|
|
1224
1571
|
return `${args[0]}.join(${args[1]})`;
|
|
1225
1572
|
case "EqualFold":
|
|
1226
1573
|
return `${args[0]}.toLowerCase() === ${args[1]}.toLowerCase()`;
|
|
1574
|
+
case "Fields":
|
|
1575
|
+
return `(${args[0]}).trim() === '' ? [] : (${args[0]}).trim().split(/\\s+/)`;
|
|
1576
|
+
case "Cut":
|
|
1577
|
+
return `((s, sep) => { const i = s.indexOf(sep); return i < 0 ? [s, "", false] : [s.slice(0, i), s.slice(i + sep.length), true]; })(${args[0]}, ${args[1]})`;
|
|
1578
|
+
case "CutPrefix":
|
|
1579
|
+
return `(${args[0]}).startsWith(${args[1]}) ? [(${args[0]}).slice((${args[1]}).length), true] : [${args[0]}, false]`;
|
|
1580
|
+
case "CutSuffix":
|
|
1581
|
+
return `(${args[0]}).endsWith(${args[1]}) ? [(${args[0]}).slice(0, -(${args[1]}).length), true] : [${args[0]}, false]`;
|
|
1582
|
+
case "SplitN":
|
|
1583
|
+
return `((s, sep, n) => { if (n === 0) return []; if (n < 0) return s.split(sep); const r = []; let cur = s; for (let i = 1; i < n && cur.length; i++) { const j = cur.indexOf(sep); if (j < 0) break; r.push(cur.slice(0, j)); cur = cur.slice(j + sep.length); } r.push(cur); return r; })(${args[0]}, ${args[1]}, ${args[2]})`;
|
|
1584
|
+
case "SplitAfter":
|
|
1585
|
+
return `((s, sep) => { if (sep === "") return [...s]; const r = []; let cur = s; while (cur.length) { const j = cur.indexOf(sep); if (j < 0) { r.push(cur); break; } r.push(cur.slice(0, j + sep.length)); cur = cur.slice(j + sep.length); } return r; })(${args[0]}, ${args[1]})`;
|
|
1586
|
+
case "SplitAfterN":
|
|
1587
|
+
return `((s, sep, n) => { if (n === 0) return []; if (n < 0 || sep === "") return ((s, sep) => { if (sep === "") return [...s]; const r = []; let cur = s; while (cur.length) { const j = cur.indexOf(sep); if (j < 0) { r.push(cur); break; } r.push(cur.slice(0, j + sep.length)); cur = cur.slice(j + sep.length); } return r; })(s, sep); const r = []; let cur = s; for (let i = 1; i < n && cur.length; i++) { const j = cur.indexOf(sep); if (j < 0) break; r.push(cur.slice(0, j + sep.length)); cur = cur.slice(j + sep.length); } r.push(cur); return r; })(${args[0]}, ${args[1]}, ${args[2]})`;
|
|
1588
|
+
case "IndexAny":
|
|
1589
|
+
return `((s, chars) => { let m = -1; for (const c of chars) { const i = s.indexOf(c); if (i >= 0 && (m < 0 || i < m)) m = i; } return m; })(${args[0]}, ${args[1]})`;
|
|
1590
|
+
case "LastIndexAny":
|
|
1591
|
+
return `((s, chars) => { let m = -1; for (const c of chars) { const i = s.lastIndexOf(c); if (i > m) m = i; } return m; })(${args[0]}, ${args[1]})`;
|
|
1592
|
+
case "ContainsAny":
|
|
1593
|
+
return `[...(${args[1]})].some(c => (${args[0]}).includes(c))`;
|
|
1594
|
+
case "ContainsRune":
|
|
1595
|
+
return `(${args[0]}).includes(String.fromCodePoint(${args[1]}))`;
|
|
1596
|
+
case "IndexRune":
|
|
1597
|
+
return `(${args[0]}).indexOf(String.fromCodePoint(${args[1]}))`;
|
|
1598
|
+
case "IndexByte":
|
|
1599
|
+
return `(${args[0]}).indexOf(String.fromCharCode(${args[1]}))`;
|
|
1600
|
+
case "LastIndexByte":
|
|
1601
|
+
return `(${args[0]}).lastIndexOf(String.fromCharCode(${args[1]}))`;
|
|
1602
|
+
case "Map":
|
|
1603
|
+
return `[...(${args[1]})].map(c => String.fromCodePoint((${args[0]})(c.codePointAt(0)))).join("")`;
|
|
1604
|
+
case "Title":
|
|
1605
|
+
return `(${args[0]}).replace(/\\b\\w/g, c => c.toUpperCase())`;
|
|
1606
|
+
case "ToTitle":
|
|
1607
|
+
return `(${args[0]}).toUpperCase()`;
|
|
1608
|
+
case "TrimFunc":
|
|
1609
|
+
return `((s, f) => { let l = 0, r = s.length; while (l < r && f(s.codePointAt(l))) l++; while (r > l && f(s.codePointAt(r - 1))) r--; return s.slice(l, r); })(${args[0]}, ${args[1]})`;
|
|
1610
|
+
case "TrimLeftFunc":
|
|
1611
|
+
return `((s, f) => { let l = 0; while (l < s.length && f(s.codePointAt(l))) l++; return s.slice(l); })(${args[0]}, ${args[1]})`;
|
|
1612
|
+
case "TrimRightFunc":
|
|
1613
|
+
return `((s, f) => { let r = s.length; while (r > 0 && f(s.codePointAt(r - 1))) r--; return s.slice(0, r); })(${args[0]}, ${args[1]})`;
|
|
1614
|
+
case "IndexFunc":
|
|
1615
|
+
return `((s, f) => { for (let i = 0; i < s.length; i++) { const cp = s.codePointAt(i); if (f(cp)) return i; if (cp > 0xFFFF) i++; } return -1; })(${args[0]}, ${args[1]})`;
|
|
1616
|
+
case "LastIndexFunc":
|
|
1617
|
+
return `((s, f) => { for (let i = s.length - 1; i >= 0; i--) { const cp = s.codePointAt(i); if (f(cp)) return i; } return -1; })(${args[0]}, ${args[1]})`;
|
|
1618
|
+
case "NewReader":
|
|
1619
|
+
return `{_src: ${args[0]}, _pos: 0, Read(p) { const n = Math.min(p.length, this._src.length - this._pos); for (let i = 0; i < n; i++) p[i] = this._src.charCodeAt(this._pos + i); this._pos += n; return [n, n === 0 ? "EOF" : null]; }, Len() { return this._src.length - this._pos; }, Reset(s) { this._src = s; this._pos = 0; }}`;
|
|
1620
|
+
case "NewReplacer": {
|
|
1621
|
+
const allArgs = args.join(", ");
|
|
1622
|
+
return `((...pairs) => { const p = []; for (let i = 0; i < pairs.length; i += 2) p.push([pairs[i], pairs[i+1]]); return { _p: p, Replace(s) { let r = s; for (const [o, n] of this._p) r = r.split(o).join(n); return r; } }; })(${allArgs})`;
|
|
1623
|
+
}
|
|
1227
1624
|
default:
|
|
1228
1625
|
return undefined;
|
|
1229
1626
|
}
|
|
@@ -1262,6 +1659,38 @@ export const expressionGenMethods = {
|
|
|
1262
1659
|
return `${__bs}(${args[0]}).split(${__bs}(${args[1]})).map(p => ${__sb}(p))`;
|
|
1263
1660
|
case "Join":
|
|
1264
1661
|
return `${__sb}(${args[0]}.map(p => ${__bs}(p)).join(${__bs}(${args[1]})))`;
|
|
1662
|
+
case "ReplaceAll":
|
|
1663
|
+
return `((b, o, n) => { const r = []; let i = 0; while (i <= b.length - o.length) { if (o.every((v, j) => b[i + j] === v)) { r.push(...n); i += o.length; } else r.push(b[i++]); } return r.concat(b.slice(i)); })(${args[0]}, ${args[1]}, ${args[2]})`;
|
|
1664
|
+
case "TrimPrefix":
|
|
1665
|
+
return `((b, p) => p.every((v, i) => b[i] === v) ? b.slice(p.length) : b.slice())(${args[0]}, ${args[1]})`;
|
|
1666
|
+
case "TrimSuffix":
|
|
1667
|
+
return `((b, s) => s.length && s.every((v, i) => b[b.length - s.length + i] === v) ? b.slice(0, -s.length) : b.slice())(${args[0]}, ${args[1]})`;
|
|
1668
|
+
case "TrimLeft":
|
|
1669
|
+
return `((b, c) => { let i = 0; while (i < b.length && c.includes(String.fromCharCode(b[i]))) i++; return b.slice(i); })(${args[0]}, ${args[1]})`;
|
|
1670
|
+
case "TrimRight":
|
|
1671
|
+
return `((b, c) => { let i = b.length; while (i > 0 && c.includes(String.fromCharCode(b[i - 1]))) i--; return b.slice(0, i); })(${args[0]}, ${args[1]})`;
|
|
1672
|
+
case "TrimFunc":
|
|
1673
|
+
return `((b, f) => { let l = 0, r = b.length; while (l < r && f(b[l])) l++; while (r > l && f(b[r - 1])) r--; return b.slice(l, r); })(${args[0]}, ${args[1]})`;
|
|
1674
|
+
case "IndexByte":
|
|
1675
|
+
return `(${args[0]}).indexOf(${args[1]})`;
|
|
1676
|
+
case "LastIndex":
|
|
1677
|
+
return `((b, s) => { for (let i = b.length - s.length; i >= 0; i--) if (s.every((v, j) => b[i + j] === v)) return i; return -1; })(${args[0]}, ${args[1]})`;
|
|
1678
|
+
case "LastIndexByte":
|
|
1679
|
+
return `(${args[0]}).lastIndexOf(${args[1]})`;
|
|
1680
|
+
case "Fields":
|
|
1681
|
+
return `((b) => { const s = String.fromCharCode(...b).trim(); return s === '' ? [] : s.split(/\\s+/).map(w => [...w].map(c => c.charCodeAt(0))); })(${args[0]})`;
|
|
1682
|
+
case "Cut":
|
|
1683
|
+
return `((b, sep) => { for (let i = 0; i <= b.length - sep.length; i++) if (sep.every((v, j) => b[i + j] === v)) return [b.slice(0, i), b.slice(i + sep.length), true]; return [b.slice(), [], false]; })(${args[0]}, ${args[1]})`;
|
|
1684
|
+
case "ContainsAny":
|
|
1685
|
+
return `[...(${args[1]})].some(c => (${args[0]}).includes(c.charCodeAt(0)))`;
|
|
1686
|
+
case "ContainsRune":
|
|
1687
|
+
return `(${args[0]}).includes(${args[1]})`;
|
|
1688
|
+
case "Map":
|
|
1689
|
+
return `(${args[1]}).map(v => (${args[0]})(v))`;
|
|
1690
|
+
case "SplitN":
|
|
1691
|
+
return `((b, sep, n) => { if (n === 0) return []; if (n < 0) return ((b, sep) => { const r = []; let i = 0; while (i <= b.length) { const j = b.findIndex((_, k) => k >= i && sep.every((v, l) => b[k + l] === sep[l])); if (j < 0 || j >= b.length) break; r.push(b.slice(i, j)); i = j + sep.length; } r.push(b.slice(i)); return r; })(b, sep); const r = []; let i = 0; for (let c = 1; c < n; c++) { const j = b.findIndex((_, k) => k >= i && sep.every((v, l) => b[k + l] === sep[l])); if (j < 0) break; r.push(b.slice(i, j)); i = j + sep.length; } r.push(b.slice(i)); return r; })(${args[0]}, ${args[1]}, ${args[2]})`;
|
|
1692
|
+
case "NewReader":
|
|
1693
|
+
return `{_src: ${args[0]}, _pos: 0, Read(p) { const n = Math.min(p.length, this._src.length - this._pos); for (let i = 0; i < n; i++) p[i] = this._src[this._pos + i]; this._pos += n; return [n, n === 0 ? "EOF" : null]; }, Len() { return this._src.length - this._pos; }, Reset(b) { this._src = b; this._pos = 0; }}`;
|
|
1265
1694
|
default:
|
|
1266
1695
|
return undefined;
|
|
1267
1696
|
}
|
|
@@ -1286,6 +1715,14 @@ export const expressionGenMethods = {
|
|
|
1286
1715
|
return `(Number.isNaN(parseInt(${args[0]}, ${args[1]} || 10)) ? [0, "invalid syntax"] : [parseInt(${args[0]}, ${args[1]} || 10), null])`;
|
|
1287
1716
|
case "ParseBool":
|
|
1288
1717
|
return `(${args[0]} === "true" || ${args[0]} === "1" ? [true, null] : ${args[0]} === "false" || ${args[0]} === "0" ? [false, null] : [false, "invalid syntax"])`;
|
|
1718
|
+
case "Quote":
|
|
1719
|
+
return `JSON.stringify(${args[0]})`;
|
|
1720
|
+
case "Unquote":
|
|
1721
|
+
return `((s) => { try { const v = JSON.parse(s); return [v, null]; } catch(e) { return ["", "invalid syntax"]; } })(${args[0]})`;
|
|
1722
|
+
case "AppendInt":
|
|
1723
|
+
return `[...(${args[0]}), ...new TextEncoder().encode((${args[1]}).toString(${args[2]}))]`;
|
|
1724
|
+
case "AppendFloat":
|
|
1725
|
+
return `[...(${args[0]}), ...new TextEncoder().encode(${args[1]}.toFixed(${args[3]} < 0 ? 6 : ${args[3]}))]`;
|
|
1289
1726
|
default:
|
|
1290
1727
|
return undefined;
|
|
1291
1728
|
}
|
|
@@ -1304,6 +1741,12 @@ export const expressionGenMethods = {
|
|
|
1304
1741
|
return `${args[0]}.sort((a, b) => ${args[1]}(a, b) ? -1 : ${args[1]}(b, a) ? 1 : 0)`;
|
|
1305
1742
|
case "SliceIsSorted":
|
|
1306
1743
|
return `${args[0]}.every((v, i, a) => i === 0 || ${args[1]}(a[i - 1], v))`;
|
|
1744
|
+
case "Search":
|
|
1745
|
+
return `((n, f) => { let lo = 0, hi = n; while (lo < hi) { const mid = (lo + hi) >>> 1; if (f(mid)) hi = mid; else lo = mid + 1; } return lo; })(${args[0]}, ${args[1]})`;
|
|
1746
|
+
case "IntsAreSorted":
|
|
1747
|
+
case "Float64sAreSorted":
|
|
1748
|
+
case "StringsAreSorted":
|
|
1749
|
+
return `(${args[0]}).every((v, i, a) => i === 0 || a[i - 1] <= v)`;
|
|
1307
1750
|
default:
|
|
1308
1751
|
return undefined;
|
|
1309
1752
|
}
|
|
@@ -1352,6 +1795,30 @@ export const expressionGenMethods = {
|
|
|
1352
1795
|
return `(${args[1]} > 0 ? ${args[0]} === Infinity : ${args[1]} < 0 ? ${args[0]} === -Infinity : !Number.isFinite(${args[0]}))`;
|
|
1353
1796
|
case "NaN":
|
|
1354
1797
|
return "NaN";
|
|
1798
|
+
case "Atan":
|
|
1799
|
+
return `Math.atan(${args[0]})`;
|
|
1800
|
+
case "Atan2":
|
|
1801
|
+
return `Math.atan2(${args[0]}, ${args[1]})`;
|
|
1802
|
+
case "Asin":
|
|
1803
|
+
return `Math.asin(${args[0]})`;
|
|
1804
|
+
case "Acos":
|
|
1805
|
+
return `Math.acos(${args[0]})`;
|
|
1806
|
+
case "Exp":
|
|
1807
|
+
return `Math.exp(${args[0]})`;
|
|
1808
|
+
case "Exp2":
|
|
1809
|
+
return `Math.pow(2, ${args[0]})`;
|
|
1810
|
+
case "Trunc":
|
|
1811
|
+
return `Math.trunc(${args[0]})`;
|
|
1812
|
+
case "Hypot":
|
|
1813
|
+
return `Math.hypot(${args[0]}, ${args[1]})`;
|
|
1814
|
+
case "Signbit":
|
|
1815
|
+
return `(${args[0]} < 0 || Object.is(${args[0]}, -0))`;
|
|
1816
|
+
case "Copysign":
|
|
1817
|
+
return `(Math.abs(${args[0]}) * (${args[1]} < 0 || Object.is(${args[1]}, -0) ? -1 : 1))`;
|
|
1818
|
+
case "Dim":
|
|
1819
|
+
return `Math.max(${args[0]} - ${args[1]}, 0)`;
|
|
1820
|
+
case "Remainder":
|
|
1821
|
+
return `(${args[0]} - Math.round(${args[0]} / ${args[1]}) * ${args[1]})`;
|
|
1355
1822
|
default:
|
|
1356
1823
|
return undefined;
|
|
1357
1824
|
}
|
|
@@ -1416,15 +1883,142 @@ export const expressionGenMethods = {
|
|
|
1416
1883
|
}
|
|
1417
1884
|
},
|
|
1418
1885
|
|
|
1886
|
+
_genTimeMethodCall(method, expr) {
|
|
1887
|
+
const recv = expr.func.expr;
|
|
1888
|
+
const recvJs = this.genExpr(recv);
|
|
1889
|
+
const args = expr.args.map((a) => this.genExpr(a));
|
|
1890
|
+
switch (method) {
|
|
1891
|
+
case "Format":
|
|
1892
|
+
this._usesTimeFmt = true;
|
|
1893
|
+
return `__timeFmt(${recvJs}._d, ${args[0]})`;
|
|
1894
|
+
case "String":
|
|
1895
|
+
this._usesTimeFmt = true;
|
|
1896
|
+
return `__timeFmt(${recvJs}._d, "2006-01-02T15:04:05Z07:00")`;
|
|
1897
|
+
case "Year":
|
|
1898
|
+
return `${recvJs}._d.getFullYear()`;
|
|
1899
|
+
case "Month":
|
|
1900
|
+
return `${recvJs}._d.getMonth() + 1`;
|
|
1901
|
+
case "Day":
|
|
1902
|
+
return `${recvJs}._d.getDate()`;
|
|
1903
|
+
case "Hour":
|
|
1904
|
+
return `${recvJs}._d.getHours()`;
|
|
1905
|
+
case "Minute":
|
|
1906
|
+
return `${recvJs}._d.getMinutes()`;
|
|
1907
|
+
case "Second":
|
|
1908
|
+
return `${recvJs}._d.getSeconds()`;
|
|
1909
|
+
case "Weekday":
|
|
1910
|
+
return `${recvJs}._d.getDay()`;
|
|
1911
|
+
case "Unix":
|
|
1912
|
+
return `Math.floor(${recvJs}._d.getTime() / 1000)`;
|
|
1913
|
+
case "UnixMilli":
|
|
1914
|
+
return `${recvJs}._d.getTime()`;
|
|
1915
|
+
case "Add":
|
|
1916
|
+
return `{_d: new Date(${recvJs}._d.getTime() + (${args[0]}))}`;
|
|
1917
|
+
case "Sub":
|
|
1918
|
+
return `${recvJs}._d.getTime() - (${args[0]})._d.getTime()`;
|
|
1919
|
+
case "Before":
|
|
1920
|
+
return `${recvJs}._d < (${args[0]})._d`;
|
|
1921
|
+
case "After":
|
|
1922
|
+
return `${recvJs}._d > (${args[0]})._d`;
|
|
1923
|
+
case "Equal":
|
|
1924
|
+
return `${recvJs}._d.getTime() === (${args[0]})._d.getTime()`;
|
|
1925
|
+
default:
|
|
1926
|
+
return undefined;
|
|
1927
|
+
}
|
|
1928
|
+
},
|
|
1929
|
+
|
|
1419
1930
|
_genTime(fn, a) {
|
|
1420
1931
|
const args = a();
|
|
1421
1932
|
switch (fn) {
|
|
1422
1933
|
case "Now":
|
|
1423
|
-
return "Date
|
|
1934
|
+
return "{_d: new Date()}";
|
|
1424
1935
|
case "Since":
|
|
1425
|
-
return `(Date.now() - ${args[0]})`;
|
|
1936
|
+
return `(Date.now() - (${args[0]})._d.getTime())`;
|
|
1426
1937
|
case "Sleep":
|
|
1427
1938
|
return `await new Promise(r => setTimeout(r, ${args[0]} / 1000000))`;
|
|
1939
|
+
case "Parse":
|
|
1940
|
+
this._usesTimeParse = true;
|
|
1941
|
+
return `__timeParse(${args[0]}, ${args[1]})`;
|
|
1942
|
+
case "Unix":
|
|
1943
|
+
return `{_d: new Date((${args[0]}) * 1000)}`;
|
|
1944
|
+
case "Date":
|
|
1945
|
+
return `{_d: new Date(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]})}`;
|
|
1946
|
+
default:
|
|
1947
|
+
return undefined;
|
|
1948
|
+
}
|
|
1949
|
+
},
|
|
1950
|
+
|
|
1951
|
+
_genRand(fn, a) {
|
|
1952
|
+
const args = a();
|
|
1953
|
+
switch (fn) {
|
|
1954
|
+
case "Intn":
|
|
1955
|
+
case "Int63n":
|
|
1956
|
+
case "Int31n":
|
|
1957
|
+
return `Math.floor(Math.random() * ${args[0]})`;
|
|
1958
|
+
case "Float64":
|
|
1959
|
+
case "Float32":
|
|
1960
|
+
return "Math.random()";
|
|
1961
|
+
case "Int":
|
|
1962
|
+
case "Int31":
|
|
1963
|
+
return "Math.floor(Math.random() * 2147483647)";
|
|
1964
|
+
case "Int63":
|
|
1965
|
+
return "Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)";
|
|
1966
|
+
case "Seed":
|
|
1967
|
+
return "(void 0)";
|
|
1968
|
+
case "Shuffle":
|
|
1969
|
+
return `((n, f) => { for (let i = n - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); f(i, j); } })(${args[0]}, ${args[1]})`;
|
|
1970
|
+
case "Perm":
|
|
1971
|
+
return `((n) => { const a = Array.from({length: n}, (_, i) => i); for (let i = n - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [a[i], a[j]] = [a[j], a[i]]; } return a; })(${args[0]})`;
|
|
1972
|
+
default:
|
|
1973
|
+
return undefined;
|
|
1974
|
+
}
|
|
1975
|
+
},
|
|
1976
|
+
|
|
1977
|
+
_genUtf8(fn, a) {
|
|
1978
|
+
const args = a();
|
|
1979
|
+
switch (fn) {
|
|
1980
|
+
case "RuneCountInString":
|
|
1981
|
+
return `[...(${args[0]})].length`;
|
|
1982
|
+
case "RuneLen":
|
|
1983
|
+
return `((r) => r < 0 ? -1 : r <= 0x7F ? 1 : r <= 0x7FF ? 2 : r <= 0xFFFF ? (r >= 0xD800 && r <= 0xDFFF ? -1 : 3) : r <= 0x10FFFF ? 4 : -1)(${args[0]})`;
|
|
1984
|
+
case "ValidString":
|
|
1985
|
+
return `/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/.test(${args[0]}) === false`;
|
|
1986
|
+
case "ValidRune":
|
|
1987
|
+
return `(${args[0]}) >= 0 && (${args[0]}) <= 0x10FFFF && !((${args[0]}) >= 0xD800 && (${args[0]}) <= 0xDFFF)`;
|
|
1988
|
+
case "DecodeRuneInString":
|
|
1989
|
+
return `((s) => { if (!s) return [0xFFFD, 0]; const cp = s.codePointAt(0); return [cp, cp > 0xFFFF ? 2 : 1]; })(${args[0]})`;
|
|
1990
|
+
case "DecodeLastRuneInString":
|
|
1991
|
+
return `((s) => { if (!s) return [0xFFFD, 0]; const i = s.length > 1 && s.charCodeAt(s.length - 1) >= 0xDC00 && s.charCodeAt(s.length - 1) <= 0xDFFF ? s.length - 2 : s.length - 1; const cp = s.codePointAt(i); return [cp, cp > 0xFFFF ? 2 : 1]; })(${args[0]})`;
|
|
1992
|
+
case "FullRuneInString":
|
|
1993
|
+
return `(${args[0]}).length > 0`;
|
|
1994
|
+
default:
|
|
1995
|
+
return undefined;
|
|
1996
|
+
}
|
|
1997
|
+
},
|
|
1998
|
+
|
|
1999
|
+
_genPath(fn, a, expr) {
|
|
2000
|
+
const args = a();
|
|
2001
|
+
switch (fn) {
|
|
2002
|
+
case "Base":
|
|
2003
|
+
return `((p) => { if (!p) return "."; const stripped = p.replace(/\\/+$/, ""); if (!stripped) return "/"; const i = stripped.lastIndexOf("/"); return i < 0 ? stripped : stripped.slice(i + 1) || "/"; })(${args[0]})`;
|
|
2004
|
+
case "Dir":
|
|
2005
|
+
return `((p) => { const i = p.lastIndexOf("/"); if (i < 0) return "."; if (i === 0) return "/"; return p.slice(0, i); })(${args[0]})`;
|
|
2006
|
+
case "Ext":
|
|
2007
|
+
return `((p) => { const b = p.slice(p.lastIndexOf("/") + 1); const i = b.lastIndexOf("."); return i <= 0 ? "" : b.slice(i); })(${args[0]})`;
|
|
2008
|
+
case "Join": {
|
|
2009
|
+
this._usesPathClean = true;
|
|
2010
|
+
const allArgs = expr.args.map((e) => this.genExpr(e)).join(", ");
|
|
2011
|
+
return `__pathClean([${allArgs}].filter(x => x !== "").join("/"))`;
|
|
2012
|
+
}
|
|
2013
|
+
case "Clean":
|
|
2014
|
+
this._usesPathClean = true;
|
|
2015
|
+
return `__pathClean(${args[0]})`;
|
|
2016
|
+
case "IsAbs":
|
|
2017
|
+
return `(${args[0]}).startsWith("/")`;
|
|
2018
|
+
case "Split":
|
|
2019
|
+
return `((p) => { const i = p.lastIndexOf("/"); return i < 0 ? ["", p] : [p.slice(0, i + 1), p.slice(i + 1)]; })(${args[0]})`;
|
|
2020
|
+
case "Match":
|
|
2021
|
+
return `((pat, name) => { try { const sp=/[.+^$()|[\\]\\\\]/g; const re = new RegExp("^" + pat.replace(sp, "\\\\$&").replace(/\\*/g, "[^/]*").replace(/\\?/g, "[^/]") + "$"); return [re.test(name), null]; } catch(e) { return [false, "syntax error in pattern"]; } })(${args[0]}, ${args[1]})`;
|
|
1428
2022
|
default:
|
|
1429
2023
|
return undefined;
|
|
1430
2024
|
}
|