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