@ball-lang/compiler 0.1.0 → 1.3.5
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 +74 -0
- package/bin/ball-ts-compile.mjs +15 -0
- package/dist/compiler.d.ts +147 -1
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +4379 -200
- package/dist/compiler.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/preamble.d.ts.map +1 -1
- package/dist/preamble.js +893 -28
- package/dist/preamble.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/compiler.ts +4766 -302
- package/src/index.ts +2 -2
- package/src/preamble.ts +893 -28
- package/src/types.ts +7 -0
package/dist/preamble.js
CHANGED
|
@@ -14,10 +14,178 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export const TS_RUNTIME_PREAMBLE = String.raw `// ── Ball runtime preamble (generated by @ball-lang/compiler) ────────
|
|
16
16
|
|
|
17
|
+
// Base class for all Ball runtime values.
|
|
18
|
+
class BallValue {}
|
|
19
|
+
|
|
20
|
+
// A cast pattern (value as T) ASSERTS the runtime type — it throws on a type
|
|
21
|
+
// mismatch (Dart semantics), it does NOT refute / fall through. Conjoined into a
|
|
22
|
+
// switch-case condition by the compiler; returns true when the type check passed,
|
|
23
|
+
// else throws a catchable error. (conformance 302_cast_patterns)
|
|
24
|
+
function ball_cast_assert(ok: boolean, t: string): boolean {
|
|
25
|
+
if (!ok) throw new Error('TypeError: type cast failed: not a ' + t);
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ── Ball container runtime types ────────────────────────────────────
|
|
30
|
+
//
|
|
31
|
+
// The self-hosted engine IR models class instances as 'BallObject extends
|
|
32
|
+
// BallMap'. The compiler treats maps/lists transparently (a Ball map is a
|
|
33
|
+
// plain JS object, a Ball list a plain JS array) and _asMap() returns an
|
|
34
|
+
// instance verbatim, reading its data through bracket access (obj of f)
|
|
35
|
+
// and the Object.prototype .entries / .keys / .length getters. To stay
|
|
36
|
+
// compatible we make BallObject a plain-object-like instance: the field data
|
|
37
|
+
// lives as OWN ENUMERABLE properties (so bracket access and .entries see it),
|
|
38
|
+
// while the class bookkeeping (typeName/fields/methods/superObject) is stored
|
|
39
|
+
// non-enumerably so it never leaks into .entries / .keys / .length.
|
|
40
|
+
//
|
|
41
|
+
// BallMap / BallList exist only so 'extends BallMap' resolves and any stray
|
|
42
|
+
// new BallMap(...) / new BallList(...) behaves like the transparent value.
|
|
43
|
+
class BallMap extends BallValue {
|
|
44
|
+
constructor(entries?: any) {
|
|
45
|
+
super();
|
|
46
|
+
if (entries && typeof entries === 'object') {
|
|
47
|
+
if (entries instanceof Map) {
|
|
48
|
+
for (const [k, v] of entries) (this as any)[k] = v;
|
|
49
|
+
} else {
|
|
50
|
+
for (const k of Object.keys(entries)) (this as any)[k] = entries[k];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class BallList extends Array {
|
|
57
|
+
constructor(items?: any) {
|
|
58
|
+
super();
|
|
59
|
+
if (Array.isArray(items)) for (const it of items) this.push(it);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
class BallObject extends BallMap {
|
|
64
|
+
constructor(arg0?: any, superObject?: any, fields?: any, methods?: any) {
|
|
65
|
+
super();
|
|
66
|
+
// Accept either the named-args object the encoder emits
|
|
67
|
+
// (new BallObject({typeName, superObject, fields, methods})) or the
|
|
68
|
+
// positional form, so the class works regardless of how it is invoked.
|
|
69
|
+
let typeName: any = arg0;
|
|
70
|
+
if (arg0 && typeof arg0 === 'object' && !Array.isArray(arg0) &&
|
|
71
|
+
('typeName' in arg0 || 'fields' in arg0 || 'methods' in arg0 ||
|
|
72
|
+
'superObject' in arg0)) {
|
|
73
|
+
typeName = arg0.typeName;
|
|
74
|
+
superObject = arg0.superObject;
|
|
75
|
+
fields = arg0.fields;
|
|
76
|
+
methods = arg0.methods;
|
|
77
|
+
}
|
|
78
|
+
const fieldMap = (fields && typeof fields === 'object') ? fields : {};
|
|
79
|
+
const methodMap = (methods && typeof methods === 'object') ? methods : {};
|
|
80
|
+
// Field data → own enumerable properties (visible to bracket access and
|
|
81
|
+
// the Object.prototype map getters).
|
|
82
|
+
for (const k of Object.keys(fieldMap)) (this as any)[k] = fieldMap[k];
|
|
83
|
+
// Class bookkeeping → own props the engine reads/writes by bracket name.
|
|
84
|
+
(this as any)['__type__'] = typeName ?? '';
|
|
85
|
+
(this as any)['__super__'] = superObject ?? null;
|
|
86
|
+
(this as any)['__fields__'] = fieldMap;
|
|
87
|
+
(this as any)['__methods__'] = methodMap;
|
|
88
|
+
// Mirror the Dart class fields too, but non-enumerably so they never show
|
|
89
|
+
// up as Ball fields in .entries / .keys / .length.
|
|
90
|
+
for (const [name, value] of [
|
|
91
|
+
['typeName', typeName ?? ''], ['superObject', superObject ?? null],
|
|
92
|
+
['fields', fieldMap], ['methods', methodMap],
|
|
93
|
+
] as Array<[string, any]>) {
|
|
94
|
+
Object.defineProperty(this, name, {
|
|
95
|
+
value, writable: true, configurable: true, enumerable: false,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
setField(name: any, value: any): void {
|
|
101
|
+
(this as any).fields[name] = value;
|
|
102
|
+
(this as any)[name] = value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
(globalThis as any).BallMap = BallMap;
|
|
106
|
+
(globalThis as any).BallList = BallList;
|
|
107
|
+
(globalThis as any).BallObject = BallObject;
|
|
108
|
+
|
|
109
|
+
// BallDouble wrapper — tracks that a number should print as a double
|
|
110
|
+
// (e.g. 42.0 not 42). Used by the compiled Dart engine's _toDouble.
|
|
111
|
+
class BallDouble {
|
|
112
|
+
readonly value: number;
|
|
113
|
+
constructor(v: number) { this.value = v; }
|
|
114
|
+
valueOf(): number { return this.value; }
|
|
115
|
+
get isNaN(): boolean { return Number.isNaN(this.value); }
|
|
116
|
+
get isFinite(): boolean { return Number.isFinite(this.value); }
|
|
117
|
+
get isInfinite(): boolean { return !Number.isFinite(this.value) && !Number.isNaN(this.value); }
|
|
118
|
+
get isNegative(): boolean { return this.value < 0 || (this.value === 0 && 1/this.value === -Infinity); }
|
|
119
|
+
toString(): string {
|
|
120
|
+
const v = this.value;
|
|
121
|
+
if (!isFinite(v)) return v.toString();
|
|
122
|
+
if (v === 0 && 1/v === -Infinity) return '-0.0';
|
|
123
|
+
if (Number.isInteger(v)) return v.toFixed(1);
|
|
124
|
+
return v.toString();
|
|
125
|
+
}
|
|
126
|
+
// Arithmetic: unwrap for operations
|
|
127
|
+
[Symbol.toPrimitive](hint: string): any {
|
|
128
|
+
if (hint === 'string') return this.toString();
|
|
129
|
+
return this.value;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
(globalThis as any).BallDouble = BallDouble;
|
|
133
|
+
|
|
134
|
+
// Arithmetic helpers that propagate BallDouble through operations.
|
|
135
|
+
// If either operand is BallDouble, the result is BallDouble (preserving .0).
|
|
136
|
+
function __ball_mul(a: any, b: any): any {
|
|
137
|
+
if (a != null && typeof a === 'object' && typeof a.__op_mul === 'function') return a.__op_mul(b);
|
|
138
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) * __to_bigint(b));
|
|
139
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
140
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
141
|
+
const r = av * bv;
|
|
142
|
+
return (a instanceof BallDouble || b instanceof BallDouble) ? new BallDouble(r) : r;
|
|
143
|
+
}
|
|
144
|
+
function __ball_add(a: any, b: any): any {
|
|
145
|
+
if (a != null && typeof a === 'object' && typeof a.__op_add === 'function') return a.__op_add(b);
|
|
146
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) + __to_bigint(b));
|
|
147
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
148
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
149
|
+
const r = av + bv;
|
|
150
|
+
return (a instanceof BallDouble || b instanceof BallDouble) ? new BallDouble(r) : r;
|
|
151
|
+
}
|
|
152
|
+
function __ball_sub(a: any, b: any): any {
|
|
153
|
+
if (a != null && typeof a === 'object' && typeof a.__op_sub === 'function') return a.__op_sub(b);
|
|
154
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) - __to_bigint(b));
|
|
155
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
156
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
157
|
+
const r = av - bv;
|
|
158
|
+
return (a instanceof BallDouble || b instanceof BallDouble) ? new BallDouble(r) : r;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Dart equality: NaN != NaN, BallDouble value comparison, null == undefined.
|
|
162
|
+
function __ball_eq(a: any, b: any): boolean {
|
|
163
|
+
if (a != null && typeof a === 'object' && typeof a.__op_eq === 'function') return a.__op_eq(b);
|
|
164
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') {
|
|
165
|
+
if (typeof a === 'bigint' && typeof b === 'bigint') return a === b;
|
|
166
|
+
if (typeof a === 'bigint' && typeof b === 'number') return a === BigInt(b);
|
|
167
|
+
if (typeof a === 'number' && typeof b === 'bigint') return BigInt(a) === b;
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
if (a instanceof BallDouble || b instanceof BallDouble) {
|
|
171
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
172
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
173
|
+
if (Number.isNaN(av) || Number.isNaN(bv)) return false;
|
|
174
|
+
return av === bv;
|
|
175
|
+
}
|
|
176
|
+
if (a == null && b == null) return true;
|
|
177
|
+
if (a == null || b == null) return a == b;
|
|
178
|
+
return a === b;
|
|
179
|
+
}
|
|
180
|
+
|
|
17
181
|
function __ball_to_string(v: any): string {
|
|
18
182
|
if (v === null || v === undefined) return 'null';
|
|
183
|
+
if (typeof v === 'bigint') return v.toString();
|
|
19
184
|
if (typeof v === 'boolean') return v ? 'true' : 'false';
|
|
185
|
+
if (v instanceof BallDouble) return v.toString();
|
|
20
186
|
if (typeof v === 'number') {
|
|
187
|
+
if (!isFinite(v) || Number.isNaN(v)) return v.toString();
|
|
188
|
+
if (v === 0 && 1/v === -Infinity) return '-0.0';
|
|
21
189
|
if (Number.isInteger(v)) return v.toString();
|
|
22
190
|
const s = v.toString();
|
|
23
191
|
return s.includes('.') || s.includes('e') ? s : s + '.0';
|
|
@@ -33,6 +201,22 @@ function __ball_to_string(v: any): string {
|
|
|
33
201
|
}
|
|
34
202
|
return '{' + parts.join(', ') + '}';
|
|
35
203
|
}
|
|
204
|
+
if (typeof v === 'object' && !Array.isArray(v)) {
|
|
205
|
+
// StringBuffer-like objects
|
|
206
|
+
if (v['__buffer__'] && Array.isArray(v['__buffer__'])) {
|
|
207
|
+
return v['__buffer__'].join('');
|
|
208
|
+
}
|
|
209
|
+
// Check for custom toString method on the instance (not Object.prototype).
|
|
210
|
+
if (v.toString !== Object.prototype.toString && typeof v.toString === 'function') {
|
|
211
|
+
return v.toString();
|
|
212
|
+
}
|
|
213
|
+
// Dart Map-like object: format as {key: value, ...}
|
|
214
|
+
const keys = Object.keys(v).filter((k: string) => !k.startsWith('__'));
|
|
215
|
+
if (keys.length > 0) {
|
|
216
|
+
return '{' + keys.map((k: string) => __ball_to_string(k) + ': ' + __ball_to_string(v[k])).join(', ') + '}';
|
|
217
|
+
}
|
|
218
|
+
return '{}';
|
|
219
|
+
}
|
|
36
220
|
return String(v);
|
|
37
221
|
}
|
|
38
222
|
|
|
@@ -44,6 +228,31 @@ function __ball_parse_int(s: string): number {
|
|
|
44
228
|
return parseInt(trimmed, 10);
|
|
45
229
|
}
|
|
46
230
|
|
|
231
|
+
// Dart-style int conversion that preserves int64 precision. JS numbers lose
|
|
232
|
+
// precision above 2^53, so integer literals encoded as decimal strings (the
|
|
233
|
+
// JSON proto3 representation of int64) would round. When the string magnitude
|
|
234
|
+
// exceeds Number.MAX_SAFE_INTEGER we return a BigInt to keep the exact value;
|
|
235
|
+
// otherwise we keep a plain number so the common arithmetic path is unchanged.
|
|
236
|
+
function __ball_to_int(v: any): any {
|
|
237
|
+
if (typeof v === 'bigint') return v;
|
|
238
|
+
if (typeof v === 'string') {
|
|
239
|
+
if (/^-?\d+$/.test(v)) {
|
|
240
|
+
const b = BigInt(v);
|
|
241
|
+
if (b > 9007199254740991n || b < -9007199254740991n) return b;
|
|
242
|
+
return Number(b);
|
|
243
|
+
}
|
|
244
|
+
return Math.trunc(Number(v)) || 0;
|
|
245
|
+
}
|
|
246
|
+
const n = (v instanceof BallDouble) ? v.value : v;
|
|
247
|
+
const t = Math.trunc(n) || 0;
|
|
248
|
+
if (t >= 9223372036854775808) return __I64_MAX;
|
|
249
|
+
if (t <= -9223372036854775808) return __I64_MIN;
|
|
250
|
+
if (t > 9007199254740991 || t < -9007199254740991) {
|
|
251
|
+
try { return __i64_wrap(BigInt(Math.round(t))); } catch {}
|
|
252
|
+
}
|
|
253
|
+
return t;
|
|
254
|
+
}
|
|
255
|
+
|
|
47
256
|
function __ball_parse_double(s: string): number {
|
|
48
257
|
const n = parseFloat(s);
|
|
49
258
|
if (Number.isNaN(n)) throw new Error('FormatException: ' + s);
|
|
@@ -55,9 +264,161 @@ function __ball_double_to_string(n: number): string {
|
|
|
55
264
|
return n.toString();
|
|
56
265
|
}
|
|
57
266
|
|
|
267
|
+
// Polymorphic concat / merge used for std.list_concat. The encoder emits
|
|
268
|
+
// list_concat both for Dart list concat AND for Map.addAll(...) (encoded as
|
|
269
|
+
// m = list_concat(m, other)). Arrays concat positionally; plain objects
|
|
270
|
+
// (Ball maps) merge by key with the right side winning (so child class
|
|
271
|
+
// methods override parent methods).
|
|
272
|
+
function __ball_concat(a: any, b: any): any {
|
|
273
|
+
const aIsArr = Array.isArray(a);
|
|
274
|
+
const bIsArr = Array.isArray(b);
|
|
275
|
+
if (aIsArr || bIsArr) {
|
|
276
|
+
const al = aIsArr ? a : (a == null ? [] : [a]);
|
|
277
|
+
const bl = bIsArr ? b : (b == null ? [] : [b]);
|
|
278
|
+
return [...al, ...bl];
|
|
279
|
+
}
|
|
280
|
+
if ((a && typeof a === 'object') || (b && typeof b === 'object')) {
|
|
281
|
+
return Object.assign({}, a ?? {}, b ?? {});
|
|
282
|
+
}
|
|
283
|
+
return [a, b];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// In-place collection append: mutates target by appending all elements.
|
|
287
|
+
// For arrays: pushes elements (Dart List.addAll semantics).
|
|
288
|
+
// For objects: merges keys (Dart Map.addAll semantics).
|
|
289
|
+
// Preserves reference identity so callers sharing the same collection see changes.
|
|
290
|
+
function __ball_push_all(target: any, items: any): void {
|
|
291
|
+
if (Array.isArray(target)) {
|
|
292
|
+
if (Array.isArray(items)) {
|
|
293
|
+
for (let i = 0; i < items.length; i++) target.push(items[i]);
|
|
294
|
+
} else if (items != null) {
|
|
295
|
+
target.push(items);
|
|
296
|
+
}
|
|
297
|
+
} else if (target && typeof target === 'object') {
|
|
298
|
+
if (items && typeof items === 'object' && !Array.isArray(items)) {
|
|
299
|
+
for (const k of Object.keys(items)) target[k] = items[k];
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ── BigInt / signed-64-bit integer support ──────────────────────
|
|
305
|
+
// Dart int is signed 64-bit; JS Number loses precision above 2^53.
|
|
306
|
+
// Arithmetic on BigInt values wraps to the signed 64-bit range and
|
|
307
|
+
// demotes back to Number when the result fits in MAX_SAFE_INTEGER.
|
|
308
|
+
const __I64_MAX = 9223372036854775807n;
|
|
309
|
+
const __I64_MIN = -9223372036854775808n;
|
|
310
|
+
const __I64_MOD = 18446744073709551616n;
|
|
311
|
+
function __i64_wrap(v: bigint): any {
|
|
312
|
+
v = ((v % __I64_MOD) + __I64_MOD) % __I64_MOD;
|
|
313
|
+
if (v > __I64_MAX) v = v - __I64_MOD;
|
|
314
|
+
if (v >= -9007199254740991n && v <= 9007199254740991n) return Number(v);
|
|
315
|
+
return v;
|
|
316
|
+
}
|
|
317
|
+
function __to_bigint(v: any): bigint {
|
|
318
|
+
if (typeof v === 'bigint') return v;
|
|
319
|
+
if (v instanceof BallDouble) return BigInt(Math.trunc(v.value));
|
|
320
|
+
return BigInt(v);
|
|
321
|
+
}
|
|
322
|
+
function __ball_bitand(a: any, b: any): any { return __i64_wrap(__to_bigint(a) & __to_bigint(b)); }
|
|
323
|
+
function __ball_bitor(a: any, b: any): any { return __i64_wrap(__to_bigint(a) | __to_bigint(b)); }
|
|
324
|
+
function __ball_bitxor(a: any, b: any): any { return __i64_wrap(__to_bigint(a) ^ __to_bigint(b)); }
|
|
325
|
+
function __ball_bitnot(a: any): any { return __i64_wrap(~__to_bigint(a)); }
|
|
326
|
+
function __ball_shl(a: any, b: any): any { return __i64_wrap(__to_bigint(a) << __to_bigint(b)); }
|
|
327
|
+
function __ball_shr(a: any, b: any): any { return __i64_wrap(__to_bigint(a) >> __to_bigint(b)); }
|
|
328
|
+
function __ball_negate(a: any): any {
|
|
329
|
+
if (typeof a === 'bigint') return __i64_wrap(-a);
|
|
330
|
+
if (a instanceof BallDouble) return new BallDouble(-a.value);
|
|
331
|
+
return -a;
|
|
332
|
+
}
|
|
333
|
+
function __ball_divide(a: any, b: any): any {
|
|
334
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') {
|
|
335
|
+
const ba = __to_bigint(a), bb = __to_bigint(b);
|
|
336
|
+
const r = ba / bb;
|
|
337
|
+
return __i64_wrap(r);
|
|
338
|
+
}
|
|
339
|
+
return Math.trunc(a / b);
|
|
340
|
+
}
|
|
341
|
+
function __ball_math_abs(a: any): any {
|
|
342
|
+
if (typeof a === 'bigint') {
|
|
343
|
+
const neg = -a;
|
|
344
|
+
return __i64_wrap(neg < 0n ? a : neg);
|
|
345
|
+
}
|
|
346
|
+
return Math.abs(a);
|
|
347
|
+
}
|
|
348
|
+
// Greatest common divisor (Dart's int.gcd). Preserves BigInt (i64) inputs so
|
|
349
|
+
// integer identities round-trip; falls back to Number arithmetic otherwise.
|
|
350
|
+
function __ball_math_gcd(a: any, b: any): any {
|
|
351
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') {
|
|
352
|
+
let x = __to_bigint(a); x = x < 0n ? -x : x;
|
|
353
|
+
let y = __to_bigint(b); y = y < 0n ? -y : y;
|
|
354
|
+
while (y) { const t = y; y = x % y; x = t; }
|
|
355
|
+
return __i64_wrap(x);
|
|
356
|
+
}
|
|
357
|
+
let x = Math.abs(Number(a)), y = Math.abs(Number(b));
|
|
358
|
+
while (y) { const t = y; y = x % y; x = t; }
|
|
359
|
+
return x;
|
|
360
|
+
}
|
|
361
|
+
// Least common multiple, derived from gcd. lcm(0, n) == lcm(n, 0) == 0.
|
|
362
|
+
function __ball_math_lcm(a: any, b: any): any {
|
|
363
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') {
|
|
364
|
+
const x = __to_bigint(a), y = __to_bigint(b);
|
|
365
|
+
if (x === 0n || y === 0n) return __i64_wrap(0n);
|
|
366
|
+
const g = __to_bigint(__ball_math_gcd(x, y));
|
|
367
|
+
const r = (x / g) * y;
|
|
368
|
+
return __i64_wrap(r < 0n ? -r : r);
|
|
369
|
+
}
|
|
370
|
+
const x = Number(a), y = Number(b);
|
|
371
|
+
if (x === 0 || y === 0) return 0;
|
|
372
|
+
const g = Number(__ball_math_gcd(x, y));
|
|
373
|
+
return Math.abs((x / g) * y);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Dart-style Euclidean modulo: result is always non-negative.
|
|
377
|
+
// JS % is remainder (can be negative), Dart % is Euclidean modulo.
|
|
378
|
+
function __dart_mod(a: any, b: any): any {
|
|
379
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') {
|
|
380
|
+
const ba = __to_bigint(a), bb = __to_bigint(b);
|
|
381
|
+
const r = ba % bb;
|
|
382
|
+
return __i64_wrap(r < 0n ? r + (bb < 0n ? -bb : bb) : r);
|
|
383
|
+
}
|
|
384
|
+
const r = a % b;
|
|
385
|
+
return r < 0 ? r + (b < 0 ? -b : b) : r;
|
|
386
|
+
}
|
|
387
|
+
|
|
58
388
|
// Active exception for rethrow. Catch bodies shadow with a local.
|
|
59
389
|
let __ball_active_error: any = undefined;
|
|
60
390
|
|
|
391
|
+
// Safe own-property lookup. Returns undefined if key is not an own property.
|
|
392
|
+
// Avoids triggering Object.prototype getters (entries, keys, values) on
|
|
393
|
+
// plain objects that aren't meant to be Dart Maps.
|
|
394
|
+
function __ball_own(obj: any, key: any): any {
|
|
395
|
+
if (obj == null || typeof obj !== 'object') return undefined;
|
|
396
|
+
return Object.prototype.hasOwnProperty.call(obj, key) ? obj[key] : undefined;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Dart-style index access. Dart's List '[]' operator throws RangeError on
|
|
400
|
+
// out-of-bounds access, whereas JS array indexing silently returns undefined.
|
|
401
|
+
// To make 'on RangeError' catch clauses behave like Dart we bounds-check list
|
|
402
|
+
// (array) access here and throw a RangeError-shaped exception. Maps, strings
|
|
403
|
+
// and objects keep their JS semantics (no throw) — Dart Map '[]' returns null
|
|
404
|
+
// for absent keys, and String '[]' is handled by callers.
|
|
405
|
+
function __ball_index(target: any, idx: any): any {
|
|
406
|
+
if (Array.isArray(target) && typeof idx === 'number' && Number.isInteger(idx)) {
|
|
407
|
+
if (idx < 0 || idx >= target.length) {
|
|
408
|
+
throw {
|
|
409
|
+
__type__: 'RangeError',
|
|
410
|
+
message: 'RangeError (index): Invalid value: ' +
|
|
411
|
+
(target.length === 0
|
|
412
|
+
? 'Valid value range is empty: ' + idx
|
|
413
|
+
: 'Not in inclusive range 0..' + (target.length - 1) + ': ' + idx),
|
|
414
|
+
index: idx,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
return target[idx];
|
|
418
|
+
}
|
|
419
|
+
return target[idx];
|
|
420
|
+
}
|
|
421
|
+
|
|
61
422
|
// Dart type shims — provide static methods for Dart built-in types
|
|
62
423
|
// that don't exist in JS (int, double, num, bool).
|
|
63
424
|
const int = {
|
|
@@ -84,6 +445,161 @@ const bool = {
|
|
|
84
445
|
// late-initialized variables and block-scoped flow tracking.
|
|
85
446
|
const __no_init__: unique symbol = Symbol('__no_init__');
|
|
86
447
|
|
|
448
|
+
// Null-aware spread source normalizer (the ...? operator). Returns an
|
|
449
|
+
// iterable for the spread loop, mapping null / undefined / the __no_init__
|
|
450
|
+
// sentinel (an uninitialized nullable, e.g. List<int>? n;) to an empty list
|
|
451
|
+
// — matching Dart's ...?n which contributes nothing when the operand is null.
|
|
452
|
+
function __ball_spread_iter(v: any): any {
|
|
453
|
+
if (v == null || v === __no_init__) return [];
|
|
454
|
+
return v;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Dart type constructor shims — List, Map, etc.
|
|
458
|
+
const List = {
|
|
459
|
+
filled: (count: any, value: any) => Array(count).fill(value),
|
|
460
|
+
generate: (count: any, generator: any) => {
|
|
461
|
+
const r: any[] = [];
|
|
462
|
+
for (let i = 0; i < count; i++) r.push(generator(i));
|
|
463
|
+
return r;
|
|
464
|
+
},
|
|
465
|
+
from: (iter: any) => Array.isArray(iter) ? [...iter] : [...iter],
|
|
466
|
+
of: (iter: any) => Array.isArray(iter) ? [...iter] : [...iter],
|
|
467
|
+
unmodifiable: (iter: any) => Object.freeze(Array.isArray(iter) ? [...iter] : [...iter]),
|
|
468
|
+
empty: (opts?: any) => [],
|
|
469
|
+
castFrom: (source: any) => Array.isArray(source) ? [...source] : [],
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
// Set.unmodifiable
|
|
473
|
+
const _nativeSet = Set;
|
|
474
|
+
(Set as any).unmodifiable = (iter: any) => {
|
|
475
|
+
const s = new _nativeSet(iter);
|
|
476
|
+
return Object.freeze(s);
|
|
477
|
+
};
|
|
478
|
+
(Set as any).from = (iter: any) => new _nativeSet(iter);
|
|
479
|
+
(Set as any).of = (iter: any) => new _nativeSet(iter);
|
|
480
|
+
// Ball encoder sometimes uses set_create for lists, then list_push on them.
|
|
481
|
+
// Bridge the gap with push/indexOf/length on Set.
|
|
482
|
+
if (!(Set.prototype as any).push) (Set.prototype as any).push = function(v: any) { this.add(v); return this.size; };
|
|
483
|
+
Object.defineProperty(Set.prototype, 'length', { configurable: true, get() { return this.size; } });
|
|
484
|
+
Object.defineProperty(Set.prototype, 'isEmpty', { configurable: true, get() { return this.size === 0; } });
|
|
485
|
+
Object.defineProperty(Set.prototype, 'isNotEmpty', { configurable: true, get() { return this.size !== 0; } });
|
|
486
|
+
|
|
487
|
+
// Patch: scope _bindings must use null-prototype objects to avoid
|
|
488
|
+
// Object.prototype getters (entries, keys, values, length) polluting
|
|
489
|
+
// the "in" operator used by scope.lookup/has/set.
|
|
490
|
+
const _origScopeInit = { patched: false };
|
|
491
|
+
function _patchScopeBindings(scope: any) {
|
|
492
|
+
if (!scope || _origScopeInit.patched) return;
|
|
493
|
+
const ScopeClass = scope.constructor;
|
|
494
|
+
if (!ScopeClass) return;
|
|
495
|
+
const origCtor = ScopeClass;
|
|
496
|
+
const origBind = ScopeClass.prototype.bind;
|
|
497
|
+
// Override bind to lazily convert _bindings to null-proto object
|
|
498
|
+
ScopeClass.prototype.bind = function(name: any, value: any) {
|
|
499
|
+
if (Object.getPrototypeOf(this._bindings) !== null) {
|
|
500
|
+
const entries = Object.entries(this._bindings);
|
|
501
|
+
this._bindings = Object.create(null);
|
|
502
|
+
for (const [k, v] of entries) this._bindings[k] = v;
|
|
503
|
+
}
|
|
504
|
+
return (this._bindings[name] = value);
|
|
505
|
+
};
|
|
506
|
+
// Also patch child() to create null-proto bindings
|
|
507
|
+
const origChild = ScopeClass.prototype.child;
|
|
508
|
+
if (origChild) {
|
|
509
|
+
ScopeClass.prototype.child = function() {
|
|
510
|
+
const c = origChild.call(this);
|
|
511
|
+
if (Object.getPrototypeOf(c._bindings) !== null) {
|
|
512
|
+
c._bindings = Object.create(null);
|
|
513
|
+
}
|
|
514
|
+
return c;
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
_origScopeInit.patched = true;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Proto has* functions as global helpers (encoder routes method calls through ball_proto)
|
|
521
|
+
// Generic has* helper — returns true if obj[field] is present and non-null
|
|
522
|
+
function _has(obj: any, field: string): boolean { return obj?.[field] !== undefined && obj?.[field] !== null; }
|
|
523
|
+
function hasMetadata(obj: any): boolean { return _has(obj, 'metadata'); }
|
|
524
|
+
function hasBody(obj: any): boolean { return _has(obj, 'body'); }
|
|
525
|
+
function hasInput(obj: any): boolean { return _has(obj, 'input'); }
|
|
526
|
+
function hasDescriptor(obj: any): boolean { return _has(obj, 'descriptor'); }
|
|
527
|
+
function hasStringValue(obj: any): boolean { return _has(obj, 'stringValue'); }
|
|
528
|
+
function hasBoolValue(obj: any): boolean { return _has(obj, 'boolValue'); }
|
|
529
|
+
function hasNumberValue(obj: any): boolean { return _has(obj, 'numberValue'); }
|
|
530
|
+
function hasResult(obj: any): boolean { return _has(obj, 'result'); }
|
|
531
|
+
function hasCall(obj: any): boolean { return _has(obj, 'call'); }
|
|
532
|
+
function hasListValue(obj: any): boolean { return _has(obj, 'listValue'); }
|
|
533
|
+
function hasNullValue(obj: any): boolean { return _has(obj, 'nullValue'); }
|
|
534
|
+
function hasStructValue(obj: any): boolean { return _has(obj, 'structValue'); }
|
|
535
|
+
function hasMatch(obj: any): boolean { return _has(obj, 'match'); }
|
|
536
|
+
function hasXxx(obj: any): boolean { return false; }
|
|
537
|
+
function whichXxx(obj: any): string { return 'notSet'; }
|
|
538
|
+
// whichExpr/whichValue/whichStmt/whichKind sit on the hottest path of the
|
|
539
|
+
// compiled engine (whichExpr alone runs up to 8x per _evalExpression). The
|
|
540
|
+
// previous 'typeof obj.whichXxx === "function"' probe always walked the
|
|
541
|
+
// prototype chain to the Object.prototype shim installed by installProtoShims
|
|
542
|
+
// (true for EVERY plain object) and then *invoked* it — a prototype walk + a
|
|
543
|
+
// megamorphic keyed-load loop per call, even though the compiled engine's AST
|
|
544
|
+
// nodes never carry an own whichXxx. We gate the method probe behind an
|
|
545
|
+
// own-property check (so plain nodes skip the prototype walk entirely and use
|
|
546
|
+
// the inline discriminator) while still honoring hand-rolled wrapper objects —
|
|
547
|
+
// notably the metadata wrapValue Value wrappers, whose own getters
|
|
548
|
+
// (.stringValue etc.) are always-defined, so their own whichXxx() must win
|
|
549
|
+
// over the inline field probes. Hence the own-method check stays FIRST.
|
|
550
|
+
function whichExpr(obj: any): string {
|
|
551
|
+
if (!obj) return 'notSet';
|
|
552
|
+
if (Object.prototype.hasOwnProperty.call(obj, 'whichExpr') && typeof obj.whichExpr === 'function') return obj.whichExpr();
|
|
553
|
+
if (obj.call) return 'call'; if (obj.literal) return 'literal';
|
|
554
|
+
if (obj.reference) return 'reference'; if (obj.fieldAccess) return 'fieldAccess';
|
|
555
|
+
if (obj.messageCreation) return 'messageCreation'; if (obj.block) return 'block';
|
|
556
|
+
if (obj.lambda) return 'lambda'; return 'notSet';
|
|
557
|
+
}
|
|
558
|
+
function whichValue(obj: any): string {
|
|
559
|
+
if (!obj) return 'notSet';
|
|
560
|
+
if (Object.prototype.hasOwnProperty.call(obj, 'whichValue') && typeof obj.whichValue === 'function') return obj.whichValue();
|
|
561
|
+
if (obj.intValue !== undefined) return 'intValue'; if (obj.doubleValue !== undefined) return 'doubleValue';
|
|
562
|
+
if (obj.stringValue !== undefined) return 'stringValue'; if (obj.boolValue !== undefined) return 'boolValue';
|
|
563
|
+
if (obj.listValue) return 'listValue'; if (obj.bytesValue !== undefined) return 'bytesValue';
|
|
564
|
+
return 'notSet';
|
|
565
|
+
}
|
|
566
|
+
function whichStmt(obj: any): string {
|
|
567
|
+
if (!obj) return 'notSet';
|
|
568
|
+
if (Object.prototype.hasOwnProperty.call(obj, 'whichStmt') && typeof obj.whichStmt === 'function') return obj.whichStmt();
|
|
569
|
+
if (obj.let) return 'let'; if (obj.expression) return 'expression'; return 'notSet';
|
|
570
|
+
}
|
|
571
|
+
function whichKind(obj: any): string {
|
|
572
|
+
if (!obj) return 'notSet';
|
|
573
|
+
if (Object.prototype.hasOwnProperty.call(obj, 'whichKind') && typeof obj.whichKind === 'function') return obj.whichKind();
|
|
574
|
+
if (obj.nullValue !== undefined) return 'nullValue'; if (obj.numberValue !== undefined) return 'numberValue';
|
|
575
|
+
if (obj.stringValue !== undefined) return 'stringValue'; if (obj.boolValue !== undefined) return 'boolValue';
|
|
576
|
+
if (obj.structValue) return 'structValue'; if (obj.listValue) return 'listValue';
|
|
577
|
+
return 'notSet';
|
|
578
|
+
}
|
|
579
|
+
function whichSource(obj: any): string {
|
|
580
|
+
if (!obj) return 'notSet';
|
|
581
|
+
if (obj.path) return 'path'; if (obj.url) return 'url'; if (obj.inline) return 'inline';
|
|
582
|
+
return 'notSet';
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// Identical function (Dart identical())
|
|
586
|
+
function identical(a: any, b: any): boolean { return a === b; }
|
|
587
|
+
|
|
588
|
+
// Function.apply shim (Dart Function.apply)
|
|
589
|
+
(Function as any).apply = function(fn: any, positionalArgs: any, namedArgs?: any) {
|
|
590
|
+
if (typeof fn !== 'function') return undefined;
|
|
591
|
+
const args = positionalArgs == null ? [] : (Array.isArray(positionalArgs) ? positionalArgs : [positionalArgs]);
|
|
592
|
+
return fn(...args);
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
// Dart cascade helper — evaluates target, applies ops, returns target.
|
|
596
|
+
function __ball_cascade(target: any, ops: any[]): any {
|
|
597
|
+
for (const op of ops) {
|
|
598
|
+
if (typeof op === 'function') op(target);
|
|
599
|
+
}
|
|
600
|
+
return target;
|
|
601
|
+
}
|
|
602
|
+
|
|
87
603
|
// ── Dart \u2192 JS method-name polyfills ────────────────────────────────
|
|
88
604
|
//
|
|
89
605
|
// Idempotent: guarded so multiple preamble inclusions don't double-install.
|
|
@@ -118,14 +634,39 @@ const __no_init__: unique symbol = Symbol('__no_init__');
|
|
|
118
634
|
for (const v of iter) this.push(v);
|
|
119
635
|
};
|
|
120
636
|
if (!ap.removeLast) ap.removeLast = function () { return this.pop(); };
|
|
637
|
+
if (!ap.removeAt) ap.removeAt = function (i: any) { return this.splice(i, 1)[0]; };
|
|
638
|
+
if (!ap.insert) ap.insert = function (i: any, v: any) { this.splice(i, 0, v); };
|
|
639
|
+
if (!ap.setAll) ap.setAll = function (idx: number, values: any[]) { for (let i = 0; i < values.length; i++) this[idx + i] = values[i]; };
|
|
121
640
|
if (!ap.where) ap.where = Array.prototype.filter;
|
|
122
641
|
if (!ap.toList) ap.toList = function () { return this.slice(); };
|
|
123
642
|
if (!ap.toSet) ap.toSet = function () { return new Set(this); };
|
|
124
643
|
if (!ap.contains) ap.contains = function (v: any) { return this.indexOf(v) >= 0; };
|
|
644
|
+
if (!ap.sublist) ap.sublist = function (start: any, end?: any) { return this.slice(start, end); };
|
|
645
|
+
if (!ap.asMap) ap.asMap = function () {
|
|
646
|
+
const m: any = {};
|
|
647
|
+
for (let i = 0; i < this.length; i++) m[i] = this[i];
|
|
648
|
+
return m;
|
|
649
|
+
};
|
|
650
|
+
if (!ap.expand) ap.expand = function (fn: any) { return this.flatMap(fn); };
|
|
651
|
+
if (!ap.take) ap.take = function (n: any) { return this.slice(0, n); };
|
|
652
|
+
if (!ap.skip) ap.skip = function (n: any) { return this.slice(n); };
|
|
653
|
+
if (!ap.any) ap.any = function (fn: any) { return this.some(fn); };
|
|
654
|
+
if (!ap.fold) ap.fold = function (init: any, fn: any) { return this.reduce(fn, init); };
|
|
655
|
+
if (!ap.followedBy) ap.followedBy = function (other: any) { return [...this, ...other]; };
|
|
656
|
+
if (!ap.getRange) ap.getRange = function (start: any, end: any) { return this.slice(start, end); };
|
|
657
|
+
if (!ap.fillRange) ap.fillRange = function (start: any, end: any, fill: any) {
|
|
658
|
+
for (let i = start; i < end; i++) this[i] = fill;
|
|
659
|
+
};
|
|
660
|
+
if (!ap.setRange) ap.setRange = function (start: any, end: any, iterable: any, skipCount?: any) {
|
|
661
|
+
const src = Array.isArray(iterable) ? iterable : [...iterable];
|
|
662
|
+
const skip = skipCount ?? 0;
|
|
663
|
+
for (let i = start; i < end; i++) this[i] = src[i - start + skip];
|
|
664
|
+
};
|
|
125
665
|
|
|
126
666
|
// Dart Set polyfills — Set.contains → Set.has, etc.
|
|
127
667
|
const setp: any = Set.prototype;
|
|
128
668
|
if (!setp.contains) setp.contains = function (v: any) { return this.has(v); };
|
|
669
|
+
if (!setp.includes) setp.includes = function (v: any) { return this.has(v); };
|
|
129
670
|
if (!setp.toList) setp.toList = function () { return [...this]; };
|
|
130
671
|
if (!setp.add) { /* Set already has .add */ }
|
|
131
672
|
if (!setp.remove) setp.remove = function (v: any) { return this.delete(v); };
|
|
@@ -149,6 +690,9 @@ const __no_init__: unique symbol = Symbol('__no_init__');
|
|
|
149
690
|
Object.defineProperty(sp, 'isNotEmpty', {
|
|
150
691
|
configurable: true, get() { return this.length !== 0; },
|
|
151
692
|
});
|
|
693
|
+
// Note: undefined/null safety for .isEmpty/.isNotEmpty is handled in the
|
|
694
|
+
// generated code via optional-chaining (?.isEmpty) patterns and protoWrap;
|
|
695
|
+
// properties cannot be installed on undefined/null directly.
|
|
152
696
|
// Dart String methods not on JS String.
|
|
153
697
|
if (!sp.contains) sp.contains = function (s: any) { return this.includes(s); };
|
|
154
698
|
if (!sp.replaceFirst) sp.replaceFirst = function (from: any, to: any) {
|
|
@@ -180,6 +724,37 @@ const __no_init__: unique symbol = Symbol('__no_init__');
|
|
|
180
724
|
};
|
|
181
725
|
if (!rp.hasMatch) rp.hasMatch = function (s: any) { return this.test(s); };
|
|
182
726
|
|
|
727
|
+
// Dart Number polyfills — Dart num/int methods not on JS Number.prototype.
|
|
728
|
+
const _ballNp: any = Number.prototype;
|
|
729
|
+
if (!_ballNp.gcd) _ballNp.gcd = function (other: any) {
|
|
730
|
+
let a = Math.abs(this as number), b = Math.abs(Number(other));
|
|
731
|
+
while (b) { const t = b; b = a % b; a = t; }
|
|
732
|
+
return a;
|
|
733
|
+
};
|
|
734
|
+
Object.defineProperty(_ballNp, 'sign', {
|
|
735
|
+
configurable: true, get() { const n = Number(this); return n > 0 ? 1 : n < 0 ? -1 : 0; },
|
|
736
|
+
});
|
|
737
|
+
Object.defineProperty(_ballNp, 'isNaN', {
|
|
738
|
+
configurable: true, get() { return Number.isNaN(Number(this)); },
|
|
739
|
+
});
|
|
740
|
+
Object.defineProperty(_ballNp, 'isFinite', {
|
|
741
|
+
configurable: true, get() { return Number.isFinite(Number(this)); },
|
|
742
|
+
});
|
|
743
|
+
Object.defineProperty(_ballNp, 'isInfinite', {
|
|
744
|
+
configurable: true, get() { const n = Number(this); return n === Infinity || n === -Infinity; },
|
|
745
|
+
});
|
|
746
|
+
if (!_ballNp.abs) _ballNp.abs = function () { return Math.abs(Number(this)); };
|
|
747
|
+
if (!_ballNp.ceil) _ballNp.ceil = function () { return Math.ceil(Number(this)); };
|
|
748
|
+
if (!_ballNp.floor) _ballNp.floor = function () { return Math.floor(Number(this)); };
|
|
749
|
+
if (!_ballNp.round) _ballNp.round = function () { return Math.round(Number(this)); };
|
|
750
|
+
if (!_ballNp.truncate) _ballNp.truncate = function () { return Math.trunc(Number(this)); };
|
|
751
|
+
if (!_ballNp.toInt) _ballNp.toInt = function () { return Math.trunc(Number(this)); };
|
|
752
|
+
if (!_ballNp.toDouble) _ballNp.toDouble = function () { return Number(this); };
|
|
753
|
+
if (!_ballNp.clamp) _ballNp.clamp = function (lo: any, hi: any) { const n = Number(this); return n < lo ? lo : n > hi ? hi : n; };
|
|
754
|
+
if (!_ballNp.compareTo) _ballNp.compareTo = function (other: any) { const a = Number(this), b = Number(other); return a < b ? -1 : a > b ? 1 : 0; };
|
|
755
|
+
if (!_ballNp.toStringAsFixed) _ballNp.toStringAsFixed = function (digits: any) { return Number(this).toFixed(digits); };
|
|
756
|
+
if (!_ballNp.remainder) _ballNp.remainder = function (other: any) { return Number(this) % Number(other); };
|
|
757
|
+
|
|
183
758
|
// Object.prototype polyfills — used by the compiled engine when
|
|
184
759
|
// checking Ball program inputs (plain objects, not Maps).
|
|
185
760
|
const op2: any = Object.prototype;
|
|
@@ -189,7 +764,7 @@ const __no_init__: unique symbol = Symbol('__no_init__');
|
|
|
189
764
|
value: function (k: any) {
|
|
190
765
|
if (this instanceof Map) return this.has(k);
|
|
191
766
|
if (this == null || typeof this !== 'object') return false;
|
|
192
|
-
return k
|
|
767
|
+
return Object.prototype.hasOwnProperty.call(this, k);
|
|
193
768
|
},
|
|
194
769
|
});
|
|
195
770
|
}
|
|
@@ -207,6 +782,44 @@ const __no_init__: unique symbol = Symbol('__no_init__');
|
|
|
207
782
|
},
|
|
208
783
|
});
|
|
209
784
|
}
|
|
785
|
+
// addAll — Dart Map.addAll. Works on plain objects too.
|
|
786
|
+
if (!op2.addAll) {
|
|
787
|
+
Object.defineProperty(op2, 'addAll', {
|
|
788
|
+
configurable: true, writable: true, enumerable: false,
|
|
789
|
+
value: function (other: any) {
|
|
790
|
+
if (this instanceof Map) {
|
|
791
|
+
if (other instanceof Map) {
|
|
792
|
+
for (const [k, v] of other.entries()) this.set(k, v);
|
|
793
|
+
} else if (other && typeof other === 'object') {
|
|
794
|
+
for (const k of Object.keys(other)) this.set(k, other[k]);
|
|
795
|
+
}
|
|
796
|
+
} else {
|
|
797
|
+
if (other instanceof Map) {
|
|
798
|
+
for (const [k, v] of other) this[k] = v;
|
|
799
|
+
} else if (other && typeof other === 'object') {
|
|
800
|
+
Object.assign(this, other);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
},
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
// forEach — Dart Map.forEach. Works on plain objects.
|
|
807
|
+
// Don't overwrite native Map.prototype.forEach.
|
|
808
|
+
Object.defineProperty(op2, 'forEach', {
|
|
809
|
+
configurable: true, writable: true, enumerable: false,
|
|
810
|
+
value: function (fn: any) {
|
|
811
|
+
if (this instanceof Map) {
|
|
812
|
+
return Map.prototype.forEach.call(this, fn);
|
|
813
|
+
}
|
|
814
|
+
if (Array.isArray(this)) {
|
|
815
|
+
return Array.prototype.forEach.call(this, fn);
|
|
816
|
+
}
|
|
817
|
+
// Plain object: Dart Map.forEach(void f(K key, V value))
|
|
818
|
+
if (typeof fn === 'function') {
|
|
819
|
+
for (const k of Object.keys(this)) fn(k, this[k]);
|
|
820
|
+
}
|
|
821
|
+
},
|
|
822
|
+
});
|
|
210
823
|
// remove — Dart Map.remove.
|
|
211
824
|
if (!op2.remove) {
|
|
212
825
|
Object.defineProperty(op2, 'remove', {
|
|
@@ -217,6 +830,14 @@ const __no_init__: unique symbol = Symbol('__no_init__');
|
|
|
217
830
|
},
|
|
218
831
|
});
|
|
219
832
|
}
|
|
833
|
+
// cast — Dart Map.cast<K2,V2>() / List.cast<E2>(). The cast is a static
|
|
834
|
+
// re-typing only; at runtime it returns the same collection unchanged.
|
|
835
|
+
if (!op2.cast) {
|
|
836
|
+
Object.defineProperty(op2, 'cast', {
|
|
837
|
+
configurable: true, writable: true, enumerable: false,
|
|
838
|
+
value: function () { return this; },
|
|
839
|
+
});
|
|
840
|
+
}
|
|
220
841
|
// Dart Map has .entries / .keys / .values as GETTERS (no parens).
|
|
221
842
|
// JS Map has them as METHODS (need parens). The compiled engine
|
|
222
843
|
// accesses map.entries as a getter. Shadow BOTH Map.prototype AND
|
|
@@ -240,41 +861,81 @@ const __no_init__: unique symbol = Symbol('__no_init__');
|
|
|
240
861
|
get() { return [..._nativeMapValues.call(this)]; },
|
|
241
862
|
});
|
|
242
863
|
// For plain objects — same getters on Object.prototype.
|
|
243
|
-
Object.
|
|
864
|
+
// Helper: define a getter on Object.prototype that also allows
|
|
865
|
+
// own-property assignment (setter stores as a data property on the
|
|
866
|
+
// instance, shadowing the prototype getter for future accesses).
|
|
867
|
+
function defDartGetter(name: string, getter: () => any) {
|
|
868
|
+
Object.defineProperty(op2, name, {
|
|
869
|
+
configurable: true, enumerable: false,
|
|
870
|
+
get: getter,
|
|
871
|
+
set(v: any) {
|
|
872
|
+
Object.defineProperty(this, name, {
|
|
873
|
+
value: v, writable: true, configurable: true, enumerable: true,
|
|
874
|
+
});
|
|
875
|
+
},
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
defDartGetter('entries', function (this: any) {
|
|
879
|
+
if (this instanceof Map) return [..._nativeMapEntries.call(this)].map(([k, v]: any) => ({ key: k, value: v }));
|
|
880
|
+
if (this == null || typeof this !== 'object') return [];
|
|
881
|
+
return Object.entries(this).map(([k, v]: any) => ({ key: k, value: v }));
|
|
882
|
+
});
|
|
883
|
+
defDartGetter('keys', function (this: any) {
|
|
884
|
+
if (this instanceof Map) return [..._nativeMapKeys.call(this)];
|
|
885
|
+
if (this == null || typeof this !== 'object') return [];
|
|
886
|
+
return Object.keys(this);
|
|
887
|
+
});
|
|
888
|
+
defDartGetter('values', function (this: any) {
|
|
889
|
+
if (this instanceof Map) return [..._nativeMapValues.call(this)];
|
|
890
|
+
if (this == null || typeof this !== 'object') return [];
|
|
891
|
+
return Object.values(this);
|
|
892
|
+
});
|
|
893
|
+
defDartGetter('length', function (this: any) {
|
|
894
|
+
if (this instanceof Map) return this.size;
|
|
895
|
+
if (this instanceof Set) return this.size;
|
|
896
|
+
if (typeof this === 'string' || Array.isArray(this)) return this.length;
|
|
897
|
+
if (this == null || typeof this !== 'object') return 0;
|
|
898
|
+
return Object.keys(this).filter((k: string) => !k.startsWith('__')).length;
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
// runtimeType — Dart's Object.runtimeType. Returns the Dart-style
|
|
902
|
+
// type name for any JS value. Used by the compiled engine for type
|
|
903
|
+
// checking and error messages.
|
|
904
|
+
Object.defineProperty(op2, 'runtimeType', {
|
|
244
905
|
configurable: true, enumerable: false,
|
|
245
906
|
get() {
|
|
246
|
-
if (this
|
|
247
|
-
if (this
|
|
248
|
-
|
|
907
|
+
if (this === null || this === undefined) return 'Null';
|
|
908
|
+
if (this instanceof BallDouble) return 'double';
|
|
909
|
+
if (typeof this === 'number' || this instanceof Number) return Number.isInteger(+this) ? 'int' : 'double';
|
|
910
|
+
if (typeof this === 'string' || this instanceof String) return 'String';
|
|
911
|
+
if (typeof this === 'boolean' || this instanceof Boolean) return 'bool';
|
|
912
|
+
if (typeof this === 'function') return 'Function';
|
|
913
|
+
if (Array.isArray(this)) return 'List';
|
|
914
|
+
if (this instanceof Set) return 'Set';
|
|
915
|
+
if (this instanceof Map) return 'Map';
|
|
916
|
+
if (this instanceof RegExp) return 'RegExp';
|
|
917
|
+
const t = this['__type__'];
|
|
918
|
+
if (typeof t === 'string' && t.length > 0) {
|
|
919
|
+
const ci = t.indexOf(':');
|
|
920
|
+
return ci >= 0 ? t.substring(ci + 1) : t;
|
|
921
|
+
}
|
|
922
|
+
return 'Map';
|
|
249
923
|
},
|
|
250
924
|
});
|
|
251
|
-
|
|
925
|
+
// Also add to Number.prototype, String.prototype, Boolean.prototype
|
|
926
|
+
// (they don't inherit from Object.prototype getters reliably for primitives).
|
|
927
|
+
Object.defineProperty(Number.prototype, 'runtimeType', {
|
|
252
928
|
configurable: true, enumerable: false,
|
|
253
|
-
get() {
|
|
254
|
-
if (this instanceof Map) return [..._nativeMapKeys.call(this)];
|
|
255
|
-
if (this == null || typeof this !== 'object') return [];
|
|
256
|
-
return Object.keys(this);
|
|
257
|
-
},
|
|
929
|
+
get() { return Number.isInteger(+this) ? 'int' : 'double'; },
|
|
258
930
|
});
|
|
259
|
-
Object.defineProperty(
|
|
931
|
+
Object.defineProperty(String.prototype, 'runtimeType', {
|
|
260
932
|
configurable: true, enumerable: false,
|
|
261
|
-
get() {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
},
|
|
933
|
+
get() { return 'String'; },
|
|
934
|
+
});
|
|
935
|
+
Object.defineProperty(Boolean.prototype, 'runtimeType', {
|
|
936
|
+
configurable: true, enumerable: false,
|
|
937
|
+
get() { return 'bool'; },
|
|
266
938
|
});
|
|
267
|
-
|
|
268
|
-
// Number polyfills for Dart-style methods.
|
|
269
|
-
const np: any = Number.prototype;
|
|
270
|
-
if (!np.toInt) np.toInt = function () { return Math.trunc(this); };
|
|
271
|
-
if (!np.toDouble) np.toDouble = function () { return this + 0.0; };
|
|
272
|
-
if (!np.compareTo) np.compareTo = function (other: any) {
|
|
273
|
-
return this < other ? -1 : this > other ? 1 : 0;
|
|
274
|
-
};
|
|
275
|
-
if (!np.clamp) np.clamp = function (lo: any, hi: any) {
|
|
276
|
-
return Math.min(Math.max(this, lo), hi);
|
|
277
|
-
};
|
|
278
939
|
})();
|
|
279
940
|
|
|
280
941
|
// ── Protobuf Struct/Value compatibility ─────────────────────────
|
|
@@ -470,5 +1131,209 @@ const ModuleImport_Source = {
|
|
|
470
1131
|
return [];
|
|
471
1132
|
});
|
|
472
1133
|
})();
|
|
1134
|
+
|
|
1135
|
+
// ── Reified generics helpers ────────────────────────────────────────
|
|
1136
|
+
function __ball_with_type_args<T>(obj: T, args: string[]): T {
|
|
1137
|
+
(obj as any).__type_args__ = args;
|
|
1138
|
+
return obj;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
// ── Generic type checking helper ────────────────────────────────────
|
|
1142
|
+
function __ball_split_type_args(s: string): string[] {
|
|
1143
|
+
const result: string[] = [];
|
|
1144
|
+
let depth = 0, start = 0;
|
|
1145
|
+
for (let i = 0; i < s.length; i++) {
|
|
1146
|
+
if (s[i] === '<') depth++;
|
|
1147
|
+
else if (s[i] === '>') depth--;
|
|
1148
|
+
else if (s[i] === ',' && depth === 0) {
|
|
1149
|
+
result.push(s.slice(start, i).trim());
|
|
1150
|
+
start = i + 1;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
const last = s.slice(start).trim();
|
|
1154
|
+
if (last) result.push(last);
|
|
1155
|
+
return result;
|
|
1156
|
+
}
|
|
1157
|
+
function __ball_is_type(value: any, typeStr: string): boolean {
|
|
1158
|
+
const t = typeStr.trim();
|
|
1159
|
+
if (t.endsWith('?')) {
|
|
1160
|
+
if (value == null) return true;
|
|
1161
|
+
return __ball_is_type(value, t.slice(0, -1));
|
|
1162
|
+
}
|
|
1163
|
+
const ltIdx = t.indexOf('<');
|
|
1164
|
+
if (ltIdx === -1) {
|
|
1165
|
+
switch (t) {
|
|
1166
|
+
case 'int': return typeof value === 'number' && Number.isInteger(value);
|
|
1167
|
+
case 'double': return value instanceof BallDouble || (typeof value === 'number' && !Number.isInteger(value));
|
|
1168
|
+
case 'num': case 'number': return typeof value === 'number' || value instanceof BallDouble;
|
|
1169
|
+
case 'String': case 'string': return typeof value === 'string';
|
|
1170
|
+
case 'bool': case 'boolean': return typeof value === 'boolean';
|
|
1171
|
+
case 'List': case 'Iterable': return Array.isArray(value);
|
|
1172
|
+
case 'Map': return typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof BallDouble) && !(value instanceof Set);
|
|
1173
|
+
case 'Set': return value instanceof Set;
|
|
1174
|
+
case 'Null': return value == null;
|
|
1175
|
+
case 'Function': return typeof value === 'function';
|
|
1176
|
+
case 'Object': case 'dynamic': return value != null;
|
|
1177
|
+
default: {
|
|
1178
|
+
const objType = value?.__type__ ?? value?.constructor?.name;
|
|
1179
|
+
if (objType === t) return true;
|
|
1180
|
+
return value != null;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
const baseType = t.slice(0, ltIdx).trim();
|
|
1185
|
+
const typeArgs = __ball_split_type_args(t.slice(ltIdx + 1, t.lastIndexOf('>')));
|
|
1186
|
+
switch (baseType) {
|
|
1187
|
+
case 'List': case 'Iterable':
|
|
1188
|
+
if (!Array.isArray(value)) return false;
|
|
1189
|
+
if (typeArgs.length === 0) return true;
|
|
1190
|
+
return value.every((e: any) => __ball_is_type(e, typeArgs[0]));
|
|
1191
|
+
case 'Map':
|
|
1192
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value) || value instanceof BallDouble || value instanceof Set) return false;
|
|
1193
|
+
if (typeArgs.length < 2) return true;
|
|
1194
|
+
return Object.keys(value).filter((k: string) => !k.startsWith('__')).every((k: string) => __ball_is_type(k, typeArgs[0]) && __ball_is_type(value[k], typeArgs[1]));
|
|
1195
|
+
case 'Set':
|
|
1196
|
+
if (!(value instanceof Set)) return false;
|
|
1197
|
+
if (typeArgs.length === 0) return true;
|
|
1198
|
+
for (const e of value) { if (!__ball_is_type(e, typeArgs[0])) return false; }
|
|
1199
|
+
return true;
|
|
1200
|
+
default: {
|
|
1201
|
+
const objType = value?.__type__ ?? value?.constructor?.name;
|
|
1202
|
+
if (objType === baseType) {
|
|
1203
|
+
const objArgs = value.__type_args__;
|
|
1204
|
+
if (Array.isArray(objArgs)) {
|
|
1205
|
+
if (objArgs.length !== typeArgs.length) return false;
|
|
1206
|
+
return objArgs.every((a: any, i: number) => String(a).trim() === typeArgs[i].trim());
|
|
1207
|
+
}
|
|
1208
|
+
return false;
|
|
1209
|
+
}
|
|
1210
|
+
return __ball_is_type(value, baseType);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
// Minimal DateTime / Duration / Future polyfills used by std_time and
|
|
1216
|
+
// the round-tripped engine's sleep_ms helper. Wide enough for the
|
|
1217
|
+
// conformance suite, narrow enough to stay out of users' way.
|
|
1218
|
+
class DateTime {
|
|
1219
|
+
readonly _epochMs: number;
|
|
1220
|
+
readonly isUtc: boolean;
|
|
1221
|
+
constructor(epochMs?: number, isUtc: boolean = false) {
|
|
1222
|
+
this._epochMs = typeof epochMs === 'number' ? epochMs : Date.now();
|
|
1223
|
+
this.isUtc = isUtc;
|
|
1224
|
+
}
|
|
1225
|
+
static now(): DateTime { return new DateTime(Date.now(), false); }
|
|
1226
|
+
static fromMillisecondsSinceEpoch(ms: number, isUtc: any = false): DateTime {
|
|
1227
|
+
return new DateTime(ms, isUtc === true || (isUtc && (isUtc as any).isUtc === true));
|
|
1228
|
+
}
|
|
1229
|
+
static parse(s: string): DateTime { return new DateTime(Date.parse(s), true); }
|
|
1230
|
+
get millisecondsSinceEpoch(): number { return this._epochMs; }
|
|
1231
|
+
get microsecondsSinceEpoch(): number { return this._epochMs * 1000; }
|
|
1232
|
+
toUtc(): DateTime { return new DateTime(this._epochMs, true); }
|
|
1233
|
+
toIso8601String(): string { return new Date(this._epochMs).toISOString(); }
|
|
1234
|
+
get year(): number { return new Date(this._epochMs).getUTCFullYear(); }
|
|
1235
|
+
get month(): number { return new Date(this._epochMs).getUTCMonth() + 1; }
|
|
1236
|
+
get day(): number { return new Date(this._epochMs).getUTCDate(); }
|
|
1237
|
+
get hour(): number { return new Date(this._epochMs).getUTCHours(); }
|
|
1238
|
+
get minute(): number { return new Date(this._epochMs).getUTCMinutes(); }
|
|
1239
|
+
get second(): number { return new Date(this._epochMs).getUTCSeconds(); }
|
|
1240
|
+
}
|
|
1241
|
+
class Duration {
|
|
1242
|
+
readonly _us: number;
|
|
1243
|
+
constructor(opts?: any) {
|
|
1244
|
+
const o = opts ?? {};
|
|
1245
|
+
const ms = o.milliseconds ?? 0;
|
|
1246
|
+
const s = o.seconds ?? 0;
|
|
1247
|
+
const m = o.minutes ?? 0;
|
|
1248
|
+
const us = o.microseconds ?? 0;
|
|
1249
|
+
this._us = us + ms * 1000 + s * 1_000_000 + m * 60_000_000;
|
|
1250
|
+
}
|
|
1251
|
+
get inMilliseconds(): number { return Math.floor(this._us / 1000); }
|
|
1252
|
+
get inMicroseconds(): number { return this._us; }
|
|
1253
|
+
}
|
|
1254
|
+
const Future = {
|
|
1255
|
+
delayed(d: any): Promise<void> {
|
|
1256
|
+
const ms = (d && typeof d.inMilliseconds === 'number') ? d.inMilliseconds : Number(d ?? 0);
|
|
1257
|
+
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
1258
|
+
},
|
|
1259
|
+
value(v: any): Promise<any> { return Promise.resolve(v); },
|
|
1260
|
+
};
|
|
1261
|
+
|
|
1262
|
+
// ── dart:typed_data shims (ByteData, Endian) ───────────────────────
|
|
1263
|
+
// ball_protobuf uses ByteData for IEEE 754 float/double bit conversion.
|
|
1264
|
+
// Dart's ByteData wraps a fixed-size byte buffer with typed get/set methods.
|
|
1265
|
+
const Endian = { little: true, big: false, host: true };
|
|
1266
|
+
|
|
1267
|
+
class ByteData {
|
|
1268
|
+
_view: DataView;
|
|
1269
|
+
_length: number;
|
|
1270
|
+
constructor(size: number) {
|
|
1271
|
+
this._view = new DataView(new ArrayBuffer(size));
|
|
1272
|
+
this._length = size;
|
|
1273
|
+
}
|
|
1274
|
+
get lengthInBytes(): number { return this._length; }
|
|
1275
|
+
getUint8(i: number): number { return this._view.getUint8(i); }
|
|
1276
|
+
setUint8(i: number, v: number): void { this._view.setUint8(i, v); }
|
|
1277
|
+
getInt8(i: number): number { return this._view.getInt8(i); }
|
|
1278
|
+
setInt8(i: number, v: number): void { this._view.setInt8(i, v); }
|
|
1279
|
+
getUint16(i: number, endian?: any): number { return this._view.getUint16(i, endian === Endian.little); }
|
|
1280
|
+
setUint16(i: number, v: number, endian?: any): void { this._view.setUint16(i, v, endian === Endian.little); }
|
|
1281
|
+
getInt16(i: number, endian?: any): number { return this._view.getInt16(i, endian === Endian.little); }
|
|
1282
|
+
setInt16(i: number, v: number, endian?: any): void { this._view.setInt16(i, v, endian === Endian.little); }
|
|
1283
|
+
getUint32(i: number, endian?: any): number { return this._view.getUint32(i, endian === Endian.little); }
|
|
1284
|
+
setUint32(i: number, v: number, endian?: any): void { this._view.setUint32(i, v, endian === Endian.little); }
|
|
1285
|
+
getInt32(i: number, endian?: any): number { return this._view.getInt32(i, endian === Endian.little); }
|
|
1286
|
+
setInt32(i: number, v: number, endian?: any): void { this._view.setInt32(i, v, endian === Endian.little); }
|
|
1287
|
+
getFloat32(i: number, endian?: any): number { return this._view.getFloat32(i, endian === Endian.little); }
|
|
1288
|
+
setFloat32(i: number, v: number, endian?: any): void { this._view.setFloat32(i, v, endian === Endian.little); }
|
|
1289
|
+
getFloat64(i: number, endian?: any): number { return this._view.getFloat64(i, endian === Endian.little); }
|
|
1290
|
+
setFloat64(i: number, v: number, endian?: any): void { this._view.setFloat64(i, v, endian === Endian.little); }
|
|
1291
|
+
getUint64(i: number, endian?: any): bigint {
|
|
1292
|
+
const lo = this._view.getUint32(i, endian === Endian.little);
|
|
1293
|
+
const hi = this._view.getUint32(i + 4, endian === Endian.little);
|
|
1294
|
+
return endian === Endian.little
|
|
1295
|
+
? BigInt(lo) | (BigInt(hi) << 32n)
|
|
1296
|
+
: (BigInt(lo) << 32n) | BigInt(hi);
|
|
1297
|
+
}
|
|
1298
|
+
setUint64(i: number, v: bigint, endian?: any): void {
|
|
1299
|
+
const lo = Number(v & 0xFFFFFFFFn);
|
|
1300
|
+
const hi = Number((v >> 32n) & 0xFFFFFFFFn);
|
|
1301
|
+
if (endian === Endian.little) {
|
|
1302
|
+
this._view.setUint32(i, lo, true);
|
|
1303
|
+
this._view.setUint32(i + 4, hi, true);
|
|
1304
|
+
} else {
|
|
1305
|
+
this._view.setUint32(i, hi, false);
|
|
1306
|
+
this._view.setUint32(i + 4, lo, false);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
getInt64(i: number, endian?: any): bigint {
|
|
1310
|
+
const unsigned = this.getUint64(i, endian);
|
|
1311
|
+
return unsigned >= 0x8000000000000000n ? unsigned - 0x10000000000000000n : unsigned;
|
|
1312
|
+
}
|
|
1313
|
+
setInt64(i: number, v: bigint, endian?: any): void {
|
|
1314
|
+
this.setUint64(i, v < 0n ? v + 0x10000000000000000n : v, endian);
|
|
1315
|
+
}
|
|
1316
|
+
get buffer(): { asUint8List: (start?: number, length?: number) => number[] } {
|
|
1317
|
+
const view = this._view;
|
|
1318
|
+
return {
|
|
1319
|
+
asUint8List: (start?: number, length?: number) => {
|
|
1320
|
+
const s = start ?? 0;
|
|
1321
|
+
const l = length ?? view.byteLength - s;
|
|
1322
|
+
return [...new Uint8Array(view.buffer, s, l)];
|
|
1323
|
+
},
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// ── dart:convert shims (utf8, jsonEncode, jsonDecode) ───────────────
|
|
1329
|
+
// ball_protobuf uses utf8.encode/decode for string↔bytes and
|
|
1330
|
+
// jsonEncode/jsonDecode for JSON serialization.
|
|
1331
|
+
const utf8 = {
|
|
1332
|
+
encode(s: string): number[] { return [...new TextEncoder().encode(s)]; },
|
|
1333
|
+
decode(bytes: any): string { return new TextDecoder().decode(new Uint8Array(bytes)); },
|
|
1334
|
+
};
|
|
1335
|
+
|
|
1336
|
+
function jsonEncode(obj: any): string { return JSON.stringify(obj); }
|
|
1337
|
+
function jsonDecode(s: string): any { return JSON.parse(s); }
|
|
473
1338
|
`;
|
|
474
1339
|
//# sourceMappingURL=preamble.js.map
|