@ball-lang/engine 1.4.4 → 1.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ball-lang/engine",
3
- "version": "1.4.4",
3
+ "version": "1.5.0",
4
4
  "description": "Ball language engine — interprets Ball programs in TypeScript/JavaScript. Runs in Node.js and browsers.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1389,7 +1389,7 @@ export class BallEngine {
1389
1389
  this.moduleHandlers = moduleHandlers;
1390
1390
  this._validateProgramLimits();
1391
1391
  if (enableProfiling) {
1392
- this._callCounts = new Set();
1392
+ this._callCounts = {};
1393
1393
  }
1394
1394
  for (const handler of this.moduleHandlers) {
1395
1395
  handler.init(this);
@@ -1428,7 +1428,7 @@ export class BallEngine {
1428
1428
  }
1429
1429
 
1430
1430
  profilingReport(): any {
1431
- return Map.unmodifiable((this._callCounts ?? new Set()));
1431
+ return Map.unmodifiable((this._callCounts ?? {}));
1432
1432
  }
1433
1433
 
1434
1434
  callFunction(module: any, function_: any, input: any): any {
@@ -2212,7 +2212,7 @@ export class BallEngine {
2212
2212
  fields[entry.key] = entry.value;
2213
2213
  }
2214
2214
  }
2215
- return new BallObject({ typeName: typeName, superObject: __ball_index(instance, '__super__'), fields: fields, methods: (__ball_index(instance, '__methods__') ?? new Set()) });
2215
+ return new BallObject({ typeName: typeName, superObject: __ball_index(instance, '__super__'), fields: fields, methods: (__ball_index(instance, '__methods__') ?? {}) });
2216
2216
  }
2217
2217
 
2218
2218
  async _invokeSuperConstructor(childCtor: any, superclass: any, resolvedParams: any): Promise<any> {
@@ -3726,7 +3726,7 @@ export class BallEngine {
3726
3726
  }
3727
3727
  else if ((__sw === 'reversed')) {
3728
3728
  if (!__ball_eq(rawList, null)) {
3729
- return [...rawList.reversed];
3729
+ return this._manualReverse(rawList);
3730
3730
  }
3731
3731
  }
3732
3732
  else if ((__sw === 'keys')) {
@@ -4553,7 +4553,7 @@ export class BallEngine {
4553
4553
  _lazyFields(call: any): any {
4554
4554
  const input = call;
4555
4555
  if ((!hasInput(call) || !__ball_eq(whichExpr(call.input), Expression_Expr.messageCreation))) {
4556
- return new Set();
4556
+ return {};
4557
4557
  }
4558
4558
  let result = {};
4559
4559
  for (const f of call.input.messageCreation.fields) {
@@ -5822,6 +5822,20 @@ export class BallEngine {
5822
5822
  throw new _FlowSignal('goto', { label: label });
5823
5823
  }
5824
5824
 
5825
+ _gotoSignalLabel(signal: any): any {
5826
+ const input = signal;
5827
+ if ((signal instanceof _FlowSignal)) {
5828
+ return (__ball_eq(signal.kind, 'goto') ? signal.label : null);
5829
+ }
5830
+ if ((typeof signal === 'string')) {
5831
+ return signal;
5832
+ }
5833
+ if (((typeof signal === 'object' && signal !== null && !Array.isArray(signal) && !(signal instanceof BallDouble) && !(signal instanceof Set)) && __ball_eq(__ball_index(signal, 'kind'), 'goto'))) {
5834
+ let l = __ball_index(signal, 'label');
5835
+ return ((typeof l === 'string') ? l : null);
5836
+ }
5837
+ }
5838
+
5825
5839
  async _evalLabel(call: any, scope: any): Promise<any> {
5826
5840
  let fields = this._lazyFields(call);
5827
5841
  let label = this._stringFieldVal(fields, 'name');
@@ -5838,13 +5852,13 @@ export class BallEngine {
5838
5852
  } catch (__ball_active_error) {
5839
5853
  const e = __ball_active_error;
5840
5854
  let signal = e;
5841
- if ((((signal instanceof _FlowSignal) && __ball_eq(signal.kind, 'goto')) && __ball_eq(signal.label, label))) {
5855
+ if (__ball_eq(this._gotoSignalLabel(signal), label)) {
5842
5856
  repeat = true;
5843
5857
  } else {
5844
5858
  throw __ball_active_error;
5845
5859
  }
5846
5860
  }
5847
- if ((((!repeat && (result instanceof _FlowSignal)) && __ball_eq(result.kind, 'goto')) && __ball_eq(result.label, label))) {
5861
+ if ((!repeat && __ball_eq(this._gotoSignalLabel(result), label))) {
5848
5862
  repeat = true;
5849
5863
  }
5850
5864
  }
@@ -6064,7 +6078,7 @@ export class BallEngine {
6064
6078
  return _wrapList(self.slice(this._toInt(arg0), (!__ball_eq(end, null) ? this._toInt(end) : null)));
6065
6079
  }
6066
6080
  else if ((__sw === 'reversed')) {
6067
- return _wrapList([...self.reversed]);
6081
+ return _wrapList(this._manualReverse(self));
6068
6082
  }
6069
6083
  else if ((__sw === 'sort')) {
6070
6084
  if ((typeof arg0 === 'function')) {
@@ -7209,7 +7223,7 @@ export class BallEngine {
7209
7223
  return (() => { const __r: any[] = []; for (const idx of indices) { __r.push(__ball_index(list, idx)); } return __r; })();
7210
7224
  }), ['list_reverse']: ((i) => {
7211
7225
  const input = i;
7212
- return this._trackListCopy([...this._stdAsList(__ball_index(this._stdAsMap(i), 'list')).reversed]);
7226
+ return this._trackListCopy(this._manualReverse(this._stdAsList(__ball_index(this._stdAsMap(i), 'list'))));
7213
7227
  }), ['list_slice']: ((i) => {
7214
7228
  const input = i;
7215
7229
  let m = this._stdAsMap(i);
@@ -8154,6 +8168,15 @@ export class BallEngine {
8154
8168
  return list;
8155
8169
  }
8156
8170
 
8171
+ _manualReverse(list: any): any {
8172
+ const input = list;
8173
+ let result = [];
8174
+ for (let i = __ball_sub(list.length, 1); (i >= 0); (i--)) {
8175
+ result = (result.push(__ball_index(list, i)), result);
8176
+ }
8177
+ return result;
8178
+ }
8179
+
8157
8180
  _resolveMethod(typeName: any, methodName: any): any {
8158
8181
  let colonIdx = typeName.indexOf(':');
8159
8182
  let modPart = ((colonIdx >= 0) ? typeName.substring(0, colonIdx) : this._currentModule);
@@ -8320,7 +8343,8 @@ export class BallEngine {
8320
8343
  }
8321
8344
  if (__ball_eq(typeName, null)) {
8322
8345
  let parts = [];
8323
- for (const e of map.entries) {
8346
+ let rawMap = (((typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof BallDouble) && !(v instanceof Set)) && !(false /* BallMap is Map in TS */)) ? v : map);
8347
+ for (const e of rawMap.entries) {
8324
8348
  let k = await this._ballToStringAsync(e.key);
8325
8349
  let val = await this._ballToStringAsync(e.value);
8326
8350
  parts = (parts.push(((__ball_to_string(k) + ': ') + __ball_to_string(val))), parts);
@@ -9044,7 +9068,7 @@ export class BallEngine {
9044
9068
  }
9045
9069
  let list = this._stdAsList(fields);
9046
9070
  if (__ball_eq(list, null)) {
9047
- return new Set();
9071
+ return {};
9048
9072
  }
9049
9073
  let result = {};
9050
9074
  let positional = 1;
@@ -10005,7 +10029,7 @@ function _ballToDouble(value: any): any {
10005
10029
 
10006
10030
  function _ballValueIsSet(v: any): any {
10007
10031
  const input = v;
10008
- return (((typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof BallDouble) && !(v instanceof Set)) && __ball_eq(v.length, 1)) && (_kBallSetTag in v));
10032
+ return ((typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof BallDouble) && !(v instanceof Set)) && (_kBallSetTag in v));
10009
10033
  }
10010
10034
 
10011
10035
  function _ballIsInt(v: any): any {
@@ -786,8 +786,19 @@ export function createEngineSetup(mod: EngineModule) {
786
786
  _r('list_add', (i: any) => { const m = _m(i); const l = m['list'] ?? m['collection']; const v = m['value'] ?? m['element']; if (l instanceof Set) { l.add(v); return null; } if (Array.isArray(l)) l.push(v); return null; });
787
787
  _r('list_add_all', (i: any) => { const m = _m(i); const l = m['list'] ?? m['collection']; const o = m['other'] ?? m['elements'] ?? []; if (Array.isArray(l) && Array.isArray(o)) l.push(...o); return null; });
788
788
  _r('list_remove_at', (i: any) => { const m = _m(i); const l = m['list'] ?? m['collection']; const idx = Number(m['index'] ?? 0); return Array.isArray(l) ? l.splice(idx, 1)[0] : null; });
789
- _r('list_insert', (i: any) => { const m = _m(i); const l = m['list'] ?? m['collection']; const idx = Number(m['index'] ?? 0); const v = m['value'] ?? m['element']; if (Array.isArray(l)) l.splice(idx, 0, v); return null; });
790
- _r('list_clear', (i: any) => { const m = _m(i); const l = m['list'] ?? m['collection']; if (Array.isArray(l)) l.length = 0; return null; });
789
+ // Both mutate in place AND return the (mutated) list: the encoder wraps
790
+ // `list.insert(...)` / `list.clear()` statements in
791
+ // `assign(target: list, value: list_insert(...)/list_clear(...))`
792
+ // (`mutatingMethods` in encoder.dart), so returning `null` here — as a
793
+ // literal Dart-`void`-return translation would — reassigns the variable
794
+ // to `null` instead of the mutated list (issue #64 std-coverage gap:
795
+ // `385_list_insert_at_index` was the first fixture to actually exercise
796
+ // the non-cascade `list_insert` path on the TS self-host and caught
797
+ // this). `list_clear` has the identical bug shape but was previously
798
+ // only exercised via a cascade (`111_cascade_operator.dart`), which
799
+ // discards the mutating call's return value and never surfaced it.
800
+ _r('list_insert', (i: any) => { const m = _m(i); const l = m['list'] ?? m['collection']; const idx = Number(m['index'] ?? 0); const v = m['value'] ?? m['element']; if (Array.isArray(l)) l.splice(idx, 0, v); return l; });
801
+ _r('list_clear', (i: any) => { const m = _m(i); const l = m['list'] ?? m['collection']; if (Array.isArray(l)) l.length = 0; return l; });
791
802
  _r('list_contains', (i: any) => {
792
803
  const m = _m(i); const l = m['list'] ?? m['collection'] ?? []; const v = m['value'] ?? m['element'];
793
804
  if (l instanceof Set) { if (l.has(v)) return true; if (typeof v === 'number') return l.has(String(v)); if (typeof v === 'string') { const n = Number(v); if (!isNaN(n)) return l.has(n); } return false; }