@ball-lang/engine 1.68.6 → 1.69.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.68.6",
3
+ "version": "1.69.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",
@@ -6456,7 +6456,35 @@ export class BallEngine {
6456
6456
  return self.includes(arg0);
6457
6457
  }
6458
6458
  else if ((__sw === 'indexOf')) {
6459
- return self.indexOf(arg0);
6459
+ let indexFrom = __ball_index(args, 'arg1');
6460
+ if (__ball_eq(indexFrom, null)) {
6461
+ return self.indexOf(arg0);
6462
+ }
6463
+ let scan = this._toInt(indexFrom);
6464
+ if (__ball_lt(scan, 0)) {
6465
+ scan = 0;
6466
+ }
6467
+ while (__ball_lt(scan, self.length)) {
6468
+ if (__ball_eq(__ball_index(self, scan), arg0)) {
6469
+ return scan;
6470
+ }
6471
+ (scan++);
6472
+ }
6473
+ return __ball_negate(1);
6474
+ }
6475
+ else if ((__sw === 'lastIndexOf')) {
6476
+ let lastFrom = __ball_index(args, 'arg1');
6477
+ let lastScan = (__ball_eq(lastFrom, null) ? __ball_sub(self.length, 1) : this._toInt(lastFrom));
6478
+ if (__ball_ge(lastScan, self.length)) {
6479
+ lastScan = __ball_sub(self.length, 1);
6480
+ }
6481
+ while (__ball_ge(lastScan, 0)) {
6482
+ if (__ball_eq(__ball_index(self, lastScan), arg0)) {
6483
+ return lastScan;
6484
+ }
6485
+ (lastScan--);
6486
+ }
6487
+ return __ball_negate(1);
6460
6488
  }
6461
6489
  else if ((__sw === 'join')) {
6462
6490
  let joinParts = [];
@@ -6806,7 +6834,19 @@ export class BallEngine {
6806
6834
  return self.substring(this._toInt(arg0), (!__ball_eq(end, null) ? this._toInt(end) : null));
6807
6835
  }
6808
6836
  else if ((__sw === 'indexOf')) {
6809
- return self.indexOf(__ball_to_string(arg0));
6837
+ let strFrom = __ball_index(args, 'arg1');
6838
+ if (__ball_eq(strFrom, null)) {
6839
+ return self.indexOf(__ball_to_string(arg0));
6840
+ }
6841
+ let strScan = this._toInt(strFrom);
6842
+ if (__ball_lt(strScan, 0)) {
6843
+ strScan = 0;
6844
+ }
6845
+ if (__ball_gt(strScan, self.length)) {
6846
+ return __ball_negate(1);
6847
+ }
6848
+ let strHit = self.substring(strScan).indexOf(__ball_to_string(arg0));
6849
+ return (__ball_lt(strHit, 0) ? __ball_negate(1) : __ball_add(strHit, strScan));
6810
6850
  }
6811
6851
  else if ((__sw === 'split')) {
6812
6852
  return self.split(__ball_to_string(arg0));
@@ -6824,7 +6864,51 @@ export class BallEngine {
6824
6864
  return self.split(__ball_to_string(arg0)).join(__ball_to_string((__ball_index(args, 'arg1') ?? '')));
6825
6865
  }
6826
6866
  else if ((__sw === 'startsWith')) {
6827
- return self.startsWith(__ball_to_string(arg0));
6867
+ let swFrom = __ball_index(args, 'arg1');
6868
+ if (__ball_eq(swFrom, null)) {
6869
+ return self.startsWith(__ball_to_string(arg0));
6870
+ }
6871
+ let swAt = this._toInt(swFrom);
6872
+ if (__ball_lt(swAt, 0)) {
6873
+ swAt = 0;
6874
+ }
6875
+ if (__ball_gt(swAt, self.length)) {
6876
+ return false;
6877
+ }
6878
+ return self.substring(swAt).startsWith(__ball_to_string(arg0));
6879
+ }
6880
+ else if ((__sw === 'lastIndexOf')) {
6881
+ let liNeedle = __ball_to_string(arg0);
6882
+ let liStart = __ball_index(args, 'arg1');
6883
+ if (__ball_eq(liStart, null)) {
6884
+ return self.lastIndexOf(liNeedle);
6885
+ }
6886
+ let liAt = this._toInt(liStart);
6887
+ if (__ball_lt(liAt, 0)) {
6888
+ return __ball_negate(1);
6889
+ }
6890
+ let liEnd = __ball_add(liAt, liNeedle.length);
6891
+ if (__ball_gt(liEnd, self.length)) {
6892
+ liEnd = self.length;
6893
+ }
6894
+ return self.substring(0, liEnd).lastIndexOf(liNeedle);
6895
+ }
6896
+ else if ((__sw === 'replaceFirst')) {
6897
+ let rfTo = __ball_to_string((__ball_index(args, 'arg1') ?? ''));
6898
+ let rfStart = __ball_index(args, 'arg2');
6899
+ if (__ball_eq(rfStart, null)) {
6900
+ return self.replace(__ball_to_string(arg0), rfTo);
6901
+ }
6902
+ let rfAt = this._toInt(rfStart);
6903
+ if (__ball_lt(rfAt, 0)) {
6904
+ rfAt = 0;
6905
+ }
6906
+ if (__ball_gt(rfAt, self.length)) {
6907
+ return self;
6908
+ }
6909
+ let rfHead = self.substring(0, rfAt);
6910
+ let rfTail = self.substring(rfAt).replace(__ball_to_string(arg0), rfTo);
6911
+ return __ball_add(rfHead, rfTail);
6828
6912
  }
6829
6913
  else if ((__sw === 'endsWith')) {
6830
6914
  return self.endsWith(__ball_to_string(arg0));
@@ -7964,23 +8048,22 @@ export class BallEngine {
7964
8048
  let m = this._stdAsMap(i);
7965
8049
  let items = this._ballSetItems(__ball_index(m, 'set'));
7966
8050
  let value = __ball_index(m, 'value');
7967
- if (!items.includes(value)) {
7968
- this._trackMemoryAllocation(_ballPointerBytes);
7969
- return this._ballSetOf([items, value]);
8051
+ if (items.includes(value)) {
8052
+ return false;
7970
8053
  }
7971
- return this._ballSetOf(items);
8054
+ this._trackMemoryAllocation(_ballPointerBytes);
8055
+ items = (items.push(value), items);
8056
+ return true;
7972
8057
  }), ['set_remove']: ((i) => {
7973
8058
  const input = i;
7974
8059
  let m = this._stdAsMap(i);
7975
8060
  let items = this._ballSetItems(__ball_index(m, 'set'));
7976
- let value = __ball_index(m, 'value');
7977
- let kept = [];
7978
- for (const e of items) {
7979
- if (!__ball_eq(e, value)) {
7980
- kept = (kept.push(e), kept);
7981
- }
8061
+ let index = items.indexOf(__ball_index(m, 'value'));
8062
+ if (__ball_lt(index, 0)) {
8063
+ return false;
7982
8064
  }
7983
- return this._ballSetOf(kept);
8065
+ items.splice(index, 1)[0];
8066
+ return true;
7984
8067
  }), ['set_contains']: ((i) => {
7985
8068
  const input = i;
7986
8069
  let m = this._stdAsMap(i);
@@ -949,7 +949,13 @@ export function createEngineSetup(mod: EngineModule) {
949
949
  _r('set_length', (i: any) => { const m = _m(i); const s = m['set'] ?? m['collection'] ?? new Set(); return s instanceof Set ? s.size : (Array.isArray(s) ? new Set(s).size : 0); });
950
950
  _r('set_from', (i: any) => { const m = _m(i); const l = m['list'] ?? m['collection'] ?? m['iterable'] ?? []; return new Set(Array.isArray(l) ? l : []); });
951
951
  _r('set_create', (i: any) => { const m = _m(i); return new Set(Array.isArray(m['elements'] ?? m['values'] ?? []) ? (m['elements'] ?? m['values'] ?? []) : []); });
952
- _r('set_add', (i: any) => { const m = _m(i); const s = m['set'] ?? m['collection']; const v = m['value'] ?? m['element']; if (s instanceof Set) { s.add(v); return true; } return false; });
952
+ // `true` ONLY on a fresh insert (issue #545). The old unconditional `true`
953
+ // made `set_add` on an element already present answer differently here than
954
+ // on every other engine — Dart's `Set.add` reports whether the element was
955
+ // newly inserted, and that is the one portable contract (conformance
956
+ // fixture 459_set_add_remove_bool). `set_remove`'s `Set.delete` already
957
+ // reports presence correctly.
958
+ _r('set_add', (i: any) => { const m = _m(i); const s = m['set'] ?? m['collection']; const v = m['value'] ?? m['element']; if (s instanceof Set) { if (s.has(v)) return false; s.add(v); return true; } return false; });
953
959
  _r('set_remove', (i: any) => { const m = _m(i); const s = m['set'] ?? m['collection']; const v = m['value'] ?? m['element']; return s instanceof Set ? s.delete(v) : false; });
954
960
  _r('set_add_all', (i: any) => { const m = _m(i); const s = m['set'] ?? m['collection']; const other = m['other'] ?? m['elements'] ?? []; if (s instanceof Set) { const items = Array.isArray(other) ? other : (other instanceof Set ? [...other] : []); for (const item of items) s.add(item); } return null; });
955
961
  _r('union', (i: any) => { const m = _m(i); const self = m['self'] ?? m['set'] ?? new Set(); const other = m['arg0'] ?? m['other'] ?? new Set(); const sA = self instanceof Set ? self : new Set(Array.isArray(self) ? self : []); const sB = other instanceof Set ? other : new Set(Array.isArray(other) ? other : []); return new Set([...sA, ...sB]); });