@ball-lang/cli 1.24.0 → 1.25.0

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.
@@ -0,0 +1,1736 @@
1
+ // @ts-nocheck — auto-generated
2
+ // ── Ball runtime preamble (generated by @ball-lang/compiler) ────────
3
+
4
+ // Base class for all Ball runtime values.
5
+ export class BallValue {}
6
+
7
+ // A cast pattern (value as T) ASSERTS the runtime type — it throws on a type
8
+ // mismatch (Dart semantics), it does NOT refute / fall through. Conjoined into a
9
+ // switch-case condition by the compiler; returns true when the type check passed,
10
+ // else throws a catchable error. (conformance 302_cast_patterns)
11
+ export function ball_cast_assert(ok: boolean, t: string): boolean {
12
+ if (!ok) throw new Error('TypeError: type cast failed: not a ' + t);
13
+ return true;
14
+ }
15
+
16
+ // ── Ball container runtime types ────────────────────────────────────
17
+ //
18
+ // The self-hosted engine IR models class instances as 'BallObject extends
19
+ // BallMap'. The compiler treats maps/lists transparently (a Ball map is a
20
+ // plain JS object, a Ball list a plain JS array) and _asMap() returns an
21
+ // instance verbatim, reading its data through bracket access (obj of f)
22
+ // and the Object.prototype .entries / .keys / .length getters. To stay
23
+ // compatible we make BallObject a plain-object-like instance: the field data
24
+ // lives as OWN ENUMERABLE properties (so bracket access and .entries see it),
25
+ // while the class bookkeeping (typeName/fields/methods/superObject) is stored
26
+ // non-enumerably so it never leaks into .entries / .keys / .length.
27
+ //
28
+ // BallMap / BallList exist only so 'extends BallMap' resolves and any stray
29
+ // new BallMap(...) / new BallList(...) behaves like the transparent value.
30
+ export class BallMap extends BallValue {
31
+ constructor(entries?: any) {
32
+ super();
33
+ if (entries && typeof entries === 'object') {
34
+ if (entries instanceof Map) {
35
+ for (const [k, v] of entries) (this as any)[k] = v;
36
+ } else {
37
+ for (const k of Object.keys(entries)) (this as any)[k] = entries[k];
38
+ }
39
+ }
40
+ }
41
+ }
42
+
43
+ export class BallList extends Array {
44
+ constructor(items?: any) {
45
+ super();
46
+ if (Array.isArray(items)) for (const it of items) this.push(it);
47
+ }
48
+ }
49
+
50
+ export class BallObject extends BallMap {
51
+ constructor(arg0?: any, superObject?: any, fields?: any, methods?: any) {
52
+ super();
53
+ // Accept either the named-args object the encoder emits
54
+ // (new BallObject({typeName, superObject, fields, methods})) or the
55
+ // positional form, so the class works regardless of how it is invoked.
56
+ let typeName: any = arg0;
57
+ if (arg0 && typeof arg0 === 'object' && !Array.isArray(arg0) &&
58
+ ('typeName' in arg0 || 'fields' in arg0 || 'methods' in arg0 ||
59
+ 'superObject' in arg0)) {
60
+ typeName = arg0.typeName;
61
+ superObject = arg0.superObject;
62
+ fields = arg0.fields;
63
+ methods = arg0.methods;
64
+ }
65
+ const fieldMap = (fields && typeof fields === 'object') ? fields : {};
66
+ const methodMap = (methods && typeof methods === 'object') ? methods : {};
67
+ // Field data → own enumerable properties (visible to bracket access and
68
+ // the Object.prototype map getters).
69
+ for (const k of Object.keys(fieldMap)) (this as any)[k] = fieldMap[k];
70
+ // Class bookkeeping → own props the engine reads/writes by bracket name.
71
+ (this as any)['__type__'] = typeName ?? '';
72
+ (this as any)['__super__'] = superObject ?? null;
73
+ (this as any)['__fields__'] = fieldMap;
74
+ (this as any)['__methods__'] = methodMap;
75
+ // Mirror the Dart class fields too, but non-enumerably so they never show
76
+ // up as Ball fields in .entries / .keys / .length.
77
+ for (const [name, value] of [
78
+ ['typeName', typeName ?? ''], ['superObject', superObject ?? null],
79
+ ['fields', fieldMap], ['methods', methodMap],
80
+ ] as Array<[string, any]>) {
81
+ Object.defineProperty(this, name, {
82
+ value, writable: true, configurable: true, enumerable: false,
83
+ });
84
+ }
85
+ }
86
+
87
+ setField(name: any, value: any): void {
88
+ (this as any).fields[name] = value;
89
+ (this as any)[name] = value;
90
+ }
91
+ }
92
+ (globalThis as any).BallMap = BallMap;
93
+ (globalThis as any).BallList = BallList;
94
+ (globalThis as any).BallObject = BallObject;
95
+
96
+ // BallDouble wrapper — tracks that a number should print as a double
97
+ // (e.g. 42.0 not 42). Used by the compiled Dart engine's _toDouble.
98
+ export class BallDouble {
99
+ readonly value: number;
100
+ // Collapse nested wrapping down to the innermost raw number instead of
101
+ // storing a BallDouble that holds another BallDouble. The concrete source of
102
+ // nested wrapping was string_to_double's engine handler wrapping the result
103
+ // of the already-wrapping compiled parse path from issue 222; that redundant
104
+ // wrap was removed at its root in issue 237, so this guard is now purely
105
+ // defensive (verified: the full TS engine suite stays green without it). It is
106
+ // kept as a cheap, idempotent belt-and-suspenders against any other caller
107
+ // that might wrap an already-wrapped value: a doubly-wrapped BallDouble makes
108
+ // Number/valueOf coercion throw "Cannot convert object to primitive value".
109
+ // For a plain-number caller the instanceof check is a no-op.
110
+ constructor(v: number) { this.value = v instanceof BallDouble ? v.value : v; }
111
+ valueOf(): number { return this.value; }
112
+ get isNaN(): boolean { return Number.isNaN(this.value); }
113
+ get isFinite(): boolean { return Number.isFinite(this.value); }
114
+ get isInfinite(): boolean { return !Number.isFinite(this.value) && !Number.isNaN(this.value); }
115
+ get isNegative(): boolean { return this.value < 0 || (this.value === 0 && 1/this.value === -Infinity); }
116
+ // Mirrors the Number.prototype.remainder polyfill below (truncating
117
+ // remainder, matching JS % and Dart's num.remainder) — BallDouble wraps
118
+ // a JS number so it never inherits Number.prototype and needs its own.
119
+ remainder(other: any): number { return this.value % Number(other); }
120
+ toString(): string {
121
+ const v = this.value;
122
+ if (!isFinite(v)) return v.toString();
123
+ if (v === 0 && 1/v === -Infinity) return '-0.0';
124
+ if (Number.isInteger(v)) return v.toFixed(1);
125
+ return v.toString();
126
+ }
127
+ // Arithmetic: unwrap for operations
128
+ [Symbol.toPrimitive](hint: string): any {
129
+ if (hint === 'string') return this.toString();
130
+ return this.value;
131
+ }
132
+ }
133
+ (globalThis as any).BallDouble = BallDouble;
134
+
135
+ // Arithmetic helpers that propagate BallDouble through operations.
136
+ // If either operand is BallDouble, the result is BallDouble (preserving .0).
137
+ //
138
+ // Operator-overload dispatch checks for __op_X__ methods (TRAILING double
139
+ // underscore) — this MUST match the Dart encoder's canonical operator naming
140
+ // (_canonicalOperatorName in dart/encoder/lib/encoder.dart), which always
141
+ // emits a trailing __. A single-underscore lookup (__op_mul) never matches,
142
+ // so overloaded operators silently fall through to raw JS arithmetic (#205).
143
+ export function __ball_mul(a: any, b: any): any {
144
+ if (a != null && typeof a === 'object' && typeof a.__op_mul__ === 'function') return a.__op_mul__(b);
145
+ if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) * __to_bigint(b));
146
+ const av = a instanceof BallDouble ? a.value : a;
147
+ const bv = b instanceof BallDouble ? b.value : b;
148
+ const r = av * bv;
149
+ return (a instanceof BallDouble || b instanceof BallDouble) ? new BallDouble(r) : r;
150
+ }
151
+ export function __ball_add(a: any, b: any): any {
152
+ if (a != null && typeof a === 'object' && typeof a.__op_add__ === 'function') return a.__op_add__(b);
153
+ if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) + __to_bigint(b));
154
+ const av = a instanceof BallDouble ? a.value : a;
155
+ const bv = b instanceof BallDouble ? b.value : b;
156
+ const r = av + bv;
157
+ return (a instanceof BallDouble || b instanceof BallDouble) ? new BallDouble(r) : r;
158
+ }
159
+ export function __ball_sub(a: any, b: any): any {
160
+ if (a != null && typeof a === 'object' && typeof a.__op_sub__ === 'function') return a.__op_sub__(b);
161
+ if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) - __to_bigint(b));
162
+ const av = a instanceof BallDouble ? a.value : a;
163
+ const bv = b instanceof BallDouble ? b.value : b;
164
+ const r = av - bv;
165
+ return (a instanceof BallDouble || b instanceof BallDouble) ? new BallDouble(r) : r;
166
+ }
167
+
168
+ // Dart equality: NaN != NaN, BallDouble value comparison, null == undefined.
169
+ export function __ball_eq(a: any, b: any): boolean {
170
+ if (a != null && typeof a === 'object' && typeof a.__op_eq__ === 'function') return a.__op_eq__(b);
171
+ if (typeof a === 'bigint' || typeof b === 'bigint') {
172
+ if (typeof a === 'bigint' && typeof b === 'bigint') return a === b;
173
+ if (typeof a === 'bigint' && typeof b === 'number') return a === BigInt(b);
174
+ if (typeof a === 'number' && typeof b === 'bigint') return BigInt(a) === b;
175
+ return false;
176
+ }
177
+ if (a instanceof BallDouble || b instanceof BallDouble) {
178
+ const av = a instanceof BallDouble ? a.value : a;
179
+ const bv = b instanceof BallDouble ? b.value : b;
180
+ if (Number.isNaN(av) || Number.isNaN(bv)) return false;
181
+ return av === bv;
182
+ }
183
+ if (a == null && b == null) return true;
184
+ if (a == null || b == null) return a == b;
185
+ return a === b;
186
+ }
187
+
188
+ // Relational operator-overload dispatch (less-than/greater-than/etc.),
189
+ // matching the __op_add__-style convention above. Unlike arithmetic,
190
+ // relational comparisons had NO overload attempt at all before #205 — every
191
+ // overloaded Vec2 < x etc. compiled straight to raw JS comparison.
192
+ export function __ball_lt(a: any, b: any): any {
193
+ if (a != null && typeof a === 'object' && typeof a.__op_lt__ === 'function') return a.__op_lt__(b);
194
+ if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) < __to_bigint(b);
195
+ const av = a instanceof BallDouble ? a.value : a;
196
+ const bv = b instanceof BallDouble ? b.value : b;
197
+ return av < bv;
198
+ }
199
+ export function __ball_gt(a: any, b: any): any {
200
+ if (a != null && typeof a === 'object' && typeof a.__op_gt__ === 'function') return a.__op_gt__(b);
201
+ if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) > __to_bigint(b);
202
+ const av = a instanceof BallDouble ? a.value : a;
203
+ const bv = b instanceof BallDouble ? b.value : b;
204
+ return av > bv;
205
+ }
206
+ export function __ball_le(a: any, b: any): any {
207
+ if (a != null && typeof a === 'object' && typeof a.__op_le__ === 'function') return a.__op_le__(b);
208
+ if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) <= __to_bigint(b);
209
+ const av = a instanceof BallDouble ? a.value : a;
210
+ const bv = b instanceof BallDouble ? b.value : b;
211
+ return av <= bv;
212
+ }
213
+ export function __ball_ge(a: any, b: any): any {
214
+ if (a != null && typeof a === 'object' && typeof a.__op_ge__ === 'function') return a.__op_ge__(b);
215
+ if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) >= __to_bigint(b);
216
+ const av = a instanceof BallDouble ? a.value : a;
217
+ const bv = b instanceof BallDouble ? b.value : b;
218
+ return av >= bv;
219
+ }
220
+
221
+ export function __ball_to_string(v: any): string {
222
+ if (v === null || v === undefined) return 'null';
223
+ if (typeof v === 'bigint') return v.toString();
224
+ if (typeof v === 'boolean') return v ? 'true' : 'false';
225
+ if (v instanceof BallDouble) return v.toString();
226
+ if (typeof v === 'number') {
227
+ if (!isFinite(v) || Number.isNaN(v)) return v.toString();
228
+ if (v === 0 && 1/v === -Infinity) return '-0.0';
229
+ if (Number.isInteger(v)) return v.toString();
230
+ const s = v.toString();
231
+ return s.includes('.') || s.includes('e') ? s : s + '.0';
232
+ }
233
+ if (typeof v === 'string') return v;
234
+ if (Array.isArray(v)) {
235
+ return '[' + v.map(__ball_to_string).join(', ') + ']';
236
+ }
237
+ if (v instanceof Map) {
238
+ const parts: string[] = [];
239
+ // v.entries() as a method call would hit the Dart-property-style
240
+ // getter of the same name (installed further down in this file) and
241
+ // try to invoke its return value -- an array -- as a function.
242
+ // _nativeMapEntries is the real, un-shadowed method (issue #259).
243
+ for (const [k, val] of _nativeMapEntries.call(v)) {
244
+ parts.push(__ball_to_string(k) + ': ' + __ball_to_string(val));
245
+ }
246
+ return '{' + parts.join(', ') + '}';
247
+ }
248
+ if (v instanceof Set) {
249
+ // A Set is a plain object from typeof's perspective (falls through to
250
+ // the generic branch below, which reads Object.keys — always [] for a
251
+ // Set's internal slots), so every Set printed as the empty "{}" no
252
+ // matter its contents until this dedicated case was added (#219).
253
+ return '{' + [...v].map(__ball_to_string).join(', ') + '}';
254
+ }
255
+ if (typeof v === 'object' && !Array.isArray(v)) {
256
+ // StringBuffer-like objects
257
+ if (v['__buffer__'] && Array.isArray(v['__buffer__'])) {
258
+ return v['__buffer__'].join('');
259
+ }
260
+ // Check for custom toString method on the instance (not Object.prototype).
261
+ if (v.toString !== Object.prototype.toString && typeof v.toString === 'function') {
262
+ return v.toString();
263
+ }
264
+ // Dart Map-like object: format as {key: value, ...}
265
+ const keys = Object.keys(v).filter((k: string) => !k.startsWith('__'));
266
+ if (keys.length > 0) {
267
+ return '{' + keys.map((k: string) => __ball_to_string(k) + ': ' + __ball_to_string(v[k])).join(', ') + '}';
268
+ }
269
+ return '{}';
270
+ }
271
+ return String(v);
272
+ }
273
+
274
+ export function __ball_parse_int(s: string): number {
275
+ const trimmed = s.trim();
276
+ if (!/^-?\d+$/.test(trimmed)) {
277
+ throw new Error('FormatException: ' + s);
278
+ }
279
+ return parseInt(trimmed, 10);
280
+ }
281
+
282
+ // Dart-style int conversion that preserves int64 precision. JS numbers lose
283
+ // precision above 2^53, so integer literals encoded as decimal strings (the
284
+ // JSON proto3 representation of int64) would round. When the string magnitude
285
+ // exceeds Number.MAX_SAFE_INTEGER we return a BigInt to keep the exact value;
286
+ // otherwise we keep a plain number so the common arithmetic path is unchanged.
287
+ export function __ball_to_int(v: any): any {
288
+ if (typeof v === 'bigint') return v;
289
+ if (typeof v === 'string') {
290
+ if (/^-?\d+$/.test(v)) {
291
+ const b = BigInt(v);
292
+ if (b > 9007199254740991n || b < -9007199254740991n) return b;
293
+ return Number(b);
294
+ }
295
+ return Math.trunc(Number(v)) || 0;
296
+ }
297
+ const n = (v instanceof BallDouble) ? v.value : v;
298
+ const t = Math.trunc(n) || 0;
299
+ if (t >= 9223372036854775808) return __I64_MAX;
300
+ if (t <= -9223372036854775808) return __I64_MIN;
301
+ if (t > 9007199254740991 || t < -9007199254740991) {
302
+ try { return __i64_wrap(BigInt(Math.round(t))); } catch {}
303
+ }
304
+ return t;
305
+ }
306
+
307
+ // Returns a BallDouble (not a bare number) so a whole-valued result (e.g.
308
+ // double.parse('7.0')) still prints "7.0", not "7" — JS numbers erase the
309
+ // int/double distinction that the wrapper exists to preserve (#67/#222).
310
+ export function __ball_parse_double(s: string): BallDouble {
311
+ const n = parseFloat(s);
312
+ if (Number.isNaN(n)) throw new Error('FormatException: ' + s);
313
+ return new BallDouble(n);
314
+ }
315
+
316
+ export function __ball_double_to_string(n: number): string {
317
+ if (Number.isInteger(n)) return n.toFixed(1);
318
+ return n.toString();
319
+ }
320
+
321
+ // num.toStringAsFixed(digits). JS Number.prototype.toFixed drops the sign of
322
+ // -0 (returns "0.00" not "-0.00"); Dart's toStringAsFixed keeps it, matching
323
+ // the -0 handling __ball_to_string/BallDouble.toString already do.
324
+ export function __ball_to_fixed(v: any, digits: any): string {
325
+ const n = Number(v);
326
+ const s = n.toFixed(digits);
327
+ if (n === 0 && 1 / n === -Infinity && !s.startsWith('-')) return '-' + s;
328
+ return s;
329
+ }
330
+
331
+ // Polymorphic concat / merge used for std.list_concat. The encoder emits
332
+ // list_concat both for Dart list concat AND for Map.addAll(...) (encoded as
333
+ // m = list_concat(m, other)). Arrays concat positionally; plain objects
334
+ // (Ball maps) merge by key with the right side winning (so child class
335
+ // methods override parent methods).
336
+ export function __ball_concat(a: any, b: any): any {
337
+ const aIsArr = Array.isArray(a);
338
+ const bIsArr = Array.isArray(b);
339
+ if (aIsArr || bIsArr) {
340
+ const al = aIsArr ? a : (a == null ? [] : [a]);
341
+ const bl = bIsArr ? b : (b == null ? [] : [b]);
342
+ return [...al, ...bl];
343
+ }
344
+ if ((a && typeof a === 'object') || (b && typeof b === 'object')) {
345
+ return Object.assign({}, a ?? {}, b ?? {});
346
+ }
347
+ return [a, b];
348
+ }
349
+
350
+ // In-place collection append: mutates target by appending all elements.
351
+ // For arrays: pushes elements (Dart List.addAll semantics).
352
+ // For objects: merges keys (Dart Map.addAll semantics).
353
+ // Preserves reference identity so callers sharing the same collection see changes.
354
+ export function __ball_push_all(target: any, items: any): void {
355
+ if (Array.isArray(target)) {
356
+ if (Array.isArray(items)) {
357
+ for (let i = 0; i < items.length; i++) target.push(items[i]);
358
+ } else if (items != null) {
359
+ target.push(items);
360
+ }
361
+ } else if (target && typeof target === 'object') {
362
+ if (items && typeof items === 'object' && !Array.isArray(items)) {
363
+ for (const k of Object.keys(items)) target[k] = items[k];
364
+ }
365
+ }
366
+ }
367
+
368
+ // ── BigInt / signed-64-bit integer support ──────────────────────
369
+ // Dart int is signed 64-bit; JS Number loses precision above 2^53.
370
+ // Arithmetic on BigInt values wraps to the signed 64-bit range and
371
+ // demotes back to Number when the result fits in MAX_SAFE_INTEGER.
372
+ export const __I64_MAX = 9223372036854775807n;
373
+ export const __I64_MIN = -9223372036854775808n;
374
+ export function __i64_wrap(v: bigint): any {
375
+ // Two's-complement wrap to the signed 64-bit range — BigInt.asIntN(64, v)
376
+ // is the idiomatic builtin for exactly this (equivalent to the old manual
377
+ // modulo-then-resign, verified against it across boundary/overflow cases).
378
+ v = BigInt.asIntN(64, v);
379
+ if (v >= -9007199254740991n && v <= 9007199254740991n) return Number(v);
380
+ return v;
381
+ }
382
+ export function __to_bigint(v: any): bigint {
383
+ if (typeof v === 'bigint') return v;
384
+ // Matches the reference Dart engine's _toInt (engine_std.dart), which
385
+ // falls through to 0 for anything that isn't an int/BallInt/double/
386
+ // BallDouble/String/bool -- including null. NaN is deliberately NOT
387
+ // special-cased here: Dart's double.toInt() throws on NaN (via
388
+ // _ballDoubleToInt64), and BigInt(NaN) already throws for the same
389
+ // reason (RangeError: not an integer), so that path already fails loud
390
+ // consistently with the reference engine without any extra handling.
391
+ if (v === null || v === undefined) return 0n;
392
+ if (v instanceof BallDouble) return BigInt(Math.trunc(v.value));
393
+ return BigInt(v);
394
+ }
395
+ // Fast-path guard: true when v is a plain (non-bigint, non-BallDouble)
396
+ // integer within the signed 32-bit range. AND/OR/XOR/NOT never grow a
397
+ // result past its operands' bit width, so when both operands fit in 32
398
+ // bits, JS's native 32-bit bitwise operators give a result numerically
399
+ // IDENTICAL to the full 64-bit BigInt path (sign-extending a 32-bit value
400
+ // to 64 bits before AND/OR/XOR/NOT never changes the low 32 result bits,
401
+ // and — verified across the full boundary range — never changes whether
402
+ // the high bits are the correct sign-extension of them either). Left/right
403
+ // shift are NOT given this fast path: shifting can grow a result past 32
404
+ // bits even when the input operand fits (e.g. large_int << 40), so their
405
+ // overflow behavior isn't safely 32-bit-local the way AND/OR/XOR/NOT is.
406
+ export function __fits32(v: any): boolean {
407
+ return typeof v === 'number' && Number.isInteger(v) && v >= -2147483648 && v <= 2147483647;
408
+ }
409
+ export function __ball_bitand(a: any, b: any): any {
410
+ if (__fits32(a) && __fits32(b)) return a & b;
411
+ return __i64_wrap(__to_bigint(a) & __to_bigint(b));
412
+ }
413
+ export function __ball_bitor(a: any, b: any): any {
414
+ if (__fits32(a) && __fits32(b)) return a | b;
415
+ return __i64_wrap(__to_bigint(a) | __to_bigint(b));
416
+ }
417
+ export function __ball_bitxor(a: any, b: any): any {
418
+ if (__fits32(a) && __fits32(b)) return a ^ b;
419
+ return __i64_wrap(__to_bigint(a) ^ __to_bigint(b));
420
+ }
421
+ export function __ball_bitnot(a: any): any {
422
+ if (__fits32(a)) return ~a;
423
+ return __i64_wrap(~__to_bigint(a));
424
+ }
425
+ export function __ball_shl(a: any, b: any): any { return __i64_wrap(__to_bigint(a) << __to_bigint(b)); }
426
+ export function __ball_shr(a: any, b: any): any { return __i64_wrap(__to_bigint(a) >> __to_bigint(b)); }
427
+ // Unsigned/logical shift: reinterpret a as an unsigned 64-bit value (add
428
+ // 2^64 if negative) before shifting, so zeros fill from the left instead of
429
+ // the sign bit — unlike >>> on raw JS numbers, which is only 32-bit.
430
+ export function __ball_ushr(a: any, b: any): any {
431
+ const unsigned = BigInt.asUintN(64, __to_bigint(a));
432
+ return __i64_wrap(unsigned >> __to_bigint(b));
433
+ }
434
+ // json_encode (dart:convert's jsonEncode) on a bigint-range int64 must not
435
+ // crash -- JSON.stringify throws "Do not know how to serialize a BigInt"
436
+ // without a toJSON. This is NOT proto3-JSON (which quotes int64 as a
437
+ // string) -- Ball's dart:convert-style jsonEncode matches Dart's own
438
+ // dart:convert (a bare, unquoted JSON number) and the C++ self-host's
439
+ // _ball_json_encode (std::to_string(int64_t), also unquoted). JSON.rawJSON
440
+ // embeds the exact decimal digits as a raw number token, avoiding the
441
+ // precision loss Number(this) would introduce for values past 2^53.
442
+ (BigInt.prototype as any).toJSON = function (this: bigint) {
443
+ return (JSON as any).rawJSON(this.toString());
444
+ };
445
+ export function __ball_negate(a: any): any {
446
+ if (typeof a === 'bigint') return __i64_wrap(-a);
447
+ if (a instanceof BallDouble) return new BallDouble(-a.value);
448
+ return -a;
449
+ }
450
+ export function __ball_divide(a: any, b: any): any {
451
+ if (typeof a === 'bigint' || typeof b === 'bigint') {
452
+ const ba = __to_bigint(a), bb = __to_bigint(b);
453
+ const r = ba / bb;
454
+ return __i64_wrap(r);
455
+ }
456
+ return Math.trunc(a / b);
457
+ }
458
+ export function __ball_math_abs(a: any): any {
459
+ if (typeof a === 'bigint') {
460
+ const neg = -a;
461
+ return __i64_wrap(neg < 0n ? a : neg);
462
+ }
463
+ return Math.abs(a);
464
+ }
465
+ // Greatest common divisor (Dart's int.gcd). Preserves BigInt (i64) inputs so
466
+ // integer identities round-trip; falls back to Number arithmetic otherwise.
467
+ export function __ball_math_gcd(a: any, b: any): any {
468
+ if (typeof a === 'bigint' || typeof b === 'bigint') {
469
+ let x = __to_bigint(a); x = x < 0n ? -x : x;
470
+ let y = __to_bigint(b); y = y < 0n ? -y : y;
471
+ while (y) { const t = y; y = x % y; x = t; }
472
+ return __i64_wrap(x);
473
+ }
474
+ let x = Math.abs(Number(a)), y = Math.abs(Number(b));
475
+ while (y) { const t = y; y = x % y; x = t; }
476
+ return x;
477
+ }
478
+ // Least common multiple, derived from gcd. lcm(0, n) == lcm(n, 0) == 0.
479
+ export function __ball_math_lcm(a: any, b: any): any {
480
+ if (typeof a === 'bigint' || typeof b === 'bigint') {
481
+ const x = __to_bigint(a), y = __to_bigint(b);
482
+ if (x === 0n || y === 0n) return __i64_wrap(0n);
483
+ const g = __to_bigint(__ball_math_gcd(x, y));
484
+ const r = (x / g) * y;
485
+ return __i64_wrap(r < 0n ? -r : r);
486
+ }
487
+ const x = Number(a), y = Number(b);
488
+ if (x === 0 || y === 0) return 0;
489
+ const g = Number(__ball_math_gcd(x, y));
490
+ return Math.abs((x / g) * y);
491
+ }
492
+
493
+ // Dart-style Euclidean modulo: result is always non-negative.
494
+ // JS % is remainder (can be negative), Dart % is Euclidean modulo.
495
+ export function __dart_mod(a: any, b: any): any {
496
+ if (typeof a === 'bigint' || typeof b === 'bigint') {
497
+ const ba = __to_bigint(a), bb = __to_bigint(b);
498
+ const r = ba % bb;
499
+ return __i64_wrap(r < 0n ? r + (bb < 0n ? -bb : bb) : r);
500
+ }
501
+ const r = a % b;
502
+ return r < 0 ? r + (b < 0 ? -b : b) : r;
503
+ }
504
+
505
+ // Active exception for rethrow. Catch bodies shadow with a local.
506
+ export let __ball_active_error: any = undefined;
507
+
508
+ // Dart-style index access. Dart's List '[]' operator throws RangeError on
509
+ // out-of-bounds access, whereas JS array indexing silently returns undefined.
510
+ // To make 'on RangeError' catch clauses behave like Dart we bounds-check list
511
+ // (array) access here and throw a RangeError-shaped exception. Maps, strings
512
+ // and objects keep their JS semantics (no throw) — Dart Map '[]' returns null
513
+ // for absent keys, and String '[]' is handled by callers.
514
+ export function __ball_index(target: any, idx: any): any {
515
+ if (Array.isArray(target) && typeof idx === 'number' && Number.isInteger(idx)) {
516
+ if (idx < 0 || idx >= target.length) {
517
+ throw {
518
+ __type__: 'RangeError',
519
+ message: 'RangeError (index): Invalid value: ' +
520
+ (target.length === 0
521
+ ? 'Valid value range is empty: ' + idx
522
+ : 'Not in inclusive range 0..' + (target.length - 1) + ': ' + idx),
523
+ index: idx,
524
+ };
525
+ }
526
+ return target[idx];
527
+ }
528
+ return target[idx];
529
+ }
530
+
531
+ // Dart type shims — provide static methods for Dart built-in types
532
+ // that don't exist in JS (int, double, num, bool).
533
+ export const int = {
534
+ parse: (s: any) => { const n = parseInt(String(s), 10); if (isNaN(n)) throw new Error('FormatException: ' + s); return n; },
535
+ tryParse: (s: any) => { const n = parseInt(String(s), 10); return isNaN(n) ? null : n; },
536
+ };
537
+ export const double = {
538
+ parse: (s: any) => { const n = parseFloat(String(s)); if (isNaN(n)) throw new Error('FormatException: ' + s); return n; },
539
+ tryParse: (s: any) => { const n = parseFloat(String(s)); return isNaN(n) ? null : n; },
540
+ infinity: Infinity,
541
+ nan: NaN,
542
+ negativeInfinity: -Infinity,
543
+ };
544
+ export const num = {
545
+ parse: (s: any) => { const n = Number(s); if (isNaN(n)) throw new Error('FormatException: ' + s); return n; },
546
+ tryParse: (s: any) => { const n = Number(s); return isNaN(n) ? null : n; },
547
+ };
548
+ export const bool = {
549
+ parse: (s: any) => { if (s === 'true') return true; if (s === 'false') return false; throw new Error('FormatException: ' + s); },
550
+ tryParse: (s: any) => { if (s === 'true') return true; if (s === 'false') return false; return null; },
551
+ };
552
+
553
+ // Sentinel for "not yet initialized" — used by the Dart engine for
554
+ // late-initialized variables and block-scoped flow tracking.
555
+ export const __no_init__: unique symbol = Symbol('__no_init__');
556
+
557
+ // Null-aware spread source normalizer (the ...? operator). Returns an
558
+ // iterable for the spread loop, mapping null / undefined / the __no_init__
559
+ // sentinel (an uninitialized nullable, e.g. List<int>? n;) to an empty list
560
+ // — matching Dart's ...?n which contributes nothing when the operand is null.
561
+ export function __ball_spread_iter(v: any): any {
562
+ if (v == null || v === __no_init__) return [];
563
+ return v;
564
+ }
565
+
566
+ // Dart type constructor shims — List, Map, etc.
567
+ export const List = {
568
+ filled: (count: any, value: any) => Array(count).fill(value),
569
+ generate: (count: any, generator: any) => {
570
+ const r: any[] = [];
571
+ for (let i = 0; i < count; i++) r.push(generator(i));
572
+ return r;
573
+ },
574
+ from: (iter: any) => Array.isArray(iter) ? [...iter] : [...iter],
575
+ of: (iter: any) => Array.isArray(iter) ? [...iter] : [...iter],
576
+ unmodifiable: (iter: any) => Object.freeze(Array.isArray(iter) ? [...iter] : [...iter]),
577
+ empty: (opts?: any) => [],
578
+ castFrom: (source: any) => Array.isArray(source) ? [...source] : [],
579
+ };
580
+
581
+ // Set.unmodifiable
582
+ export const _nativeSet = Set;
583
+ (Set as any).unmodifiable = (iter: any) => {
584
+ const s = new _nativeSet(iter);
585
+ return Object.freeze(s);
586
+ };
587
+ (Set as any).from = (iter: any) => new _nativeSet(iter);
588
+ (Set as any).of = (iter: any) => new _nativeSet(iter);
589
+ // Ball encoder sometimes uses set_create for lists, then list_push on them.
590
+ // Bridge the gap with push/indexOf/length on Set.
591
+ if (!(Set.prototype as any).push) (Set.prototype as any).push = function(v: any) { this.add(v); return this.size; };
592
+ Object.defineProperty(Set.prototype, 'length', { configurable: true, get() { return this.size; } });
593
+ Object.defineProperty(Set.prototype, 'isEmpty', { configurable: true, get() { return this.size === 0; } });
594
+ Object.defineProperty(Set.prototype, 'isNotEmpty', { configurable: true, get() { return this.size !== 0; } });
595
+
596
+ // Patch: scope _bindings must use null-prototype objects to avoid
597
+ // Object.prototype getters (entries, keys, values, length) polluting
598
+ // the "in" operator used by scope.lookup/has/set.
599
+ export const _origScopeInit = { patched: false };
600
+ export function _patchScopeBindings(scope: any) {
601
+ if (!scope || _origScopeInit.patched) return;
602
+ const ScopeClass = scope.constructor;
603
+ if (!ScopeClass) return;
604
+ const origCtor = ScopeClass;
605
+ const origBind = ScopeClass.prototype.bind;
606
+ // Override bind to lazily convert _bindings to null-proto object
607
+ ScopeClass.prototype.bind = function(name: any, value: any) {
608
+ if (Object.getPrototypeOf(this._bindings) !== null) {
609
+ const entries = Object.entries(this._bindings);
610
+ this._bindings = Object.create(null);
611
+ for (const [k, v] of entries) this._bindings[k] = v;
612
+ }
613
+ return (this._bindings[name] = value);
614
+ };
615
+ // Also patch child() to create null-proto bindings
616
+ const origChild = ScopeClass.prototype.child;
617
+ if (origChild) {
618
+ ScopeClass.prototype.child = function() {
619
+ const c = origChild.call(this);
620
+ if (Object.getPrototypeOf(c._bindings) !== null) {
621
+ c._bindings = Object.create(null);
622
+ }
623
+ return c;
624
+ };
625
+ }
626
+ _origScopeInit.patched = true;
627
+ }
628
+
629
+ // Proto has* functions as global helpers (encoder routes method calls through ball_proto)
630
+ // Generic has* helper — returns true if obj[field] is present and non-null
631
+ export function _has(obj: any, field: string): boolean { return obj?.[field] !== undefined && obj?.[field] !== null; }
632
+ export function hasMetadata(obj: any): boolean { return _has(obj, 'metadata'); }
633
+ export function hasBody(obj: any): boolean { return _has(obj, 'body'); }
634
+ export function hasInput(obj: any): boolean { return _has(obj, 'input'); }
635
+ export function hasDescriptor(obj: any): boolean { return _has(obj, 'descriptor'); }
636
+ // ModuleImport.source oneof (issue #364 — cli_core.dart's _importSource
637
+ // reads these via hasHttp()/hasFile()/hasGit()/hasRegistry()/hasInline()
638
+ // instead of whichSource(), since the self-hosted engine represents proto
639
+ // oneof-case enums as maps and can't self-host a whichSource() ==
640
+ // ModuleImport_Source.x comparison — see cli_core.dart's _importSource doc).
641
+ export function hasHttp(obj: any): boolean { return _has(obj, 'http'); }
642
+ export function hasFile(obj: any): boolean { return _has(obj, 'file'); }
643
+ export function hasGit(obj: any): boolean { return _has(obj, 'git'); }
644
+ export function hasRegistry(obj: any): boolean { return _has(obj, 'registry'); }
645
+ export function hasInline(obj: any): boolean { return _has(obj, 'inline'); }
646
+ export function hasStringValue(obj: any): boolean { return _has(obj, 'stringValue'); }
647
+ export function hasBoolValue(obj: any): boolean { return _has(obj, 'boolValue'); }
648
+ export function hasNumberValue(obj: any): boolean { return _has(obj, 'numberValue'); }
649
+ export function hasResult(obj: any): boolean { return _has(obj, 'result'); }
650
+ export function hasCall(obj: any): boolean { return _has(obj, 'call'); }
651
+ export function hasListValue(obj: any): boolean { return _has(obj, 'listValue'); }
652
+ export function hasNullValue(obj: any): boolean { return _has(obj, 'nullValue'); }
653
+ export function hasStructValue(obj: any): boolean { return _has(obj, 'structValue'); }
654
+ export function hasMatch(obj: any): boolean { return _has(obj, 'match'); }
655
+ export function hasXxx(obj: any): boolean { return false; }
656
+ export function whichXxx(obj: any): string { return 'notSet'; }
657
+ // whichExpr/whichValue/whichStmt/whichKind sit on the hottest path of the
658
+ // compiled engine (whichExpr alone runs up to 8x per _evalExpression). The
659
+ // previous 'typeof obj.whichXxx === "function"' probe always walked the
660
+ // prototype chain to the Object.prototype shim installed by installProtoShims
661
+ // (true for EVERY plain object) and then *invoked* it — a prototype walk + a
662
+ // megamorphic keyed-load loop per call, even though the compiled engine's AST
663
+ // nodes never carry an own whichXxx. We gate the method probe behind an
664
+ // own-property check (so plain nodes skip the prototype walk entirely and use
665
+ // the inline discriminator) while still honoring hand-rolled wrapper objects —
666
+ // notably the metadata wrapValue Value wrappers, whose own getters
667
+ // (.stringValue etc.) are always-defined, so their own whichXxx() must win
668
+ // over the inline field probes. Hence the own-method check stays FIRST.
669
+ export function whichExpr(obj: any): string {
670
+ if (!obj) return 'notSet';
671
+ if (Object.prototype.hasOwnProperty.call(obj, 'whichExpr') && typeof obj.whichExpr === 'function') return obj.whichExpr();
672
+ if (obj.call) return 'call'; if (obj.literal) return 'literal';
673
+ if (obj.reference) return 'reference'; if (obj.fieldAccess) return 'fieldAccess';
674
+ if (obj.messageCreation) return 'messageCreation'; if (obj.block) return 'block';
675
+ if (obj.lambda) return 'lambda'; return 'notSet';
676
+ }
677
+ export function whichValue(obj: any): string {
678
+ if (!obj) return 'notSet';
679
+ if (Object.prototype.hasOwnProperty.call(obj, 'whichValue') && typeof obj.whichValue === 'function') return obj.whichValue();
680
+ if (obj.intValue !== undefined) return 'intValue'; if (obj.doubleValue !== undefined) return 'doubleValue';
681
+ if (obj.stringValue !== undefined) return 'stringValue'; if (obj.boolValue !== undefined) return 'boolValue';
682
+ if (obj.listValue) return 'listValue'; if (obj.bytesValue !== undefined) return 'bytesValue';
683
+ return 'notSet';
684
+ }
685
+ export function whichStmt(obj: any): string {
686
+ if (!obj) return 'notSet';
687
+ if (Object.prototype.hasOwnProperty.call(obj, 'whichStmt') && typeof obj.whichStmt === 'function') return obj.whichStmt();
688
+ if (obj.let) return 'let'; if (obj.expression) return 'expression'; return 'notSet';
689
+ }
690
+ export function whichKind(obj: any): string {
691
+ if (!obj) return 'notSet';
692
+ if (Object.prototype.hasOwnProperty.call(obj, 'whichKind') && typeof obj.whichKind === 'function') return obj.whichKind();
693
+ if (obj.nullValue !== undefined) return 'nullValue'; if (obj.numberValue !== undefined) return 'numberValue';
694
+ if (obj.stringValue !== undefined) return 'stringValue'; if (obj.boolValue !== undefined) return 'boolValue';
695
+ if (obj.structValue) return 'structValue'; if (obj.listValue) return 'listValue';
696
+ return 'notSet';
697
+ }
698
+ export function whichSource(obj: any): string {
699
+ if (!obj) return 'notSet';
700
+ if (obj.path) return 'path'; if (obj.url) return 'url'; if (obj.inline) return 'inline';
701
+ return 'notSet';
702
+ }
703
+
704
+ // Identical function (Dart identical())
705
+ export function identical(a: any, b: any): boolean { return a === b; }
706
+
707
+ // Function.apply shim (Dart Function.apply)
708
+ (Function as any).apply = function(fn: any, positionalArgs: any, namedArgs?: any) {
709
+ if (typeof fn !== 'function') return undefined;
710
+ const args = positionalArgs == null ? [] : (Array.isArray(positionalArgs) ? positionalArgs : [positionalArgs]);
711
+ return fn(...args);
712
+ };
713
+
714
+ // Dart cascade helper — evaluates target, applies ops, returns target.
715
+ export function __ball_cascade(target: any, ops: any[]): any {
716
+ for (const op of ops) {
717
+ if (typeof op === 'function') op(target);
718
+ }
719
+ return target;
720
+ }
721
+
722
+ // ── Dart \u2192 JS method-name polyfills ────────────────────────────────
723
+ //
724
+ // Idempotent: guarded so multiple preamble inclusions don't double-install.
725
+
726
+ // Native Map.prototype.entries/keys/values, captured BEFORE the
727
+ // installBallPolyfills IIFE below shadows them with Dart-property-style
728
+ // getters of the same name. Top-level (not IIFE-scoped) so every internal
729
+ // call site that needs the REAL iterator method -- not the property-style
730
+ // getter -- can reach it: the getters themselves (which must call the
731
+ // original to avoid recursing into themselves), __ball_to_string's Map
732
+ // printer, the Map-like constructor copy sites, and the map_keys/values/
733
+ // entries base-function helpers (issue #259 -- calling .entries()/etc.
734
+ // as a METHOD on a real Map after the shadow is installed throws, since
735
+ // the getter's return value -- an array -- isn't itself callable).
736
+ export const _nativeMapEntries = Map.prototype.entries;
737
+ export const _nativeMapKeys = Map.prototype.keys;
738
+ export const _nativeMapValues = Map.prototype.values;
739
+
740
+ (function installBallPolyfills() {
741
+ const mp: any = Map.prototype;
742
+ if (!mp.containsKey) mp.containsKey = function (k: any) { return this.has(k); };
743
+ if (!mp.putIfAbsent) {
744
+ mp.putIfAbsent = function (k: any, supplier: any) {
745
+ if (!this.has(k)) this.set(k, supplier());
746
+ return this.get(k);
747
+ };
748
+ }
749
+ if (!mp.addAll) {
750
+ mp.addAll = function (other: any) {
751
+ if (other instanceof Map) {
752
+ // _nativeMapEntries, not other.entries() -- see __ball_to_string's
753
+ // Map printer above for why (issue #259).
754
+ for (const [k, v] of _nativeMapEntries.call(other)) this.set(k, v);
755
+ } else if (other && typeof other === 'object') {
756
+ for (const k of Object.keys(other)) this.set(k, other[k]);
757
+ }
758
+ };
759
+ }
760
+ Object.defineProperty(mp, 'isEmpty', {
761
+ configurable: true, get() { return this.size === 0; },
762
+ });
763
+ Object.defineProperty(mp, 'isNotEmpty', {
764
+ configurable: true, get() { return this.size !== 0; },
765
+ });
766
+
767
+ const ap: any = Array.prototype;
768
+ if (!ap.add) ap.add = function (v: any) { this.push(v); };
769
+ if (!ap.addAll) ap.addAll = function (iter: any) {
770
+ for (const v of iter) this.push(v);
771
+ };
772
+ if (!ap.removeLast) ap.removeLast = function () { return this.pop(); };
773
+ if (!ap.removeAt) ap.removeAt = function (i: any) { return this.splice(i, 1)[0]; };
774
+ if (!ap.insert) ap.insert = function (i: any, v: any) { this.splice(i, 0, v); };
775
+ if (!ap.setAll) ap.setAll = function (idx: number, values: any[]) { for (let i = 0; i < values.length; i++) this[idx + i] = values[i]; };
776
+ if (!ap.where) ap.where = Array.prototype.filter;
777
+ if (!ap.toList) ap.toList = function () { return this.slice(); };
778
+ if (!ap.toSet) ap.toSet = function () { return new Set(this); };
779
+ if (!ap.contains) ap.contains = function (v: any) { return this.indexOf(v) >= 0; };
780
+ if (!ap.sublist) ap.sublist = function (start: any, end?: any) { return this.slice(start, end); };
781
+ if (!ap.asMap) ap.asMap = function () {
782
+ const m: any = {};
783
+ for (let i = 0; i < this.length; i++) m[i] = this[i];
784
+ return m;
785
+ };
786
+ if (!ap.expand) ap.expand = function (fn: any) { return this.flatMap(fn); };
787
+ if (!ap.take) ap.take = function (n: any) { return this.slice(0, n); };
788
+ if (!ap.skip) ap.skip = function (n: any) { return this.slice(n); };
789
+ if (!ap.any) ap.any = function (fn: any) { return this.some(fn); };
790
+ if (!ap.fold) ap.fold = function (init: any, fn: any) { return this.reduce(fn, init); };
791
+ if (!ap.followedBy) ap.followedBy = function (other: any) { return [...this, ...other]; };
792
+ if (!ap.getRange) ap.getRange = function (start: any, end: any) { return this.slice(start, end); };
793
+ if (!ap.fillRange) ap.fillRange = function (start: any, end: any, fill: any) {
794
+ for (let i = start; i < end; i++) this[i] = fill;
795
+ };
796
+ if (!ap.setRange) ap.setRange = function (start: any, end: any, iterable: any, skipCount?: any) {
797
+ const src = Array.isArray(iterable) ? iterable : [...iterable];
798
+ const skip = skipCount ?? 0;
799
+ for (let i = start; i < end; i++) this[i] = src[i - start + skip];
800
+ };
801
+
802
+ // Dart Set polyfills — Set.contains → Set.has, etc.
803
+ const setp: any = Set.prototype;
804
+ if (!setp.contains) setp.contains = function (v: any) { return this.has(v); };
805
+ if (!setp.includes) setp.includes = function (v: any) { return this.has(v); };
806
+ if (!setp.toList) setp.toList = function () { return [...this]; };
807
+ if (!setp.add) { /* Set already has .add */ }
808
+ if (!setp.remove) setp.remove = function (v: any) { return this.delete(v); };
809
+ Object.defineProperty(ap, 'isEmpty', {
810
+ configurable: true, get() { return this.length === 0; },
811
+ });
812
+ Object.defineProperty(ap, 'isNotEmpty', {
813
+ configurable: true, get() { return this.length !== 0; },
814
+ });
815
+ Object.defineProperty(ap, 'first', {
816
+ configurable: true, get() { return this[0]; },
817
+ });
818
+ Object.defineProperty(ap, 'last', {
819
+ configurable: true, get() { return this[this.length - 1]; },
820
+ });
821
+
822
+ const sp: any = String.prototype;
823
+ Object.defineProperty(sp, 'isEmpty', {
824
+ configurable: true, get() { return this.length === 0; },
825
+ });
826
+ Object.defineProperty(sp, 'isNotEmpty', {
827
+ configurable: true, get() { return this.length !== 0; },
828
+ });
829
+ // Note: undefined/null safety for .isEmpty/.isNotEmpty is handled in the
830
+ // generated code via optional-chaining (?.isEmpty) patterns and protoWrap;
831
+ // properties cannot be installed on undefined/null directly.
832
+ // Dart String methods not on JS String.
833
+ if (!sp.contains) sp.contains = function (s: any) { return this.includes(s); };
834
+ if (!sp.replaceFirst) sp.replaceFirst = function (from: any, to: any) {
835
+ return this.replace(from instanceof RegExp ? from : String(from), to);
836
+ };
837
+ if (!sp.codeUnitAt) sp.codeUnitAt = function (i: any) { return this.charCodeAt(i); };
838
+ if (!sp.compareTo) sp.compareTo = function (other: any) {
839
+ return this < other ? -1 : this > other ? 1 : 0;
840
+ };
841
+ if (!sp.allMatches) sp.allMatches = function (pattern: any, start: any) {
842
+ const s = typeof start === 'number' ? this.substring(start) : this;
843
+ if (typeof pattern === 'string') {
844
+ return Array.from(s.matchAll(new RegExp(pattern, 'g')));
845
+ }
846
+ const flags = pattern.flags.includes('g') ? pattern.flags : pattern.flags + 'g';
847
+ return Array.from(s.matchAll(new RegExp(pattern.source, flags)));
848
+ };
849
+
850
+ // Dart RegExp polyfills.
851
+ const rp: any = RegExp.prototype;
852
+ if (!rp.firstMatch) rp.firstMatch = function (s: any) {
853
+ const m = this.exec(s);
854
+ if (m) m.group = (i: any) => m[i];
855
+ return m;
856
+ };
857
+ if (!rp.allMatches) rp.allMatches = function (s: any) {
858
+ const flags = this.flags.includes('g') ? this.flags : this.flags + 'g';
859
+ return [...s.matchAll(new RegExp(this.source, flags))];
860
+ };
861
+ if (!rp.hasMatch) rp.hasMatch = function (s: any) { return this.test(s); };
862
+
863
+ // Dart Number polyfills — Dart num/int methods not on JS Number.prototype.
864
+ const _ballNp: any = Number.prototype;
865
+ if (!_ballNp.gcd) _ballNp.gcd = function (other: any) {
866
+ let a = Math.abs(this as number), b = Math.abs(Number(other));
867
+ while (b) { const t = b; b = a % b; a = t; }
868
+ return a;
869
+ };
870
+ Object.defineProperty(_ballNp, 'sign', {
871
+ configurable: true, get() { const n = Number(this); return n > 0 ? 1 : n < 0 ? -1 : 0; },
872
+ });
873
+ Object.defineProperty(_ballNp, 'isNaN', {
874
+ configurable: true, get() { return Number.isNaN(Number(this)); },
875
+ });
876
+ Object.defineProperty(_ballNp, 'isFinite', {
877
+ configurable: true, get() { return Number.isFinite(Number(this)); },
878
+ });
879
+ Object.defineProperty(_ballNp, 'isInfinite', {
880
+ configurable: true, get() { const n = Number(this); return n === Infinity || n === -Infinity; },
881
+ });
882
+ Object.defineProperty(_ballNp, 'isNegative', {
883
+ configurable: true, get() { const n = Number(this); return n < 0 || (n === 0 && 1 / n === -Infinity); },
884
+ });
885
+ if (!_ballNp.abs) _ballNp.abs = function () { return Math.abs(Number(this)); };
886
+ if (!_ballNp.ceil) _ballNp.ceil = function () { return Math.ceil(Number(this)); };
887
+ if (!_ballNp.floor) _ballNp.floor = function () { return Math.floor(Number(this)); };
888
+ if (!_ballNp.round) _ballNp.round = function () { return Math.round(Number(this)); };
889
+ if (!_ballNp.truncate) _ballNp.truncate = function () { return Math.trunc(Number(this)); };
890
+ if (!_ballNp.toInt) _ballNp.toInt = function () { return Math.trunc(Number(this)); };
891
+ if (!_ballNp.toDouble) _ballNp.toDouble = function () { return Number(this); };
892
+ if (!_ballNp.clamp) _ballNp.clamp = function (lo: any, hi: any) { const n = Number(this); return n < lo ? lo : n > hi ? hi : n; };
893
+ if (!_ballNp.compareTo) _ballNp.compareTo = function (other: any) { const a = Number(this), b = Number(other); return a < b ? -1 : a > b ? 1 : 0; };
894
+ if (!_ballNp.toStringAsFixed) _ballNp.toStringAsFixed = function (digits: any) { return __ball_to_fixed(this, digits); };
895
+ if (!_ballNp.remainder) _ballNp.remainder = function (other: any) { return Number(this) % Number(other); };
896
+
897
+ // Object.prototype polyfills — used by the compiled engine when
898
+ // checking Ball program inputs (plain objects, not Maps).
899
+ const op2: any = Object.prototype;
900
+ if (!op2.containsKey) {
901
+ Object.defineProperty(op2, 'containsKey', {
902
+ configurable: true, writable: true, enumerable: false,
903
+ value: function (k: any) {
904
+ if (this instanceof Map) return this.has(k);
905
+ if (this == null || typeof this !== 'object') return false;
906
+ return Object.prototype.hasOwnProperty.call(this, k);
907
+ },
908
+ });
909
+ }
910
+ // putIfAbsent — Dart Map.putIfAbsent. Works on plain objects too.
911
+ if (!op2.putIfAbsent) {
912
+ Object.defineProperty(op2, 'putIfAbsent', {
913
+ configurable: true, writable: true, enumerable: false,
914
+ value: function (k: any, supplier: any) {
915
+ if (this instanceof Map) {
916
+ if (!this.has(k)) this.set(k, supplier());
917
+ return this.get(k);
918
+ }
919
+ if (!(k in this)) this[k] = supplier();
920
+ return this[k];
921
+ },
922
+ });
923
+ }
924
+ // addAll — Dart Map.addAll. Works on plain objects too.
925
+ if (!op2.addAll) {
926
+ Object.defineProperty(op2, 'addAll', {
927
+ configurable: true, writable: true, enumerable: false,
928
+ value: function (other: any) {
929
+ if (this instanceof Map) {
930
+ if (other instanceof Map) {
931
+ // _nativeMapEntries, not other.entries() (issue #259).
932
+ for (const [k, v] of _nativeMapEntries.call(other)) this.set(k, v);
933
+ } else if (other && typeof other === 'object') {
934
+ for (const k of Object.keys(other)) this.set(k, other[k]);
935
+ }
936
+ } else {
937
+ if (other instanceof Map) {
938
+ for (const [k, v] of other) this[k] = v;
939
+ } else if (other && typeof other === 'object') {
940
+ Object.assign(this, other);
941
+ }
942
+ }
943
+ },
944
+ });
945
+ }
946
+ // forEach — Dart Map.forEach. Works on plain objects.
947
+ // Don't overwrite native Map.prototype.forEach.
948
+ Object.defineProperty(op2, 'forEach', {
949
+ configurable: true, writable: true, enumerable: false,
950
+ value: function (fn: any) {
951
+ if (this instanceof Map) {
952
+ return Map.prototype.forEach.call(this, fn);
953
+ }
954
+ if (Array.isArray(this)) {
955
+ return Array.prototype.forEach.call(this, fn);
956
+ }
957
+ // Plain object: Dart Map.forEach(void f(K key, V value))
958
+ if (typeof fn === 'function') {
959
+ for (const k of Object.keys(this)) fn(k, this[k]);
960
+ }
961
+ },
962
+ });
963
+ // remove — Dart Map.remove.
964
+ if (!op2.remove) {
965
+ Object.defineProperty(op2, 'remove', {
966
+ configurable: true, writable: true, enumerable: false,
967
+ value: function (k: any) {
968
+ if (this instanceof Map) { const v = this.get(k); this.delete(k); return v; }
969
+ const v = this[k]; delete this[k]; return v;
970
+ },
971
+ });
972
+ }
973
+ // cast — Dart Map.cast<K2,V2>() / List.cast<E2>(). The cast is a static
974
+ // re-typing only; at runtime it returns the same collection unchanged.
975
+ if (!op2.cast) {
976
+ Object.defineProperty(op2, 'cast', {
977
+ configurable: true, writable: true, enumerable: false,
978
+ value: function () { return this; },
979
+ });
980
+ }
981
+ // Dart Map has .entries / .keys / .values as GETTERS (no parens).
982
+ // JS Map has them as METHODS (need parens). The compiled engine
983
+ // accesses map.entries as a getter. Shadow BOTH Map.prototype AND
984
+ // Object.prototype so Map and plain-object dispatch tables work.
985
+ // (_nativeMapEntries/_nativeMapKeys/_nativeMapValues are captured at
986
+ // top level above, not here, so other call sites outside this IIFE
987
+ // can reach them too -- issue #259.)
988
+ // Shadow Map.prototype.entries with a getter (Dart uses it as a getter).
989
+ Object.defineProperty(Map.prototype, 'entries', {
990
+ configurable: true, enumerable: false,
991
+ get() {
992
+ return [..._nativeMapEntries.call(this)].map(([k, v]: any) => ({ key: k, value: v }));
993
+ },
994
+ });
995
+ Object.defineProperty(Map.prototype, 'keys', {
996
+ configurable: true, enumerable: false,
997
+ get() { return [..._nativeMapKeys.call(this)]; },
998
+ });
999
+ Object.defineProperty(Map.prototype, 'values', {
1000
+ configurable: true, enumerable: false,
1001
+ get() { return [..._nativeMapValues.call(this)]; },
1002
+ });
1003
+ // For plain objects — same getters on Object.prototype.
1004
+ // Helper: define a getter on Object.prototype that also allows
1005
+ // own-property assignment (setter stores as a data property on the
1006
+ // instance, shadowing the prototype getter for future accesses).
1007
+ function defDartGetter(name: string, getter: () => any) {
1008
+ Object.defineProperty(op2, name, {
1009
+ configurable: true, enumerable: false,
1010
+ get: getter,
1011
+ set(v: any) {
1012
+ Object.defineProperty(this, name, {
1013
+ value: v, writable: true, configurable: true, enumerable: true,
1014
+ });
1015
+ },
1016
+ });
1017
+ }
1018
+ // .entries/.keys/.values on a non-Map must FAIL LOUD (throw a catchable
1019
+ // error), not silently return [] — the silent-degradation class of bug
1020
+ // that hid issue #55 (mirrors the fix already applied to the Dart/C++
1021
+ // compilers). .entries used to be the odd one out here, silently
1022
+ // returning [] instead of throwing — same bug family as #218.
1023
+ //
1024
+ // A getter installed on Object.prototype is invoked in "sloppy" (non-strict)
1025
+ // script contexts with this auto-boxed to a Number/String/Boolean WRAPPER
1026
+ // object for a primitive receiver (e.g. (42).keys boxes this to a Number
1027
+ // instance) — typeof this is then 'object', not 'number', so a bare
1028
+ // __ball_is_type(this, 'Map') (which only excludes Array/BallDouble/Set)
1029
+ // would wrongly treat a boxed int/string as Map-like. Exclude the wrapper
1030
+ // types explicitly instead of widening the shared type-check.
1031
+ const __isGenuineMap = (v: any) =>
1032
+ typeof v === 'object' && v !== null && !Array.isArray(v) &&
1033
+ !(v instanceof BallDouble) && !(v instanceof Set) &&
1034
+ !(v instanceof Number) && !(v instanceof String) && !(v instanceof Boolean);
1035
+ defDartGetter('entries', function (this: any) {
1036
+ if (this instanceof Map) return [..._nativeMapEntries.call(this)].map(([k, v]: any) => ({ key: k, value: v }));
1037
+ if (!__isGenuineMap(this)) {
1038
+ throw new Error('type \'' + __ball_to_string(this) + '\' has no .entries getter (not a Map)');
1039
+ }
1040
+ return Object.entries(this).map(([k, v]: any) => ({ key: k, value: v }));
1041
+ });
1042
+ defDartGetter('keys', function (this: any) {
1043
+ if (this instanceof Map) return [..._nativeMapKeys.call(this)];
1044
+ if (!__isGenuineMap(this)) {
1045
+ throw new Error('type \'' + __ball_to_string(this) + '\' has no .keys getter (not a Map)');
1046
+ }
1047
+ return Object.keys(this);
1048
+ });
1049
+ defDartGetter('values', function (this: any) {
1050
+ if (this instanceof Map) return [..._nativeMapValues.call(this)];
1051
+ if (!__isGenuineMap(this)) {
1052
+ throw new Error('type \'' + __ball_to_string(this) + '\' has no .values getter (not a Map)');
1053
+ }
1054
+ return Object.values(this);
1055
+ });
1056
+ defDartGetter('length', function (this: any) {
1057
+ if (this instanceof Map) return this.size;
1058
+ if (this instanceof Set) return this.size;
1059
+ if (typeof this === 'string' || Array.isArray(this)) return this.length;
1060
+ if (this == null || typeof this !== 'object') return 0;
1061
+ return Object.keys(this).filter((k: string) => !k.startsWith('__')).length;
1062
+ });
1063
+
1064
+ // runtimeType — Dart's Object.runtimeType. Returns the Dart-style
1065
+ // type name for any JS value. Used by the compiled engine for type
1066
+ // checking and error messages.
1067
+ Object.defineProperty(op2, 'runtimeType', {
1068
+ configurable: true, enumerable: false,
1069
+ get() {
1070
+ if (this === null || this === undefined) return 'Null';
1071
+ if (this instanceof BallDouble) return 'double';
1072
+ if (typeof this === 'number' || this instanceof Number) return Number.isInteger(+this) ? 'int' : 'double';
1073
+ if (typeof this === 'string' || this instanceof String) return 'String';
1074
+ if (typeof this === 'boolean' || this instanceof Boolean) return 'bool';
1075
+ if (typeof this === 'function') return 'Function';
1076
+ if (Array.isArray(this)) return 'List';
1077
+ if (this instanceof Set) return 'Set';
1078
+ if (this instanceof Map) return 'Map';
1079
+ if (this instanceof RegExp) return 'RegExp';
1080
+ const t = this['__type__'];
1081
+ if (typeof t === 'string' && t.length > 0) {
1082
+ const ci = t.indexOf(':');
1083
+ return ci >= 0 ? t.substring(ci + 1) : t;
1084
+ }
1085
+ return 'Map';
1086
+ },
1087
+ });
1088
+ // Also add to Number.prototype, String.prototype, Boolean.prototype
1089
+ // (they don't inherit from Object.prototype getters reliably for primitives).
1090
+ Object.defineProperty(Number.prototype, 'runtimeType', {
1091
+ configurable: true, enumerable: false,
1092
+ get() { return Number.isInteger(+this) ? 'int' : 'double'; },
1093
+ });
1094
+ Object.defineProperty(String.prototype, 'runtimeType', {
1095
+ configurable: true, enumerable: false,
1096
+ get() { return 'String'; },
1097
+ });
1098
+ Object.defineProperty(Boolean.prototype, 'runtimeType', {
1099
+ configurable: true, enumerable: false,
1100
+ get() { return 'bool'; },
1101
+ });
1102
+ })();
1103
+
1104
+ // std.map_keys/std.map_values/std.map_entries (the base-function-call form,
1105
+ // as opposed to the .keys/.values/.entries DART-GETTER-STYLE property
1106
+ // access the defDartGetter block above already guards) must ALSO fail loud
1107
+ // on a non-Map receiver instead of silently returning [] — same "genuine
1108
+ // Map" check, exposed as top-level helpers so compileStdCall's emitted code
1109
+ // can call them (#218).
1110
+ export function __ball_map_keys(m: any): any {
1111
+ // _nativeMapKeys, not m.keys() -- m.keys() would hit the Dart-property-
1112
+ // style getter shadowing Map.prototype.keys and try to invoke its
1113
+ // return value (an array) as a function (issue #259).
1114
+ if (m instanceof Map) return [..._nativeMapKeys.call(m)];
1115
+ if (typeof m !== 'object' || m === null || Array.isArray(m) ||
1116
+ m instanceof BallDouble || m instanceof Set ||
1117
+ m instanceof Number || m instanceof String || m instanceof Boolean) {
1118
+ throw new Error('type \'' + __ball_to_string(m) + '\' has no .keys getter (not a Map)');
1119
+ }
1120
+ return Object.keys(m);
1121
+ }
1122
+ export function __ball_map_values(m: any): any {
1123
+ // _nativeMapValues, not m.values() (issue #259 -- see __ball_map_keys).
1124
+ if (m instanceof Map) return [..._nativeMapValues.call(m)];
1125
+ if (typeof m !== 'object' || m === null || Array.isArray(m) ||
1126
+ m instanceof BallDouble || m instanceof Set ||
1127
+ m instanceof Number || m instanceof String || m instanceof Boolean) {
1128
+ throw new Error('type \'' + __ball_to_string(m) + '\' has no .values getter (not a Map)');
1129
+ }
1130
+ return Object.values(m);
1131
+ }
1132
+ export function __ball_map_entries(m: any): any {
1133
+ // _nativeMapEntries, not m.entries() (issue #259 -- see __ball_map_keys).
1134
+ if (m instanceof Map) return [..._nativeMapEntries.call(m)].map(([k, v]) => ({ key: k, value: v }));
1135
+ if (typeof m !== 'object' || m === null || Array.isArray(m) ||
1136
+ m instanceof BallDouble || m instanceof Set ||
1137
+ m instanceof Number || m instanceof String || m instanceof Boolean) {
1138
+ throw new Error('type \'' + __ball_to_string(m) + '\' has no .entries getter (not a Map)');
1139
+ }
1140
+ return Object.entries(m).map(([k, v]) => ({ key: k, value: v }));
1141
+ }
1142
+
1143
+ // Shared guard for the REMAINING map_* base-function-call cases
1144
+ // (map_get/map_set/map_delete/map_merge/map_length/map_is_empty/
1145
+ // map_contains_key/map_contains_value/map_foreach) that used to route a
1146
+ // bare map[key], Object.keys/values(map), or key in map straight to the
1147
+ // receiver with no type check at all -- silently returning undefined,
1148
+ // no-opping, or checking array-index membership instead of throwing on a
1149
+ // non-Map (issue #55's silent-degradation class, same family as #218's
1150
+ // map_keys/map_values/map_entries). Returns the validated Map/plain-object
1151
+ // itself (not a boolean) so a call site can keep using it directly, e.g.
1152
+ // __ball_require_map(x, 'map_get')[key].
1153
+ export function __ball_require_map(v: any, opName: string): any {
1154
+ if (v instanceof Map) return v;
1155
+ if (typeof v !== 'object' || v === null || Array.isArray(v) ||
1156
+ v instanceof BallDouble || v instanceof Set ||
1157
+ v instanceof Number || v instanceof String || v instanceof Boolean) {
1158
+ throw new Error('type \'' + __ball_to_string(v) + '\' is not a Map (' + opName + ')');
1159
+ }
1160
+ return v;
1161
+ }
1162
+
1163
+ // ── Protobuf Struct/Value compatibility ─────────────────────────
1164
+ //
1165
+ // Dart's protobuf runtime wraps google.protobuf.Struct as a class
1166
+ // with .fields (Map<String, Value>) and Value as .whichKind() +
1167
+ // .stringValue / .boolValue / .numberValue / .listValue / .structValue.
1168
+ // In proto3 JSON, these serialize as plain objects and values.
1169
+ //
1170
+ // This shim makes plain JSON objects behave like Struct/Value so the
1171
+ // compiled engine.dart can call .fields['key'].whichKind() etc.
1172
+ //
1173
+ // Strategy: Object.prototype gets a .fields getter that returns a
1174
+ // Proxy wrapping the object as a Map-like. Accessing [key] on the
1175
+ // proxy returns a Value-like wrapper with .whichKind() / typed
1176
+ // accessors (.stringValue, .boolValue, .numberValue, .listValue,
1177
+ // .structValue).
1178
+
1179
+ export const structpb_Value_Kind = {
1180
+ nullValue: 'nullValue',
1181
+ numberValue: 'numberValue',
1182
+ stringValue: 'stringValue',
1183
+ boolValue: 'boolValue',
1184
+ structValue: 'structValue',
1185
+ listValue: 'listValue',
1186
+ } as const;
1187
+
1188
+ export class __BallValueWrapper {
1189
+ private _raw: any;
1190
+ constructor(raw: any) { this._raw = raw; }
1191
+ whichKind(): string {
1192
+ const v = this._raw;
1193
+ if (v === null || v === undefined) return 'nullValue';
1194
+ if (typeof v === 'string') return 'stringValue';
1195
+ if (typeof v === 'boolean') return 'boolValue';
1196
+ if (typeof v === 'number') return 'numberValue';
1197
+ if (Array.isArray(v)) return 'listValue';
1198
+ if (typeof v === 'object') return 'structValue';
1199
+ return 'nullValue';
1200
+ }
1201
+ get stringValue(): string { return typeof this._raw === 'string' ? this._raw : String(this._raw ?? ''); }
1202
+ get boolValue(): boolean { return !!this._raw; }
1203
+ get numberValue(): number { return Number(this._raw); }
1204
+ get nullValue(): null { return null; }
1205
+ get listValue(): { values: __BallValueWrapper[] } {
1206
+ const arr = Array.isArray(this._raw) ? this._raw : [];
1207
+ return { values: arr.map((v: any) => new __BallValueWrapper(v)) };
1208
+ }
1209
+ get structValue(): { fields: Record<string, __BallValueWrapper> } {
1210
+ const obj = (typeof this._raw === 'object' && this._raw !== null) ? this._raw : {};
1211
+ const fields: Record<string, __BallValueWrapper> = {};
1212
+ for (const [k, v] of Object.entries(obj)) fields[k] = new __BallValueWrapper(v);
1213
+ return { fields };
1214
+ }
1215
+ // Also proxy hasXxx for sub-values.
1216
+ hasNullValue(): boolean { return this._raw == null; }
1217
+ hasStringValue(): boolean { return typeof this._raw === 'string'; }
1218
+ hasBoolValue(): boolean { return typeof this._raw === 'boolean'; }
1219
+ hasNumberValue(): boolean { return typeof this._raw === 'number'; }
1220
+ hasListValue(): boolean { return Array.isArray(this._raw); }
1221
+ hasStructValue(): boolean { return typeof this._raw === 'object' && this._raw !== null && !Array.isArray(this._raw); }
1222
+ // Pass-through for when the wrapper is used in expressions.
1223
+ toString(): string { return String(this._raw); }
1224
+ valueOf(): any { return this._raw; }
1225
+ }
1226
+
1227
+ // Struct.fields shimming is done via a metadata-specific wrapper.
1228
+ // We do NOT add .fields to Object.prototype because it conflicts
1229
+ // with data properties named "fields" on MessageCreation / TypeDef.
1230
+ // Instead, the compiled engine accesses metadata.fields['key'] —
1231
+ // in proto3 JSON, metadata IS the fields directly, so we add a
1232
+ // .fields getter only when the object is a metadata Struct (i.e.,
1233
+ // it has string/bool/number/array/object values and no proto-shape
1234
+ // keys like "call"/"literal"/"block").
1235
+ //
1236
+ // The protoWrap normalizer in the test harness is responsible for
1237
+ // converting metadata objects to have the right shape.
1238
+
1239
+ // ── Protobuf compatibility shims ────────────────────────────────
1240
+ //
1241
+ // The Dart encoder produces code that uses Dart's protobuf runtime
1242
+ // API (.whichExpr(), Expression_Expr.call, .hasInput(), .toInt(), etc.)
1243
+ // on what are really plain JSON objects at runtime. These shims make
1244
+ // the proto-style method calls work on plain objects so the compiled
1245
+ // engine.dart can execute on Node.
1246
+
1247
+ // Oneof discriminator enums — string-valued constants that match the
1248
+ // field names the Dart protobuf codegen uses.
1249
+ export const Expression_Expr = {
1250
+ call: 'call', literal: 'literal', reference: 'reference',
1251
+ fieldAccess: 'fieldAccess', messageCreation: 'messageCreation',
1252
+ block: 'block', lambda: 'lambda', notSet: 'notSet',
1253
+ } as const;
1254
+
1255
+ export const Literal_Value = {
1256
+ intValue: 'intValue', doubleValue: 'doubleValue',
1257
+ stringValue: 'stringValue', boolValue: 'boolValue',
1258
+ listValue: 'listValue', bytesValue: 'bytesValue', notSet: 'notSet',
1259
+ } as const;
1260
+
1261
+ export const Statement_Stmt = {
1262
+ let: 'let', expression: 'expression', notSet: 'notSet',
1263
+ } as const;
1264
+
1265
+ export const ModuleImport_Source = {
1266
+ http: 'http', file: 'file', inline: 'inline',
1267
+ git: 'git', registry: 'registry', notSet: 'notSet',
1268
+ } as const;
1269
+
1270
+ // Object.prototype shims for .whichXxx() / .hasXxx() / .toInt() —
1271
+ // these match the Dart protobuf generated API. Each is configurable
1272
+ // and non-enumerable so it doesn't pollute for-in loops.
1273
+ (function installProtoShims() {
1274
+ const op: any = Object.prototype;
1275
+
1276
+ function defMethod(name: string, fn: Function) {
1277
+ if (op[name]) return;
1278
+ Object.defineProperty(op, name, {
1279
+ configurable: true, writable: true, enumerable: false, value: fn,
1280
+ });
1281
+ }
1282
+
1283
+ // whichExpr / whichValue / whichStmt / whichSource — return which
1284
+ // oneof field is set on this object.
1285
+ defMethod('whichExpr', function (this: any) {
1286
+ for (const k of ['call','literal','reference','fieldAccess','messageCreation','block','lambda']) {
1287
+ if (this[k] !== undefined && this[k] !== null) return k;
1288
+ }
1289
+ return 'notSet';
1290
+ });
1291
+ defMethod('whichValue', function (this: any) {
1292
+ for (const k of ['intValue','doubleValue','stringValue','boolValue','listValue','bytesValue']) {
1293
+ if (this[k] !== undefined && this[k] !== null) return k;
1294
+ }
1295
+ return 'notSet';
1296
+ });
1297
+ defMethod('whichStmt', function (this: any) {
1298
+ if (this['let'] !== undefined && this['let'] !== null) return 'let';
1299
+ if (this['expression'] !== undefined && this['expression'] !== null) return 'expression';
1300
+ return 'notSet';
1301
+ });
1302
+ defMethod('whichSource', function (this: any) {
1303
+ for (const k of ['http','file','inline','git','registry']) {
1304
+ if (this[k] !== undefined && this[k] !== null) return k;
1305
+ }
1306
+ return 'notSet';
1307
+ });
1308
+
1309
+ // Presence checks — .hasXxx() returns true if the field is set.
1310
+ for (const field of [
1311
+ 'input','body','result','metadata','value','name','module',
1312
+ 'left','right','condition','then','else','finally',
1313
+ 'subject','cases','catches','init','update','iterable',
1314
+ 'target','index','field','object','key','message',
1315
+ 'stringValue','boolValue','intValue','doubleValue','listValue',
1316
+ 'call','literal','reference','fieldAccess','messageCreation',
1317
+ 'block','lambda','let','expression','descriptor',
1318
+ ]) {
1319
+ const methodName = 'has' + field[0].toUpperCase() + field.slice(1);
1320
+ defMethod(methodName, function (this: any) {
1321
+ return this[field] !== undefined && this[field] !== null;
1322
+ });
1323
+ }
1324
+
1325
+ // Proto field-name aliases — Dart's protobuf codegen renames some
1326
+ // fields to avoid keyword collisions (field → field_2, etc.) but
1327
+ // proto3 JSON uses the original names. Add getters so both work.
1328
+ Object.defineProperty(op, 'field_2', {
1329
+ configurable: true, enumerable: false,
1330
+ get() { return this.field; },
1331
+ set(v: any) { this.field = v; },
1332
+ });
1333
+ // descriptor_ → descriptor (same issue)
1334
+ Object.defineProperty(op, 'descriptor_', {
1335
+ configurable: true, enumerable: false,
1336
+ get() { return this.descriptor; },
1337
+ set(v: any) { this.descriptor = v; },
1338
+ });
1339
+
1340
+ // .toInt() — Dart's Int64/fixnum returns int from string. In proto3
1341
+ // JSON, int64 fields are serialized as strings ("42" not 42).
1342
+ defMethod('toInt', function (this: any) {
1343
+ if (typeof this === 'number') return this;
1344
+ if (typeof this === 'string') return parseInt(this, 10);
1345
+ if (typeof this.valueOf === 'function') return parseInt(String(this.valueOf()), 10);
1346
+ return 0;
1347
+ });
1348
+
1349
+ // .toList() on Uint8Array (bytesValue)
1350
+ defMethod('toList', function (this: any) {
1351
+ if (this instanceof Uint8Array) return Array.from(this);
1352
+ if (Array.isArray(this)) return this.slice();
1353
+ return [];
1354
+ });
1355
+ })();
1356
+
1357
+ // ── Reified generics helpers ────────────────────────────────────────
1358
+ export function __ball_with_type_args<T>(obj: T, args: string[]): T {
1359
+ (obj as any).__type_args__ = args;
1360
+ return obj;
1361
+ }
1362
+
1363
+ // ── Generic type checking helper ────────────────────────────────────
1364
+ export function __ball_split_type_args(s: string): string[] {
1365
+ const result: string[] = [];
1366
+ let depth = 0, start = 0;
1367
+ for (let i = 0; i < s.length; i++) {
1368
+ if (s[i] === '<') depth++;
1369
+ else if (s[i] === '>') depth--;
1370
+ else if (s[i] === ',' && depth === 0) {
1371
+ result.push(s.slice(start, i).trim());
1372
+ start = i + 1;
1373
+ }
1374
+ }
1375
+ const last = s.slice(start).trim();
1376
+ if (last) result.push(last);
1377
+ return result;
1378
+ }
1379
+ export function __ball_is_type(value: any, typeStr: string): boolean {
1380
+ const t = typeStr.trim();
1381
+ if (t.endsWith('?')) {
1382
+ if (value == null) return true;
1383
+ return __ball_is_type(value, t.slice(0, -1));
1384
+ }
1385
+ const ltIdx = t.indexOf('<');
1386
+ if (ltIdx === -1) {
1387
+ switch (t) {
1388
+ case 'int': return typeof value === 'number' && Number.isInteger(value);
1389
+ case 'double': return value instanceof BallDouble || (typeof value === 'number' && !Number.isInteger(value));
1390
+ case 'num': case 'number': return typeof value === 'number' || value instanceof BallDouble;
1391
+ case 'String': case 'string': return typeof value === 'string';
1392
+ case 'bool': case 'boolean': return typeof value === 'boolean';
1393
+ case 'List': case 'Iterable': return Array.isArray(value);
1394
+ case 'Map': return typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof BallDouble) && !(value instanceof Set);
1395
+ case 'Set': return value instanceof Set;
1396
+ case 'Null': return value == null;
1397
+ case 'Function': return typeof value === 'function';
1398
+ case 'Object': case 'dynamic': return value != null;
1399
+ default: {
1400
+ const objType = value?.__type__ ?? value?.constructor?.name;
1401
+ if (objType === t) return true;
1402
+ return value != null;
1403
+ }
1404
+ }
1405
+ }
1406
+ const baseType = t.slice(0, ltIdx).trim();
1407
+ const typeArgs = __ball_split_type_args(t.slice(ltIdx + 1, t.lastIndexOf('>')));
1408
+ switch (baseType) {
1409
+ case 'List': case 'Iterable':
1410
+ if (!Array.isArray(value)) return false;
1411
+ if (typeArgs.length === 0) return true;
1412
+ return value.every((e: any) => __ball_is_type(e, typeArgs[0]));
1413
+ case 'Map':
1414
+ if (typeof value !== 'object' || value === null || Array.isArray(value) || value instanceof BallDouble || value instanceof Set) return false;
1415
+ if (typeArgs.length < 2) return true;
1416
+ 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]));
1417
+ case 'Set':
1418
+ if (!(value instanceof Set)) return false;
1419
+ if (typeArgs.length === 0) return true;
1420
+ for (const e of value) { if (!__ball_is_type(e, typeArgs[0])) return false; }
1421
+ return true;
1422
+ default: {
1423
+ const objType = value?.__type__ ?? value?.constructor?.name;
1424
+ if (objType === baseType) {
1425
+ const objArgs = value.__type_args__;
1426
+ if (Array.isArray(objArgs)) {
1427
+ if (objArgs.length !== typeArgs.length) return false;
1428
+ return objArgs.every((a: any, i: number) => String(a).trim() === typeArgs[i].trim());
1429
+ }
1430
+ return false;
1431
+ }
1432
+ return __ball_is_type(value, baseType);
1433
+ }
1434
+ }
1435
+ }
1436
+
1437
+ // Minimal DateTime / Duration / Future polyfills used by std_time and
1438
+ // the round-tripped engine's sleep_ms helper. Wide enough for the
1439
+ // conformance suite, narrow enough to stay out of users' way.
1440
+ export class DateTime {
1441
+ readonly _epochMs: number;
1442
+ readonly isUtc: boolean;
1443
+ constructor(epochMs?: number, isUtc: boolean = false) {
1444
+ this._epochMs = typeof epochMs === 'number' ? epochMs : Date.now();
1445
+ this.isUtc = isUtc;
1446
+ }
1447
+ static now(): DateTime { return new DateTime(Date.now(), false); }
1448
+ static fromMillisecondsSinceEpoch(ms: number, isUtc: any = false): DateTime {
1449
+ return new DateTime(ms, isUtc === true || (isUtc && (isUtc as any).isUtc === true));
1450
+ }
1451
+ static parse(s: string): DateTime { return new DateTime(Date.parse(s), true); }
1452
+ get millisecondsSinceEpoch(): number { return this._epochMs; }
1453
+ get microsecondsSinceEpoch(): number { return this._epochMs * 1000; }
1454
+ toUtc(): DateTime { return new DateTime(this._epochMs, true); }
1455
+ toIso8601String(): string { return new Date(this._epochMs).toISOString(); }
1456
+ get year(): number { return new Date(this._epochMs).getUTCFullYear(); }
1457
+ get month(): number { return new Date(this._epochMs).getUTCMonth() + 1; }
1458
+ get day(): number { return new Date(this._epochMs).getUTCDate(); }
1459
+ get hour(): number { return new Date(this._epochMs).getUTCHours(); }
1460
+ get minute(): number { return new Date(this._epochMs).getUTCMinutes(); }
1461
+ get second(): number { return new Date(this._epochMs).getUTCSeconds(); }
1462
+ }
1463
+ export class Duration {
1464
+ readonly _us: number;
1465
+ constructor(opts?: any) {
1466
+ const o = opts ?? {};
1467
+ const ms = o.milliseconds ?? 0;
1468
+ const s = o.seconds ?? 0;
1469
+ const m = o.minutes ?? 0;
1470
+ const us = o.microseconds ?? 0;
1471
+ this._us = us + ms * 1000 + s * 1_000_000 + m * 60_000_000;
1472
+ }
1473
+ get inMilliseconds(): number { return Math.floor(this._us / 1000); }
1474
+ get inMicroseconds(): number { return this._us; }
1475
+ }
1476
+ export const Future = {
1477
+ delayed(d: any): Promise<void> {
1478
+ const ms = (d && typeof d.inMilliseconds === 'number') ? d.inMilliseconds : Number(d ?? 0);
1479
+ return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
1480
+ },
1481
+ value(v: any): Promise<any> { return Promise.resolve(v); },
1482
+ };
1483
+
1484
+ // ── dart:typed_data shims (ByteData, Endian) ───────────────────────
1485
+ // ball_protobuf uses ByteData for IEEE 754 float/double bit conversion.
1486
+ // Dart's ByteData wraps a fixed-size byte buffer with typed get/set methods.
1487
+ export const Endian = { little: true, big: false, host: true };
1488
+
1489
+ export class ByteData {
1490
+ _view: DataView;
1491
+ _length: number;
1492
+ constructor(size: number) {
1493
+ this._view = new DataView(new ArrayBuffer(size));
1494
+ this._length = size;
1495
+ }
1496
+ get lengthInBytes(): number { return this._length; }
1497
+ getUint8(i: number): number { return this._view.getUint8(i); }
1498
+ setUint8(i: number, v: number): void { this._view.setUint8(i, v); }
1499
+ getInt8(i: number): number { return this._view.getInt8(i); }
1500
+ setInt8(i: number, v: number): void { this._view.setInt8(i, v); }
1501
+ getUint16(i: number, endian?: any): number { return this._view.getUint16(i, endian === Endian.little); }
1502
+ setUint16(i: number, v: number, endian?: any): void { this._view.setUint16(i, v, endian === Endian.little); }
1503
+ getInt16(i: number, endian?: any): number { return this._view.getInt16(i, endian === Endian.little); }
1504
+ setInt16(i: number, v: number, endian?: any): void { this._view.setInt16(i, v, endian === Endian.little); }
1505
+ getUint32(i: number, endian?: any): number { return this._view.getUint32(i, endian === Endian.little); }
1506
+ setUint32(i: number, v: number, endian?: any): void { this._view.setUint32(i, v, endian === Endian.little); }
1507
+ getInt32(i: number, endian?: any): number { return this._view.getInt32(i, endian === Endian.little); }
1508
+ setInt32(i: number, v: number, endian?: any): void { this._view.setInt32(i, v, endian === Endian.little); }
1509
+ getFloat32(i: number, endian?: any): number { return this._view.getFloat32(i, endian === Endian.little); }
1510
+ setFloat32(i: number, v: number, endian?: any): void { this._view.setFloat32(i, v, endian === Endian.little); }
1511
+ getFloat64(i: number, endian?: any): number { return this._view.getFloat64(i, endian === Endian.little); }
1512
+ setFloat64(i: number, v: number, endian?: any): void { this._view.setFloat64(i, v, endian === Endian.little); }
1513
+ getUint64(i: number, endian?: any): bigint {
1514
+ const lo = this._view.getUint32(i, endian === Endian.little);
1515
+ const hi = this._view.getUint32(i + 4, endian === Endian.little);
1516
+ return endian === Endian.little
1517
+ ? BigInt(lo) | (BigInt(hi) << 32n)
1518
+ : (BigInt(lo) << 32n) | BigInt(hi);
1519
+ }
1520
+ setUint64(i: number, v: bigint, endian?: any): void {
1521
+ const lo = Number(v & 0xFFFFFFFFn);
1522
+ const hi = Number((v >> 32n) & 0xFFFFFFFFn);
1523
+ if (endian === Endian.little) {
1524
+ this._view.setUint32(i, lo, true);
1525
+ this._view.setUint32(i + 4, hi, true);
1526
+ } else {
1527
+ this._view.setUint32(i, hi, false);
1528
+ this._view.setUint32(i + 4, lo, false);
1529
+ }
1530
+ }
1531
+ getInt64(i: number, endian?: any): bigint {
1532
+ const unsigned = this.getUint64(i, endian);
1533
+ return unsigned >= 0x8000000000000000n ? unsigned - 0x10000000000000000n : unsigned;
1534
+ }
1535
+ setInt64(i: number, v: bigint, endian?: any): void {
1536
+ this.setUint64(i, v < 0n ? v + 0x10000000000000000n : v, endian);
1537
+ }
1538
+ get buffer(): { asUint8List: (start?: number, length?: number) => number[] } {
1539
+ const view = this._view;
1540
+ return {
1541
+ asUint8List: (start?: number, length?: number) => {
1542
+ const s = start ?? 0;
1543
+ const l = length ?? view.byteLength - s;
1544
+ return [...new Uint8Array(view.buffer, s, l)];
1545
+ },
1546
+ };
1547
+ }
1548
+ }
1549
+
1550
+ // ── dart:convert shims (utf8, jsonEncode, jsonDecode) ───────────────
1551
+ // ball_protobuf uses utf8.encode/decode for string↔bytes and
1552
+ // jsonEncode/jsonDecode for JSON serialization.
1553
+ export const utf8 = {
1554
+ encode(s: string): number[] { return [...new TextEncoder().encode(s)]; },
1555
+ decode(bytes: any): string { return new TextDecoder().decode(new Uint8Array(bytes)); },
1556
+ };
1557
+
1558
+ export function jsonEncode(obj: any): string { return JSON.stringify(obj); }
1559
+ export function jsonDecode(s: string): any { return JSON.parse(s); }
1560
+
1561
+
1562
+ export function __isUnknownFnError(e: any): boolean {
1563
+ const m = e && typeof e.message === 'string' ? e.message : (typeof e === 'string' ? e : '');
1564
+ return m.startsWith('Unknown std function:') || m.startsWith('Unknown base module:');
1565
+ }
1566
+ export function versionLine(version: any): any {
1567
+ const input = version;
1568
+ return ('ball ' + __ball_to_string(version));
1569
+ }
1570
+
1571
+ export function infoReport(program: any): any {
1572
+ const input = program;
1573
+ let lines = [];
1574
+ lines = (lines.push(((('Program: ' + __ball_to_string(program.name)) + ' v') + __ball_to_string(program.version))), lines);
1575
+ lines = (lines.push(((('Entry: ' + __ball_to_string(program.entryModule)) + '.') + __ball_to_string(program.entryFunction))), lines);
1576
+ lines = (lines.push(('Modules: ' + __ball_to_string(program.modules.length))), lines);
1577
+ lines = (lines.push(''), lines);
1578
+ for (const module of program.modules) {
1579
+ let isBase = _allBase(module.functions);
1580
+ lines = (lines.push(((' ' + __ball_to_string(module.name)) + __ball_to_string((isBase ? ' (base)' : '')))), lines);
1581
+ if (!(module.typeDefs.length === 0)) {
1582
+ lines = (lines.push((' typeDefs: ' + __ball_to_string(module.typeDefs.length))), lines);
1583
+ }
1584
+ if (!(module.typeAliases.length === 0)) {
1585
+ lines = (lines.push((' aliases: ' + __ball_to_string(module.typeAliases.length))), lines);
1586
+ }
1587
+ if (!(module.enums.length === 0)) {
1588
+ lines = (lines.push((' enums: ' + __ball_to_string(module.enums.length))), lines);
1589
+ }
1590
+ lines = (lines.push((' functions: ' + __ball_to_string(module.functions.length))), lines);
1591
+ if (!(module.description.length === 0)) {
1592
+ lines = (lines.push((' desc: ' + __ball_to_string(module.description))), lines);
1593
+ }
1594
+ }
1595
+ return lines.join('\n');
1596
+ }
1597
+
1598
+ export function validationErrors(program: any): any {
1599
+ const input = program;
1600
+ let errors = [];
1601
+ if ((program.entryModule.length === 0)) {
1602
+ errors = (errors.push('Missing entry_module'), errors);
1603
+ }
1604
+ if ((program.entryFunction.length === 0)) {
1605
+ errors = (errors.push('Missing entry_function'), errors);
1606
+ }
1607
+ if ((!(program.entryModule.length === 0) && !(program.entryFunction.length === 0))) {
1608
+ let entryMod;
1609
+ for (const m of program.modules) {
1610
+ if (__ball_eq(m.name, program.entryModule)) {
1611
+ entryMod = m;
1612
+ break;
1613
+ }
1614
+ }
1615
+ if (__ball_eq(entryMod, null)) {
1616
+ errors = (errors.push((('Entry module "' + __ball_to_string(program.entryModule)) + '" not found in modules')), errors);
1617
+ } else {
1618
+ let entryFunc;
1619
+ for (const f of entryMod.functions) {
1620
+ if (__ball_eq(f.name, program.entryFunction)) {
1621
+ entryFunc = f;
1622
+ break;
1623
+ }
1624
+ }
1625
+ if (__ball_eq(entryFunc, null)) {
1626
+ errors = (errors.push(((('Entry function "' + __ball_to_string(program.entryFunction)) + '" not found ') + (('in module "' + __ball_to_string(program.entryModule)) + '"'))), errors);
1627
+ }
1628
+ }
1629
+ }
1630
+ for (let i = 0; __ball_lt(i, program.modules.length); (i++)) {
1631
+ let m = __ball_index(program.modules, i);
1632
+ if ((m.name.length === 0)) {
1633
+ errors = (errors.push((('Module at index ' + __ball_to_string(i)) + ' has no name')), errors);
1634
+ }
1635
+ }
1636
+ let seen = [];
1637
+ for (const m of program.modules) {
1638
+ if (!(m.name.length === 0)) {
1639
+ if (seen.includes(m.name)) {
1640
+ errors = (errors.push((('Duplicate module name: "' + __ball_to_string(m.name)) + '"')), errors);
1641
+ } else {
1642
+ seen = (seen.push(m.name), seen);
1643
+ }
1644
+ }
1645
+ }
1646
+ for (const m of program.modules) {
1647
+ for (const f of m.functions) {
1648
+ if (((!f.isBase && !hasBody(f)) && !hasMetadata(f))) {
1649
+ errors = (errors.push((((__ball_to_string(m.name) + '.') + __ball_to_string(f.name)) + ': non-base function with no body or metadata')), errors);
1650
+ }
1651
+ }
1652
+ }
1653
+ return errors;
1654
+ }
1655
+
1656
+ export function validateOk(program: any): any {
1657
+ const input = program;
1658
+ return (validationErrors(program).length === 0);
1659
+ }
1660
+
1661
+ export function validateReport(program: any): any {
1662
+ const input = program;
1663
+ let errors = validationErrors(program);
1664
+ if ((errors.length === 0)) {
1665
+ let totalFns = 0;
1666
+ for (const m of program.modules) {
1667
+ totalFns += m.functions.length;
1668
+ }
1669
+ return ((((('Valid: "' + __ball_to_string(program.name)) + '" v') + __ball_to_string(program.version)) + '\n') + ((((' ' + __ball_to_string(program.modules.length)) + ' modules, ') + __ball_to_string(totalFns)) + ' functions'));
1670
+ }
1671
+ let lines = [];
1672
+ lines = (lines.push((('Invalid: ' + __ball_to_string(errors.length)) + ' error(s) found')), lines);
1673
+ for (const e of errors) {
1674
+ lines = (lines.push((' - ' + __ball_to_string(e))), lines);
1675
+ }
1676
+ return lines.join('\n');
1677
+ }
1678
+
1679
+ export function treeReport(program: any): any {
1680
+ const input = program;
1681
+ let lines = [];
1682
+ lines = (lines.push(((__ball_to_string(program.name) + ' v') + __ball_to_string(program.version))), lines);
1683
+ for (const m of program.modules) {
1684
+ let isBase = (_allBase(m.functions) && !(m.functions.length === 0));
1685
+ let tag = (isBase ? ' (base)' : '');
1686
+ let fnCount = m.functions.length;
1687
+ lines = (lines.push((((((' ' + __ball_to_string(m.name)) + __ball_to_string(tag)) + ' \u2014 ') + __ball_to_string(fnCount)) + ' functions')), lines);
1688
+ for (const imp of m.moduleImports) {
1689
+ lines = (lines.push(((((' \u2192 ' + __ball_to_string(imp.name)) + ' (') + __ball_to_string(_importSource(imp))) + ')')), lines);
1690
+ }
1691
+ }
1692
+ return lines.join('\n');
1693
+ }
1694
+
1695
+ export function _importSource(imp: any): any {
1696
+ const input = imp;
1697
+ if (hasHttp(imp)) {
1698
+ return ('http: ' + __ball_to_string(imp.http.url));
1699
+ }
1700
+ if (hasFile(imp)) {
1701
+ return ('file: ' + __ball_to_string(imp.file.path));
1702
+ }
1703
+ if (hasGit(imp)) {
1704
+ return ((('git: ' + __ball_to_string(imp.git.url)) + '@') + __ball_to_string(imp.git.ref));
1705
+ }
1706
+ if (hasRegistry(imp)) {
1707
+ return ((__ball_to_string(imp.registry.registry.name) + ': ') + ((__ball_to_string(imp.registry.package) + '@') + __ball_to_string(imp.registry.version)));
1708
+ }
1709
+ if (hasInline(imp)) {
1710
+ return 'inline';
1711
+ }
1712
+ return 'ref only';
1713
+ }
1714
+
1715
+ export function auditReport(program: any): any {
1716
+ const input = program;
1717
+ let report = analyzeCapabilities(program);
1718
+ let buf = "";
1719
+ buf.writeln(formatCapabilityReport(report));
1720
+ let termReport = analyzeTermination(program);
1721
+ if (!(termReport.warnings.length === 0)) {
1722
+ buf.writeln('');
1723
+ buf.writeln(formatTerminationReport(termReport));
1724
+ }
1725
+ return __ball_to_string(buf);
1726
+ }
1727
+
1728
+ export function _allBase(functions: any): any {
1729
+ const input = functions;
1730
+ for (const f of functions) {
1731
+ if (!f.isBase) {
1732
+ return false;
1733
+ }
1734
+ }
1735
+ return true;
1736
+ }