numbl 0.1.2 → 0.1.4

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/dist-cli/cli.js CHANGED
@@ -195,6 +195,179 @@ var kstr = (value) => {
195
195
  return "unknown";
196
196
  };
197
197
 
198
+ // src/numbl-core/native/lapack-bridge.ts
199
+ var NATIVE_ADDON_EXPECTED_VERSION = 1;
200
+ var _bridge = null;
201
+ function setLapackBridge(bridge) {
202
+ _bridge = bridge;
203
+ }
204
+ function getLapackBridge() {
205
+ return _bridge;
206
+ }
207
+
208
+ // src/numbl-core/runtime/constructors.ts
209
+ var RTV = {
210
+ num(value) {
211
+ return value;
212
+ },
213
+ tensor(data, shape, imag) {
214
+ const d = data instanceof FloatXArray ? data : new FloatXArray(data);
215
+ const im2 = imag ? imag instanceof FloatXArray ? imag : new FloatXArray(imag) : void 0;
216
+ const s = [...shape];
217
+ while (s.length > 2 && s[s.length - 1] === 1) s.pop();
218
+ return { kind: "tensor", data: d, imag: im2, shape: s, _rc: 1 };
219
+ },
220
+ /** Fast tensor constructor — data must be FloatXArray, shape already normalized (no trailing singletons). */
221
+ tensorRaw(data, shape) {
222
+ return { kind: "tensor", data, imag: void 0, shape, _rc: 1 };
223
+ },
224
+ /** Create a scalar tensor (1x1) */
225
+ scalar(value) {
226
+ return value;
227
+ },
228
+ /** Create a row vector [1 x n] */
229
+ row(data, imag) {
230
+ const im2 = imag ? new FloatXArray(imag) : void 0;
231
+ return {
232
+ kind: "tensor",
233
+ data: new FloatXArray(data),
234
+ imag: im2,
235
+ shape: [1, data.length],
236
+ _rc: 1
237
+ };
238
+ },
239
+ /** Create a column vector [n x 1] */
240
+ col(data, imag) {
241
+ const im2 = imag ? new FloatXArray(imag) : void 0;
242
+ return {
243
+ kind: "tensor",
244
+ data: new FloatXArray(data),
245
+ imag: im2,
246
+ shape: [data.length, 1],
247
+ _rc: 1
248
+ };
249
+ },
250
+ /** Create a matrix from row-major data */
251
+ matrix(rows, cols, data, imag) {
252
+ const d = data instanceof FloatXArray ? data : new FloatXArray(data);
253
+ const im2 = imag ? imag instanceof FloatXArray ? imag : new FloatXArray(imag) : void 0;
254
+ return { kind: "tensor", data: d, imag: im2, shape: [rows, cols], _rc: 1 };
255
+ },
256
+ string(value) {
257
+ return value;
258
+ },
259
+ char(value) {
260
+ return { kind: "char", value };
261
+ },
262
+ logical(value) {
263
+ return value;
264
+ },
265
+ cell(data, shape) {
266
+ return { kind: "cell", data, shape: [...shape], _rc: 1 };
267
+ },
268
+ struct(fields) {
269
+ const map = fields instanceof Map ? fields : new Map(Object.entries(fields));
270
+ return { kind: "struct", fields: map };
271
+ },
272
+ func(name, impl, captures = []) {
273
+ return { kind: "function", name, impl, captures };
274
+ },
275
+ classInstance(className, propertyNames, isHandleClass2 = false, defaults) {
276
+ const fields = /* @__PURE__ */ new Map();
277
+ for (const name of propertyNames) {
278
+ fields.set(
279
+ name,
280
+ defaults?.get(name) ?? RTV.tensor(new FloatXArray(0), [0, 0])
281
+ );
282
+ }
283
+ return {
284
+ kind: "class_instance",
285
+ className,
286
+ fields,
287
+ isHandleClass: isHandleClass2
288
+ };
289
+ },
290
+ complex(re2, im2) {
291
+ return { kind: "complex_number", re: re2, im: im2 };
292
+ },
293
+ dummyHandle() {
294
+ return { kind: "dummy_handle" };
295
+ },
296
+ structArray(fieldNames, elements) {
297
+ return { kind: "struct_array", fieldNames, elements };
298
+ },
299
+ sparseMatrix(m, n, ir, jc, pr, pi) {
300
+ return { kind: "sparse_matrix", m, n, ir, jc, pr, pi, _rc: 1 };
301
+ },
302
+ dictionary(entries, keyType, valueType) {
303
+ return {
304
+ kind: "dictionary",
305
+ entries: entries ?? /* @__PURE__ */ new Map(),
306
+ keyType,
307
+ valueType
308
+ };
309
+ }
310
+ };
311
+ var getItemTypeFromRuntimeValue = (value) => {
312
+ if (isRuntimeNumber(value)) {
313
+ return { kind: "Number" };
314
+ }
315
+ if (isRuntimeLogical(value)) {
316
+ return { kind: "Boolean" };
317
+ }
318
+ if (isRuntimeString(value)) {
319
+ return { kind: "String" };
320
+ }
321
+ switch (value.kind) {
322
+ case "complex_number":
323
+ return { kind: "ComplexNumber" };
324
+ case "char":
325
+ return { kind: "Char" };
326
+ case "tensor":
327
+ return {
328
+ kind: "Tensor",
329
+ isComplex: value.imag !== void 0,
330
+ isLogical: value._isLogical || void 0
331
+ };
332
+ case "cell":
333
+ return {
334
+ kind: "Cell",
335
+ elementType: value.data.length > 0 ? getItemTypeFromRuntimeValue(value.data[0]) : { kind: "Unknown" },
336
+ // length: value.shape.reduce((a, b) => a * b, 1),
337
+ length: "unknown"
338
+ // do not include length or we get too many jits
339
+ };
340
+ case "struct": {
341
+ const knownFields = {};
342
+ for (const [k, v] of value.fields) {
343
+ knownFields[k] = getItemTypeFromRuntimeValue(v);
344
+ }
345
+ return { kind: "Struct", knownFields };
346
+ }
347
+ case "function":
348
+ return {
349
+ kind: "Function",
350
+ params: [],
351
+ returns: { kind: "Unknown" }
352
+ };
353
+ case "class_instance":
354
+ return {
355
+ kind: "ClassInstance",
356
+ className: value.className
357
+ };
358
+ case "dummy_handle":
359
+ return { kind: "DummyHandle" };
360
+ case "struct_array":
361
+ return { kind: "Unknown" };
362
+ case "sparse_matrix":
363
+ return { kind: "SparseMatrix", isComplex: value.pi !== void 0 };
364
+ case "dictionary":
365
+ return { kind: "Dictionary" };
366
+ default:
367
+ return { kind: "Unknown" };
368
+ }
369
+ };
370
+
198
371
  // src/numbl-core/interpreter/jit/jitTypes.ts
199
372
  function signFromNumber(v) {
200
373
  if (v > 0) return "positive";
@@ -637,169 +810,6 @@ function extractSnippet(source, offset, contextLines = 2) {
637
810
  return snippetLines.join("\n");
638
811
  }
639
812
 
640
- // src/numbl-core/runtime/constructors.ts
641
- var RTV = {
642
- num(value) {
643
- return value;
644
- },
645
- tensor(data, shape, imag) {
646
- const d = data instanceof FloatXArray ? data : new FloatXArray(data);
647
- const im2 = imag ? imag instanceof FloatXArray ? imag : new FloatXArray(imag) : void 0;
648
- const s = [...shape];
649
- while (s.length > 2 && s[s.length - 1] === 1) s.pop();
650
- return { kind: "tensor", data: d, imag: im2, shape: s, _rc: 1 };
651
- },
652
- /** Fast tensor constructor — data must be FloatXArray, shape already normalized (no trailing singletons). */
653
- tensorRaw(data, shape) {
654
- return { kind: "tensor", data, imag: void 0, shape, _rc: 1 };
655
- },
656
- /** Create a scalar tensor (1x1) */
657
- scalar(value) {
658
- return value;
659
- },
660
- /** Create a row vector [1 x n] */
661
- row(data, imag) {
662
- const im2 = imag ? new FloatXArray(imag) : void 0;
663
- return {
664
- kind: "tensor",
665
- data: new FloatXArray(data),
666
- imag: im2,
667
- shape: [1, data.length],
668
- _rc: 1
669
- };
670
- },
671
- /** Create a column vector [n x 1] */
672
- col(data, imag) {
673
- const im2 = imag ? new FloatXArray(imag) : void 0;
674
- return {
675
- kind: "tensor",
676
- data: new FloatXArray(data),
677
- imag: im2,
678
- shape: [data.length, 1],
679
- _rc: 1
680
- };
681
- },
682
- /** Create a matrix from row-major data */
683
- matrix(rows, cols, data, imag) {
684
- const d = data instanceof FloatXArray ? data : new FloatXArray(data);
685
- const im2 = imag ? imag instanceof FloatXArray ? imag : new FloatXArray(imag) : void 0;
686
- return { kind: "tensor", data: d, imag: im2, shape: [rows, cols], _rc: 1 };
687
- },
688
- string(value) {
689
- return value;
690
- },
691
- char(value) {
692
- return { kind: "char", value };
693
- },
694
- logical(value) {
695
- return value;
696
- },
697
- cell(data, shape) {
698
- return { kind: "cell", data, shape: [...shape], _rc: 1 };
699
- },
700
- struct(fields) {
701
- const map = fields instanceof Map ? fields : new Map(Object.entries(fields));
702
- return { kind: "struct", fields: map };
703
- },
704
- func(name, impl, captures = []) {
705
- return { kind: "function", name, impl, captures };
706
- },
707
- classInstance(className, propertyNames, isHandleClass2 = false, defaults) {
708
- const fields = /* @__PURE__ */ new Map();
709
- for (const name of propertyNames) {
710
- fields.set(
711
- name,
712
- defaults?.get(name) ?? RTV.tensor(new FloatXArray(0), [0, 0])
713
- );
714
- }
715
- return {
716
- kind: "class_instance",
717
- className,
718
- fields,
719
- isHandleClass: isHandleClass2
720
- };
721
- },
722
- complex(re2, im2) {
723
- return { kind: "complex_number", re: re2, im: im2 };
724
- },
725
- dummyHandle() {
726
- return { kind: "dummy_handle" };
727
- },
728
- structArray(fieldNames, elements) {
729
- return { kind: "struct_array", fieldNames, elements };
730
- },
731
- sparseMatrix(m, n, ir, jc, pr, pi) {
732
- return { kind: "sparse_matrix", m, n, ir, jc, pr, pi, _rc: 1 };
733
- },
734
- dictionary(entries, keyType, valueType) {
735
- return {
736
- kind: "dictionary",
737
- entries: entries ?? /* @__PURE__ */ new Map(),
738
- keyType,
739
- valueType
740
- };
741
- }
742
- };
743
- var getItemTypeFromRuntimeValue = (value) => {
744
- if (isRuntimeNumber(value)) {
745
- return { kind: "Number" };
746
- }
747
- if (isRuntimeLogical(value)) {
748
- return { kind: "Boolean" };
749
- }
750
- if (isRuntimeString(value)) {
751
- return { kind: "String" };
752
- }
753
- switch (value.kind) {
754
- case "complex_number":
755
- return { kind: "ComplexNumber" };
756
- case "char":
757
- return { kind: "Char" };
758
- case "tensor":
759
- return {
760
- kind: "Tensor",
761
- isComplex: value.imag !== void 0,
762
- isLogical: value._isLogical || void 0
763
- };
764
- case "cell":
765
- return {
766
- kind: "Cell",
767
- elementType: value.data.length > 0 ? getItemTypeFromRuntimeValue(value.data[0]) : { kind: "Unknown" },
768
- // length: value.shape.reduce((a, b) => a * b, 1),
769
- length: "unknown"
770
- // do not include length or we get too many jits
771
- };
772
- case "struct": {
773
- const knownFields = {};
774
- for (const [k, v] of value.fields) {
775
- knownFields[k] = getItemTypeFromRuntimeValue(v);
776
- }
777
- return { kind: "Struct", knownFields };
778
- }
779
- case "function":
780
- return {
781
- kind: "Function",
782
- params: [],
783
- returns: { kind: "Unknown" }
784
- };
785
- case "class_instance":
786
- return {
787
- kind: "ClassInstance",
788
- className: value.className
789
- };
790
- case "dummy_handle":
791
- return { kind: "DummyHandle" };
792
- case "struct_array":
793
- return { kind: "Unknown" };
794
- case "sparse_matrix":
795
- return { kind: "SparseMatrix", isComplex: value.pi !== void 0 };
796
- case "dictionary":
797
- return { kind: "Dictionary" };
798
- default:
799
- return { kind: "Unknown" };
800
- }
801
- };
802
-
803
813
  // src/numbl-core/runtime/utils.ts
804
814
  function tensorSize2D(t) {
805
815
  const s = t.shape;
@@ -1718,6 +1728,28 @@ function binaryNumberOnly(argTypes) {
1718
1728
  return null;
1719
1729
  return [{ kind: "number" }];
1720
1730
  }
1731
+ var nativeUnaryOpCode = /* @__PURE__ */ new Map([
1732
+ [Math.exp, 0],
1733
+ [Math.log, 1],
1734
+ [Math.log2, 2],
1735
+ [Math.log10, 3],
1736
+ [Math.sqrt, 4],
1737
+ [Math.abs, 5],
1738
+ [Math.floor, 6],
1739
+ [Math.ceil, 7],
1740
+ [Math.round, 8],
1741
+ [Math.trunc, 9],
1742
+ [Math.sin, 10],
1743
+ [Math.cos, 11],
1744
+ [Math.tan, 12],
1745
+ [Math.asin, 13],
1746
+ [Math.acos, 14],
1747
+ [Math.atan, 15],
1748
+ [Math.sinh, 16],
1749
+ [Math.cosh, 17],
1750
+ [Math.tanh, 18],
1751
+ [Math.sign, 19]
1752
+ ]);
1721
1753
  function applyUnaryElemwise(v, realFn, complexFn, name) {
1722
1754
  if (isRuntimeSparseMatrix(v))
1723
1755
  return applyUnaryElemwise(sparseToDense(v), realFn, complexFn, name);
@@ -1730,6 +1762,14 @@ function applyUnaryElemwise(v, realFn, complexFn, name) {
1730
1762
  if (isRuntimeTensor(v)) {
1731
1763
  const n = v.data.length;
1732
1764
  if (!v.imag) {
1765
+ const opCode = nativeUnaryOpCode.get(realFn);
1766
+ if (opCode !== void 0) {
1767
+ const bridge = getLapackBridge();
1768
+ if (bridge?.unaryElemwise && v.data instanceof Float64Array) {
1769
+ const result = bridge.unaryElemwise(v.data, opCode);
1770
+ return RTV.tensorRaw(result, v.shape.slice());
1771
+ }
1772
+ }
1733
1773
  const out = new FloatXArray(n);
1734
1774
  for (let i = 0; i < n; i++) out[i] = realFn(v.data[i]);
1735
1775
  return makeTensor(out, void 0, v.shape.slice());
@@ -3618,16 +3658,6 @@ function toString(v) {
3618
3658
  }
3619
3659
  }
3620
3660
 
3621
- // src/numbl-core/native/lapack-bridge.ts
3622
- var NATIVE_ADDON_EXPECTED_VERSION = 1;
3623
- var _bridge = null;
3624
- function setLapackBridge(bridge) {
3625
- _bridge = bridge;
3626
- }
3627
- function getLapackBridge() {
3628
- return _bridge;
3629
- }
3630
-
3631
3661
  // src/ts-lapack/src/utils/xerbla.ts
3632
3662
  function xerbla(srname, info) {
3633
3663
  throw new Error(
@@ -20268,6 +20298,7 @@ function extractTensorElement(base, i) {
20268
20298
  const im2 = base.imag[i];
20269
20299
  return im2 === 0 ? RTV.num(base.data[i]) : RTV.complex(base.data[i], im2);
20270
20300
  }
20301
+ if (base._isLogical === true) return base.data[i] !== 0;
20271
20302
  return RTV.num(base.data[i]);
20272
20303
  }
20273
20304
  function resolveIndex(idx, dimSize, boundsLimit = dimSize) {
@@ -20321,17 +20352,35 @@ function growTensor2D(base, newRows, newCols) {
20321
20352
  }
20322
20353
  function assignSlice(base, rowIndices, colIndices, rhs, curRows) {
20323
20354
  if (isRuntimeTensor(rhs)) {
20355
+ const nR = rowIndices.length;
20356
+ const nC = colIndices.length;
20324
20357
  const [rhsRows, rhsCols] = tensorSize2D(rhs);
20325
- if (rhsRows !== rowIndices.length || rhsCols !== colIndices.length) {
20358
+ const shapeMatches = rhsRows === nR && rhsCols === nC;
20359
+ const sliceIsVector = nR === 1 || nC === 1;
20360
+ const rhsIsVector = rhsRows === 1 || rhsCols === 1;
20361
+ const countMatches = rhs.data.length === nR * nC;
20362
+ if (!shapeMatches && !(sliceIsVector && rhsIsVector && countMatches)) {
20326
20363
  throw new RuntimeError("Subscripted assignment dimension mismatch");
20327
20364
  }
20328
20365
  if (rhs.imag || base.imag) ensureImag(base);
20329
- for (let ri = 0; ri < rowIndices.length; ri++) {
20330
- for (let ci = 0; ci < colIndices.length; ci++) {
20331
- const dstLi = colMajorIndex(rowIndices[ri], colIndices[ci], curRows);
20332
- const srcLi = colMajorIndex(ri, ci, rhsRows);
20333
- base.data[dstLi] = rhs.data[srcLi];
20334
- if (base.imag) base.imag[dstLi] = rhs.imag ? rhs.imag[srcLi] : 0;
20366
+ if (shapeMatches) {
20367
+ for (let ri = 0; ri < nR; ri++) {
20368
+ for (let ci = 0; ci < nC; ci++) {
20369
+ const dstLi = colMajorIndex(rowIndices[ri], colIndices[ci], curRows);
20370
+ const srcLi = colMajorIndex(ri, ci, rhsRows);
20371
+ base.data[dstLi] = rhs.data[srcLi];
20372
+ if (base.imag) base.imag[dstLi] = rhs.imag ? rhs.imag[srcLi] : 0;
20373
+ }
20374
+ }
20375
+ } else {
20376
+ let k = 0;
20377
+ for (let ci = 0; ci < nC; ci++) {
20378
+ for (let ri = 0; ri < nR; ri++) {
20379
+ const dstLi = colMajorIndex(rowIndices[ri], colIndices[ci], curRows);
20380
+ base.data[dstLi] = rhs.data[k];
20381
+ if (base.imag) base.imag[dstLi] = rhs.imag ? rhs.imag[k] : 0;
20382
+ k++;
20383
+ }
20335
20384
  }
20336
20385
  }
20337
20386
  } else {
@@ -20668,6 +20717,23 @@ function indexIntoScalar(base, indices) {
20668
20717
  return RTV.tensor(out, [1, count]);
20669
20718
  }
20670
20719
  }
20720
+ if (indices.length === 1 && isRuntimeTensor(indices[0])) {
20721
+ const idx = indices[0];
20722
+ for (let i = 0; i < idx.data.length; i++) {
20723
+ const k = Math.round(idx.data[i]);
20724
+ if (k !== 1) throw new RuntimeError("Index exceeds array bounds");
20725
+ }
20726
+ const n = idx.data.length;
20727
+ const scalarRe = isRuntimeNumber(base) ? base : base.re;
20728
+ const data = new FloatXArray(n);
20729
+ data.fill(scalarRe);
20730
+ if (isRuntimeComplexNumber(base) && base.im !== 0) {
20731
+ const im2 = new FloatXArray(n);
20732
+ im2.fill(base.im);
20733
+ return RTV.tensor(data, [...idx.shape], im2);
20734
+ }
20735
+ return RTV.tensor(data, [...idx.shape]);
20736
+ }
20671
20737
  for (const idx of indices) {
20672
20738
  if (isColonIndex(idx)) continue;
20673
20739
  const i = toNumber(idx);
@@ -20679,6 +20745,22 @@ function indexIntoTensor(base, indices) {
20679
20745
  if (indices.length === 1) {
20680
20746
  return indexIntoTensor1D(base, indices[0]);
20681
20747
  }
20748
+ if (base.shape.length > indices.length) {
20749
+ const collapsedShape = [];
20750
+ for (let d = 0; d < indices.length - 1; d++) {
20751
+ collapsedShape.push(base.shape[d]);
20752
+ }
20753
+ let tail = 1;
20754
+ for (let d = indices.length - 1; d < base.shape.length; d++) {
20755
+ tail *= base.shape[d];
20756
+ }
20757
+ collapsedShape.push(tail);
20758
+ const view = { ...base, shape: collapsedShape };
20759
+ if (indices.length === 2) {
20760
+ return indexIntoTensor2D(view, indices[0], indices[1]);
20761
+ }
20762
+ return indexIntoTensorND(view, indices);
20763
+ }
20682
20764
  if (indices.length === 2) {
20683
20765
  return indexIntoTensor2D(base, indices[0], indices[1]);
20684
20766
  }
@@ -20707,6 +20789,11 @@ function indexIntoTensor1D(base, idx) {
20707
20789
  }
20708
20790
  function indexIntoTensor2D(base, rowIdx, colIdx) {
20709
20791
  const [rows, cols] = tensorSize2D(base);
20792
+ const baseLogical = base._isLogical === true;
20793
+ const markLogical = (t) => {
20794
+ if (baseLogical && isRuntimeTensor(t)) t._isLogical = true;
20795
+ return t;
20796
+ };
20710
20797
  if (isRuntimeNumber(rowIdx) && isColonIndex(colIdx)) {
20711
20798
  const r = Math.round(rowIdx) - 1;
20712
20799
  if (r < 0 || r >= rows)
@@ -20717,7 +20804,7 @@ function indexIntoTensor2D(base, rowIdx, colIdx) {
20717
20804
  resultData2[ci] = base.data[r + ci * rows];
20718
20805
  if (resultImag2 && base.imag) resultImag2[ci] = base.imag[r + ci * rows];
20719
20806
  }
20720
- return RTV.tensor(resultData2, [1, cols], resultImag2);
20807
+ return markLogical(RTV.tensor(resultData2, [1, cols], resultImag2));
20721
20808
  }
20722
20809
  if (isColonIndex(rowIdx) && isRuntimeNumber(colIdx)) {
20723
20810
  const c = Math.round(colIdx) - 1;
@@ -20729,7 +20816,7 @@ function indexIntoTensor2D(base, rowIdx, colIdx) {
20729
20816
  const resultImag2 = base.imag ? new FloatXArray(rows) : void 0;
20730
20817
  if (resultImag2 && base.imag)
20731
20818
  for (let ri = 0; ri < rows; ri++) resultImag2[ri] = base.imag[offset + ri];
20732
- return RTV.tensor(resultData2, [rows, 1], resultImag2);
20819
+ return markLogical(RTV.tensor(resultData2, [rows, 1], resultImag2));
20733
20820
  }
20734
20821
  const rowIdxArr = resolveIndex(rowIdx, rows);
20735
20822
  const colIdxArr = resolveIndex(colIdx, cols);
@@ -20751,7 +20838,7 @@ function indexIntoTensor2D(base, rowIdx, colIdx) {
20751
20838
  }
20752
20839
  }
20753
20840
  }
20754
- return RTV.tensor(resultData, [numR, numC], resultImag);
20841
+ return markLogical(RTV.tensor(resultData, [numR, numC], resultImag));
20755
20842
  }
20756
20843
  function indexIntoTensorND(base, indices) {
20757
20844
  const shape = base.shape;
@@ -20799,7 +20886,13 @@ function indexIntoTensorND(base, indices) {
20799
20886
  subs[d] = 0;
20800
20887
  }
20801
20888
  }
20802
- return RTV.tensor(resultData, resultShape, resultImag);
20889
+ const result = RTV.tensor(
20890
+ resultData,
20891
+ resultShape,
20892
+ resultImag
20893
+ );
20894
+ if (base._isLogical === true) result._isLogical = true;
20895
+ return result;
20803
20896
  }
20804
20897
  function indexIntoCell(base, indices) {
20805
20898
  if (indices.length === 1) {
@@ -20964,6 +21057,7 @@ function indexIntoLogical(base, indices) {
20964
21057
  return base;
20965
21058
  }
20966
21059
  function indexIntoTensorWithTensor(base, idx) {
21060
+ const baseLogical = base._isLogical === true;
20967
21061
  if (idx._isLogical) {
20968
21062
  const selected = [];
20969
21063
  const selectedIm = [];
@@ -20977,12 +21071,19 @@ function indexIntoTensorWithTensor(base, idx) {
20977
21071
  if (selected.length === 1) {
20978
21072
  if (hasImag2 && selectedIm[0] !== 0)
20979
21073
  return RTV.complex(selected[0], selectedIm[0]);
21074
+ if (baseLogical) return selected[0] !== 0;
20980
21075
  return RTV.num(selected[0]);
20981
21076
  }
20982
21077
  const imOut2 = hasImag2 && selectedIm.some((x) => x !== 0) ? new FloatXArray(selectedIm) : void 0;
20983
21078
  const isRow = base.shape.length === 2 && base.shape[0] === 1;
20984
21079
  const outShape2 = isRow ? [1, selected.length] : [selected.length, 1];
20985
- return RTV.tensor(new FloatXArray(selected), outShape2, imOut2);
21080
+ const result2 = RTV.tensor(
21081
+ new FloatXArray(selected),
21082
+ outShape2,
21083
+ imOut2
21084
+ );
21085
+ if (baseLogical) result2._isLogical = true;
21086
+ return result2;
20986
21087
  }
20987
21088
  const resultData = [];
20988
21089
  const hasImag = base.imag !== void 0;
@@ -20998,7 +21099,13 @@ function indexIntoTensorWithTensor(base, idx) {
20998
21099
  const baseIsVector = base.shape.length <= 2 && (base.shape[0] === 1 || base.shape[1] === 1 || base.shape.length === 1);
20999
21100
  const outShape = idxIs0x0 ? [0, 0] : baseIsVector ? base.shape[0] === 1 ? [1, resultData.length] : [resultData.length, 1] : idx.shape;
21000
21101
  const imOut = hasImag && imIndices.some((x) => x !== 0) ? new FloatXArray(imIndices) : void 0;
21001
- return RTV.tensor(new FloatXArray(resultData), outShape, imOut);
21102
+ const result = RTV.tensor(
21103
+ new FloatXArray(resultData),
21104
+ outShape,
21105
+ imOut
21106
+ );
21107
+ if (baseLogical) result._isLogical = true;
21108
+ return result;
21002
21109
  }
21003
21110
  function indexIntoRTValue(base, indices) {
21004
21111
  if (isRuntimeNumber(base) || isRuntimeComplexNumber(base)) {
@@ -21348,10 +21455,18 @@ function storeIntoTensor2D(base, indices, rhs) {
21348
21455
  return storeIntoTensorColonCol(base, indices[0], rhs, rows, cols);
21349
21456
  }
21350
21457
  if (rowIsTensor || colIsTensor) {
21351
- const rowIndices = resolveIndex(indices[0], rows, 0);
21352
- const colIndices = resolveIndex(indices[1], cols, 0);
21353
- const maxRow = rowIndices.length > 0 ? Math.max(...rowIndices) + 1 : rows;
21354
- const maxCol = colIndices.length > 0 ? Math.max(...colIndices) + 1 : cols;
21458
+ const isEmpty = base.data.length === 0;
21459
+ let effectiveCols = cols;
21460
+ let effectiveRows = rows;
21461
+ if (isEmpty && isRuntimeTensor(rhs)) {
21462
+ const [rhsRowsG, rhsColsG] = tensorSize2D(rhs);
21463
+ if (rowIsColon && !colIsColon) effectiveRows = rhsRowsG;
21464
+ if (colIsColon && !rowIsColon) effectiveCols = rhsColsG;
21465
+ }
21466
+ const rowIndices = rowIsColon ? Array.from({ length: effectiveRows }, (_, i) => i) : resolveIndex(indices[0], rows, 0);
21467
+ const colIndices = colIsColon ? Array.from({ length: effectiveCols }, (_, i) => i) : resolveIndex(indices[1], cols, 0);
21468
+ const maxRow = rowIndices.length > 0 ? Math.max(...rowIndices) + 1 : effectiveRows;
21469
+ const maxCol = colIndices.length > 0 ? Math.max(...colIndices) + 1 : effectiveCols;
21355
21470
  base = growTensor2D(base, maxRow, maxCol);
21356
21471
  const [curRows] = tensorSize2D(base);
21357
21472
  assignSlice(base, rowIndices, colIndices, rhs, curRows);
@@ -21779,6 +21894,9 @@ function horzcat(...values) {
21779
21894
  if (values.some((v) => isRuntimeCell(v))) {
21780
21895
  return cellCatAlongDim(values, 1);
21781
21896
  }
21897
+ if (values.some((v) => isRuntimeStruct(v) || isRuntimeStructArray(v))) {
21898
+ return structCat(values);
21899
+ }
21782
21900
  return catAlongDim(values, 1);
21783
21901
  }
21784
21902
  function vertcat(...values) {
@@ -21790,8 +21908,47 @@ function vertcat(...values) {
21790
21908
  if (values.some((v) => isRuntimeCell(v))) {
21791
21909
  return cellCatAlongDim(values, 0);
21792
21910
  }
21911
+ if (values.some((v) => isRuntimeStruct(v) || isRuntimeStructArray(v))) {
21912
+ return structCat(values);
21913
+ }
21793
21914
  return catAlongDim(values, 0);
21794
21915
  }
21916
+ function structCat(values) {
21917
+ const elements = [];
21918
+ let fieldNames = null;
21919
+ for (const v of values) {
21920
+ if (isRuntimeStruct(v)) {
21921
+ const keys = Array.from(v.fields.keys());
21922
+ if (fieldNames === null) fieldNames = keys;
21923
+ else if (!arraysEqual(fieldNames, keys)) {
21924
+ throw new RuntimeError(
21925
+ "Cannot concatenate structs with different field names"
21926
+ );
21927
+ }
21928
+ elements.push(v);
21929
+ } else if (isRuntimeStructArray(v)) {
21930
+ if (fieldNames === null) fieldNames = [...v.fieldNames];
21931
+ else if (!arraysEqual(fieldNames, v.fieldNames)) {
21932
+ throw new RuntimeError(
21933
+ "Cannot concatenate struct arrays with different field names"
21934
+ );
21935
+ }
21936
+ for (const e of v.elements) elements.push(e);
21937
+ } else {
21938
+ if (isRuntimeTensor(v) && v.data.length === 0 && v.shape.every((d) => d === 0)) {
21939
+ continue;
21940
+ }
21941
+ throw new RuntimeError(`Cannot concatenate ${kstr(v)} into struct`);
21942
+ }
21943
+ }
21944
+ if (fieldNames === null) fieldNames = [];
21945
+ return RTV.structArray(fieldNames, elements);
21946
+ }
21947
+ function arraysEqual(a, b) {
21948
+ if (a.length !== b.length) return false;
21949
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
21950
+ return true;
21951
+ }
21795
21952
  function toSparseForCat(v) {
21796
21953
  if (isRuntimeSparseMatrix(v)) return v;
21797
21954
  if (isRuntimeNumber(v)) {
@@ -22286,6 +22443,258 @@ function coerceToTensor(v, name) {
22286
22443
  throw new RuntimeError(`${name}: argument must be numeric`);
22287
22444
  }
22288
22445
 
22446
+ // src/numbl-core/helpers/string.ts
22447
+ function numStr(n) {
22448
+ if (n === Infinity) return "Inf";
22449
+ if (n === -Infinity) return "-Inf";
22450
+ if (isNaN(n)) return "NaN";
22451
+ if (n === 0) return "0";
22452
+ const prec = 5;
22453
+ const exp = Math.floor(Math.log10(Math.abs(n)));
22454
+ let s;
22455
+ if (exp < -4 || exp >= prec) {
22456
+ s = n.toExponential(prec - 1);
22457
+ const ePos = s.indexOf("e");
22458
+ let mantissa = s.slice(0, ePos);
22459
+ const expPart0 = s.slice(ePos);
22460
+ if (mantissa.includes(".")) mantissa = mantissa.replace(/\.?0+$/, "");
22461
+ const expPart = expPart0.replace(/([eE][+-])(\d)$/, "$10$2");
22462
+ s = mantissa + expPart;
22463
+ } else {
22464
+ if (Number.isInteger(n)) return String(n);
22465
+ s = n.toPrecision(prec);
22466
+ if (s.includes(".")) s = s.replace(/\.?0+$/, "");
22467
+ }
22468
+ return s;
22469
+ }
22470
+ function num2strScalar(n) {
22471
+ if (n === Infinity) return "Inf";
22472
+ if (n === -Infinity) return "-Inf";
22473
+ if (isNaN(n)) return "NaN";
22474
+ if (n === 0) return "0";
22475
+ if (Number.isInteger(n)) return String(n);
22476
+ const prec = 5;
22477
+ const exp = Math.floor(Math.log10(Math.abs(n)));
22478
+ let s;
22479
+ if (exp < -4 || exp >= prec) {
22480
+ s = n.toExponential(prec - 1);
22481
+ const ePos = s.indexOf("e");
22482
+ let mantissa = s.slice(0, ePos);
22483
+ const expPart0 = s.slice(ePos);
22484
+ if (mantissa.includes(".")) mantissa = mantissa.replace(/\.?0+$/, "");
22485
+ const expPart = expPart0.replace(/([eE][+-])(\d)$/, "$10$2");
22486
+ s = mantissa + expPart;
22487
+ } else {
22488
+ s = n.toPrecision(prec);
22489
+ if (s.includes(".")) s = s.replace(/\.?0+$/, "");
22490
+ }
22491
+ return s;
22492
+ }
22493
+ function applyWidth(spec, str) {
22494
+ const m = spec.match(/^%([-+ #]*)0?(\d+)?/);
22495
+ if (!m) return str;
22496
+ const explicitFlags = m[1] || "";
22497
+ const leftAlign = explicitFlags.includes("-");
22498
+ const afterPercent = spec.slice(1);
22499
+ const flagAndWidth = afterPercent.match(/^([-+ #]*)(0?)(\d+)?/);
22500
+ const zeroFlag = flagAndWidth ? flagAndWidth[2] === "0" : false;
22501
+ const width = flagAndWidth && flagAndWidth[3] ? parseInt(flagAndWidth[3]) : 0;
22502
+ if (width <= str.length) return str;
22503
+ const zeroPad = !leftAlign && zeroFlag;
22504
+ const padLen = width - str.length;
22505
+ if (leftAlign) return str + " ".repeat(padLen);
22506
+ if (zeroPad) {
22507
+ if (str[0] === "-" || str[0] === "+") {
22508
+ return str[0] + "0".repeat(padLen) + str.slice(1);
22509
+ }
22510
+ return "0".repeat(padLen) + str;
22511
+ }
22512
+ return " ".repeat(padLen) + str;
22513
+ }
22514
+ function sprintfFormat(fmt, args) {
22515
+ const flatArgs = [];
22516
+ for (const arg of args) {
22517
+ if (isRuntimeTensor(arg)) {
22518
+ for (let k = 0; k < arg.data.length; k++) {
22519
+ flatArgs.push(arg.data[k]);
22520
+ }
22521
+ } else {
22522
+ flatArgs.push(arg);
22523
+ }
22524
+ }
22525
+ let result = "";
22526
+ let argIdx = 0;
22527
+ do {
22528
+ const startArgIdx = argIdx;
22529
+ let outOfArgs = false;
22530
+ let i = 0;
22531
+ while (i < fmt.length && !outOfArgs) {
22532
+ if (fmt[i] === "%" && i + 1 < fmt.length) {
22533
+ i++;
22534
+ let spec = "%";
22535
+ while (i < fmt.length && !"dfigeEsoxXuc%".includes(fmt[i])) {
22536
+ if (fmt[i] === "*") {
22537
+ if (argIdx >= flatArgs.length) {
22538
+ outOfArgs = true;
22539
+ break;
22540
+ }
22541
+ spec += String(Math.round(toNumber(flatArgs[argIdx++])));
22542
+ i++;
22543
+ } else {
22544
+ spec += fmt[i];
22545
+ i++;
22546
+ }
22547
+ }
22548
+ if (outOfArgs) break;
22549
+ if (i < fmt.length) {
22550
+ const ch = fmt[i];
22551
+ i++;
22552
+ if (ch === "%") {
22553
+ result += "%";
22554
+ } else if (argIdx >= flatArgs.length) {
22555
+ outOfArgs = true;
22556
+ } else if (ch === "d" || ch === "i" || ch === "u") {
22557
+ const raw = toNumber(flatArgs[argIdx++]);
22558
+ const isInt = Number.isInteger(raw);
22559
+ const canPrintAsInt = ch === "u" ? isInt && raw >= 0 : isInt;
22560
+ if (!canPrintAsInt) {
22561
+ let eStr = raw.toExponential(6);
22562
+ eStr = eStr.replace(/e([+-])(\d)$/, "e$10$2");
22563
+ result += applyWidth(spec, eStr);
22564
+ } else {
22565
+ const n = raw;
22566
+ const flags = spec.slice(1);
22567
+ const hasPlus = flags.includes("+");
22568
+ const leftAlign = flags.includes("-");
22569
+ const widthMatch = spec.match(/^%[^0-9]*(\d+)/);
22570
+ const width = widthMatch ? parseInt(widthMatch[1]) : 0;
22571
+ const zeroPad = !leftAlign && /^[-+ ]*0/.test(spec.slice(1));
22572
+ const s = String(Math.abs(n));
22573
+ const sign = n < 0 ? "-" : hasPlus ? "+" : "";
22574
+ if (width > 0) {
22575
+ const padChar = zeroPad ? "0" : " ";
22576
+ const padLen = Math.max(0, width - sign.length - s.length);
22577
+ const pad = padChar.repeat(padLen);
22578
+ result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign + pad + s : pad + sign + s;
22579
+ } else {
22580
+ result += sign + s;
22581
+ }
22582
+ }
22583
+ } else if (ch === "f") {
22584
+ const n = toNumber(flatArgs[argIdx++]);
22585
+ if (!isFinite(n) || isNaN(n)) {
22586
+ result += applyWidth(spec, numStr(n));
22587
+ } else {
22588
+ const fFlags = spec.slice(1);
22589
+ const fHasPlus = fFlags.includes("+");
22590
+ const precMatch = spec.match(/\.(\d+)/);
22591
+ const prec = precMatch ? parseInt(precMatch[1]) : 6;
22592
+ const formatted = n.toFixed(prec);
22593
+ const fSign = n < 0 ? "" : fHasPlus ? "+" : "";
22594
+ result += applyWidth(spec, fSign + formatted);
22595
+ }
22596
+ } else if (ch === "e" || ch === "E") {
22597
+ const n = toNumber(flatArgs[argIdx++]);
22598
+ if (!isFinite(n) || isNaN(n)) {
22599
+ result += applyWidth(spec, numStr(n));
22600
+ } else {
22601
+ const precMatch = spec.match(/\.(\d+)/);
22602
+ const prec = precMatch ? parseInt(precMatch[1]) : 6;
22603
+ let eStr = n.toExponential(prec);
22604
+ eStr = eStr.replace(/e([+-])(\d)$/, "e$10$2");
22605
+ if (ch === "E") eStr = eStr.toUpperCase();
22606
+ result += applyWidth(spec, eStr);
22607
+ }
22608
+ } else if (ch === "x" || ch === "X") {
22609
+ const n = Math.round(toNumber(flatArgs[argIdx++]));
22610
+ let s = Math.abs(n).toString(16);
22611
+ if (ch === "X") s = s.toUpperCase();
22612
+ result += applyWidth(spec, s);
22613
+ } else if (ch === "o") {
22614
+ const n = Math.round(toNumber(flatArgs[argIdx++]));
22615
+ result += applyWidth(spec, Math.abs(n).toString(8));
22616
+ } else if (ch === "g" || ch === "G") {
22617
+ const gVal = toNumber(flatArgs[argIdx++]);
22618
+ if (!isFinite(gVal) || isNaN(gVal)) {
22619
+ result += applyWidth(spec, numStr(gVal));
22620
+ } else {
22621
+ const precMatch = spec.match(/\.(\d+)/);
22622
+ const gPrec = precMatch ? parseInt(precMatch[1]) : 6;
22623
+ let gStr;
22624
+ if (gVal === 0) {
22625
+ gStr = "0";
22626
+ } else {
22627
+ const exp = Math.floor(Math.log10(Math.abs(gVal)));
22628
+ if (exp < -4 || exp >= gPrec) {
22629
+ gStr = gVal.toExponential(gPrec - 1);
22630
+ const ePos = gStr.indexOf("e");
22631
+ let mantissa = gStr.slice(0, ePos);
22632
+ let expPart = gStr.slice(ePos);
22633
+ if (mantissa.includes(".")) {
22634
+ mantissa = mantissa.replace(/\.?0+$/, "");
22635
+ }
22636
+ expPart = expPart.replace(/e([+-])(\d)$/, "e$10$2");
22637
+ gStr = mantissa + expPart;
22638
+ } else {
22639
+ gStr = gVal.toPrecision(gPrec);
22640
+ if (gStr.includes(".")) {
22641
+ gStr = gStr.replace(/\.?0+$/, "");
22642
+ }
22643
+ if (gStr.includes("e")) {
22644
+ gStr = String(parseFloat(gStr));
22645
+ }
22646
+ }
22647
+ }
22648
+ if (ch === "G") gStr = gStr.toUpperCase();
22649
+ result += applyWidth(spec, gStr);
22650
+ }
22651
+ } else if (ch === "s") {
22652
+ const sVal = toString(flatArgs[argIdx++]);
22653
+ const sFlags = spec.slice(1);
22654
+ const sLeftAlign = sFlags.includes("-");
22655
+ const sWidthMatch = spec.match(/^%[^0-9]*(\d+)/);
22656
+ const sWidth = sWidthMatch ? parseInt(sWidthMatch[1]) : 0;
22657
+ if (sWidth > sVal.length) {
22658
+ const sPad = " ".repeat(sWidth - sVal.length);
22659
+ result += sLeftAlign ? sVal + sPad : sPad + sVal;
22660
+ } else {
22661
+ result += sVal;
22662
+ }
22663
+ } else if (ch === "c") {
22664
+ result += String.fromCharCode(
22665
+ Math.round(toNumber(flatArgs[argIdx++]))
22666
+ );
22667
+ } else {
22668
+ result += spec + ch;
22669
+ argIdx++;
22670
+ }
22671
+ }
22672
+ } else if (fmt[i] === "\\" && i + 1 < fmt.length) {
22673
+ i++;
22674
+ switch (fmt[i]) {
22675
+ case "n":
22676
+ result += "\n";
22677
+ break;
22678
+ case "t":
22679
+ result += " ";
22680
+ break;
22681
+ case "\\":
22682
+ result += "\\";
22683
+ break;
22684
+ default:
22685
+ result += "\\" + fmt[i];
22686
+ }
22687
+ i++;
22688
+ } else {
22689
+ result += fmt[i];
22690
+ i++;
22691
+ }
22692
+ }
22693
+ if (argIdx === startArgIdx) break;
22694
+ } while (argIdx < flatArgs.length);
22695
+ return result;
22696
+ }
22697
+
22289
22698
  // src/numbl-core/helpers/arithmetic.ts
22290
22699
  function toComplex(v) {
22291
22700
  if (isRuntimeComplexNumber(v)) return { re: v.re, im: v.im };
@@ -22461,6 +22870,18 @@ function tryNativeElemwiseReal(at, bt, opCode) {
22461
22870
  );
22462
22871
  return RTV.tensorRaw(result, at.shape);
22463
22872
  }
22873
+ function tryNativeElemwiseScalar(scalar, tensor, opCode, scalarOnLeft) {
22874
+ if (tensor.imag) return null;
22875
+ const bridge = getLapackBridge();
22876
+ if (!bridge?.elemwiseScalar) return null;
22877
+ const result = bridge.elemwiseScalar(
22878
+ scalar,
22879
+ tensor.data,
22880
+ opCode,
22881
+ scalarOnLeft
22882
+ );
22883
+ return RTV.tensorRaw(result, tensor.shape);
22884
+ }
22464
22885
  function tensorElemwiseComplex(at, bt, opCode, jsOp) {
22465
22886
  const bridge = getLapackBridge();
22466
22887
  if (bridge?.elemwiseComplex) {
@@ -22501,7 +22922,26 @@ function tensorElemwiseComplex(at, bt, opCode, jsOp) {
22501
22922
  const isReal = resultIm.every((x) => x === 0);
22502
22923
  return RTV.tensor(resultRe, at.shape, isReal ? void 0 : resultIm);
22503
22924
  }
22925
+ function coerceToConcatString(v) {
22926
+ if (isRuntimeString(v)) return v;
22927
+ if (isRuntimeChar(v)) return v.value;
22928
+ if (isRuntimeLogical(v)) return v ? "true" : "false";
22929
+ if (isRuntimeNumber(v)) return num2strScalar(v);
22930
+ if (isRuntimeTensor(v) && v.data.length === 1 && !v.imag) {
22931
+ const x = v.data[0];
22932
+ if (v._isLogical === true) return x ? "true" : "false";
22933
+ return num2strScalar(x);
22934
+ }
22935
+ return null;
22936
+ }
22504
22937
  function mAdd(a, b) {
22938
+ if (isRuntimeString(a) || isRuntimeString(b)) {
22939
+ const aStr = coerceToConcatString(a);
22940
+ const bStr = coerceToConcatString(b);
22941
+ if (aStr !== null && bStr !== null) {
22942
+ return RTV.string(aStr + bStr);
22943
+ }
22944
+ }
22505
22945
  const m = matchSameShapeTensors(a, b);
22506
22946
  if (m) {
22507
22947
  const [at, bt] = m;
@@ -22531,6 +22971,13 @@ function mAdd(a, b) {
22531
22971
  im: aIm + bIm
22532
22972
  }));
22533
22973
  }
22974
+ if (isRuntimeNumber(a) && isRuntimeTensor(b)) {
22975
+ const nr = tryNativeElemwiseScalar(a, b, ELEMWISE_ADD, true);
22976
+ if (nr) return nr;
22977
+ } else if (isRuntimeTensor(a) && isRuntimeNumber(b)) {
22978
+ const nr = tryNativeElemwiseScalar(b, a, ELEMWISE_ADD, false);
22979
+ if (nr) return nr;
22980
+ }
22534
22981
  return binaryOp(a, b, (x, y) => x + y);
22535
22982
  }
22536
22983
  function mSub(a, b) {
@@ -22563,6 +23010,13 @@ function mSub(a, b) {
22563
23010
  im: aIm - bIm
22564
23011
  }));
22565
23012
  }
23013
+ if (isRuntimeNumber(a) && isRuntimeTensor(b)) {
23014
+ const nr = tryNativeElemwiseScalar(a, b, ELEMWISE_SUB, true);
23015
+ if (nr) return nr;
23016
+ } else if (isRuntimeTensor(a) && isRuntimeNumber(b)) {
23017
+ const nr = tryNativeElemwiseScalar(b, a, ELEMWISE_SUB, false);
23018
+ if (nr) return nr;
23019
+ }
22566
23020
  return binaryOp(a, b, (x, y) => x - y);
22567
23021
  }
22568
23022
  function mMul(a, b) {
@@ -22579,6 +23033,13 @@ function mMul(a, b) {
22579
23033
  im: aRe * bIm + aIm * bRe
22580
23034
  }));
22581
23035
  }
23036
+ if (isRuntimeNumber(a) && isRuntimeTensor(b)) {
23037
+ const nr = tryNativeElemwiseScalar(a, b, ELEMWISE_MUL, true);
23038
+ if (nr) return nr;
23039
+ } else if (isRuntimeTensor(a) && isRuntimeNumber(b)) {
23040
+ const nr = tryNativeElemwiseScalar(b, a, ELEMWISE_MUL, false);
23041
+ if (nr) return nr;
23042
+ }
22582
23043
  return binaryOp(a, b, (x, y) => x * y);
22583
23044
  }
22584
23045
  function mElemMul(a, b) {
@@ -22611,6 +23072,13 @@ function mElemMul(a, b) {
22611
23072
  im: aRe * bIm + aIm * bRe
22612
23073
  }));
22613
23074
  }
23075
+ if (isRuntimeNumber(a) && isRuntimeTensor(b)) {
23076
+ const nr = tryNativeElemwiseScalar(a, b, ELEMWISE_MUL, true);
23077
+ if (nr) return nr;
23078
+ } else if (isRuntimeTensor(a) && isRuntimeNumber(b)) {
23079
+ const nr = tryNativeElemwiseScalar(b, a, ELEMWISE_MUL, false);
23080
+ if (nr) return nr;
23081
+ }
22614
23082
  return binaryOp(a, b, (x, y) => x * y);
22615
23083
  }
22616
23084
  function mDiv(a, b) {
@@ -22649,6 +23117,13 @@ function mElemDiv(a, b) {
22649
23117
  if (isComplexOrMixed(a, b)) {
22650
23118
  return complexBinaryOp(a, b, complexDivide);
22651
23119
  }
23120
+ if (isRuntimeNumber(a) && isRuntimeTensor(b)) {
23121
+ const nr = tryNativeElemwiseScalar(a, b, ELEMWISE_DIV, true);
23122
+ if (nr) return nr;
23123
+ } else if (isRuntimeTensor(a) && isRuntimeNumber(b)) {
23124
+ const nr = tryNativeElemwiseScalar(b, a, ELEMWISE_DIV, false);
23125
+ if (nr) return nr;
23126
+ }
22652
23127
  return binaryOp(a, b, (x, y) => x / y);
22653
23128
  }
22654
23129
  function mLeftDiv(a, b) {
@@ -23618,7 +24093,7 @@ var token_config_default = {
23618
24093
  stripUnderscores: true,
23619
24094
  integerToken: "Integer",
23620
24095
  floatToken: "Float",
23621
- exponentChars: ["e", "E"],
24096
+ exponentChars: ["e", "E", "d", "D"],
23622
24097
  decimalPoint: ".",
23623
24098
  dotOperatorPrefixes: ["*", "/", "\\", "^"]
23624
24099
  },
@@ -23923,6 +24398,9 @@ function tokenizeDetailed(input) {
23923
24398
  if (numCfg.stripUnderscores) {
23924
24399
  lexeme = lexeme.replace(/_/g, "");
23925
24400
  }
24401
+ if (isFloat) {
24402
+ lexeme = lexeme.replace(/[dD]/g, "e");
24403
+ }
23926
24404
  const tok = isFloat ? Token[numCfg.floatToken] : Token[numCfg.integerToken];
23927
24405
  lineStart = false;
23928
24406
  out.push({ token: tok, lexeme, start, end: pos });
@@ -26914,6 +27392,29 @@ function methodDispatch(rt, name, nargout, args) {
26914
27392
  }
26915
27393
  return fieldVal;
26916
27394
  }
27395
+ {
27396
+ const accessorKey = `${firstRV.className}.get.${name}`;
27397
+ if (!rt.activeAccessors.has(accessorKey)) {
27398
+ const getter = rt.cachedResolveClassMethod(
27399
+ firstRV.className,
27400
+ `get.${name}`
27401
+ );
27402
+ if (getter) {
27403
+ rt.activeAccessors.add(accessorKey);
27404
+ let gotVal;
27405
+ try {
27406
+ gotVal = getter(1, first);
27407
+ } finally {
27408
+ rt.activeAccessors.delete(accessorKey);
27409
+ }
27410
+ const remaining = args.slice(1);
27411
+ if (remaining.length > 0) {
27412
+ return rt.index(gotVal, remaining, nargout);
27413
+ }
27414
+ return gotVal;
27415
+ }
27416
+ }
27417
+ }
26917
27418
  try {
26918
27419
  return callClassMethod(rt, firstRV.className, name, nargout, args);
26919
27420
  } catch (e) {
@@ -27868,6 +28369,7 @@ function index(rt, base, indices, nargout = 1, skipSubsref = false) {
27868
28369
  const im2 = t.imag[i];
27869
28370
  return im2 === 0 ? t.data[i] : RTV.complex(t.data[i], im2);
27870
28371
  }
28372
+ if (t._isLogical === true) return t.data[i] !== 0;
27871
28373
  return t.data[i];
27872
28374
  }
27873
28375
  } else if (nIdx === 2) {
@@ -27876,7 +28378,14 @@ function index(rt, base, indices, nargout = 1, skipSubsref = false) {
27876
28378
  if (typeof ri === "number" && typeof ci === "number") {
27877
28379
  const s = t.shape;
27878
28380
  const rows = s.length === 0 ? 1 : s.length === 1 ? 1 : s[0];
27879
- const cols = s.length === 0 ? 1 : s.length === 1 ? s[0] : s[1];
28381
+ let cols;
28382
+ if (s.length === 0) cols = 1;
28383
+ else if (s.length === 1) cols = s[0];
28384
+ else if (s.length === 2) cols = s[1];
28385
+ else {
28386
+ cols = 1;
28387
+ for (let k = 1; k < s.length; k++) cols *= s[k];
28388
+ }
27880
28389
  const r = Math.round(ri) - 1;
27881
28390
  const c = Math.round(ci) - 1;
27882
28391
  if (r < 0 || r >= rows || c < 0 || c >= cols)
@@ -27886,6 +28395,7 @@ function index(rt, base, indices, nargout = 1, skipSubsref = false) {
27886
28395
  const im2 = t.imag[lin];
27887
28396
  return im2 === 0 ? t.data[lin] : RTV.complex(t.data[lin], im2);
27888
28397
  }
28398
+ if (t._isLogical === true) return t.data[lin] !== 0;
27889
28399
  return t.data[lin];
27890
28400
  }
27891
28401
  } else if (nIdx >= 3) {
@@ -28276,14 +28786,20 @@ function multiOutputCellAssign(base, indices, results) {
28276
28786
  if (base === void 0 || base === null) base = RTV.cell([], [0, 0]);
28277
28787
  let mv = ensureRuntimeValue(base);
28278
28788
  if (!isRuntimeCell(mv)) mv = RTV.cell([], [0, 0]);
28279
- const idxMv = ensureRuntimeValue(indices);
28280
28789
  let idxArray;
28281
- if (isRuntimeTensor(idxMv)) {
28282
- idxArray = Array.from(idxMv.data);
28283
- } else if (isRuntimeNumber(idxMv)) {
28284
- idxArray = [idxMv];
28790
+ if (indices === COLON_SENTINEL) {
28791
+ const n = mv.data.length;
28792
+ idxArray = [];
28793
+ for (let i = 1; i <= n; i++) idxArray.push(i);
28285
28794
  } else {
28286
- idxArray = [1];
28795
+ const idxMv = ensureRuntimeValue(indices);
28796
+ if (isRuntimeTensor(idxMv)) {
28797
+ idxArray = Array.from(idxMv.data);
28798
+ } else if (isRuntimeNumber(idxMv)) {
28799
+ idxArray = [idxMv];
28800
+ } else {
28801
+ idxArray = [1];
28802
+ }
28287
28803
  }
28288
28804
  for (let i = 0; i < idxArray.length && i < results.length; i++) {
28289
28805
  const idx = idxArray[i];
@@ -28294,225 +28810,6 @@ function multiOutputCellAssign(base, indices, results) {
28294
28810
  return mv;
28295
28811
  }
28296
28812
 
28297
- // src/numbl-core/helpers/string.ts
28298
- function numStr(n) {
28299
- if (n === Infinity) return "Inf";
28300
- if (n === -Infinity) return "-Inf";
28301
- if (isNaN(n)) return "NaN";
28302
- if (n === 0) return "0";
28303
- const prec = 5;
28304
- const exp = Math.floor(Math.log10(Math.abs(n)));
28305
- let s;
28306
- if (exp < -4 || exp >= prec) {
28307
- s = n.toExponential(prec - 1);
28308
- const ePos = s.indexOf("e");
28309
- let mantissa = s.slice(0, ePos);
28310
- const expPart0 = s.slice(ePos);
28311
- if (mantissa.includes(".")) mantissa = mantissa.replace(/\.?0+$/, "");
28312
- const expPart = expPart0.replace(/([eE][+-])(\d)$/, "$10$2");
28313
- s = mantissa + expPart;
28314
- } else {
28315
- if (Number.isInteger(n)) return String(n);
28316
- s = n.toPrecision(prec);
28317
- if (s.includes(".")) s = s.replace(/\.?0+$/, "");
28318
- }
28319
- return s;
28320
- }
28321
- function applyWidth(spec, str) {
28322
- const m = spec.match(/^%([-+ #]*)0?(\d+)?/);
28323
- if (!m) return str;
28324
- const explicitFlags = m[1] || "";
28325
- const leftAlign = explicitFlags.includes("-");
28326
- const afterPercent = spec.slice(1);
28327
- const flagAndWidth = afterPercent.match(/^([-+ #]*)(0?)(\d+)?/);
28328
- const zeroFlag = flagAndWidth ? flagAndWidth[2] === "0" : false;
28329
- const width = flagAndWidth && flagAndWidth[3] ? parseInt(flagAndWidth[3]) : 0;
28330
- if (width <= str.length) return str;
28331
- const zeroPad = !leftAlign && zeroFlag;
28332
- const padLen = width - str.length;
28333
- if (leftAlign) return str + " ".repeat(padLen);
28334
- if (zeroPad) {
28335
- if (str[0] === "-" || str[0] === "+") {
28336
- return str[0] + "0".repeat(padLen) + str.slice(1);
28337
- }
28338
- return "0".repeat(padLen) + str;
28339
- }
28340
- return " ".repeat(padLen) + str;
28341
- }
28342
- function sprintfFormat(fmt, args) {
28343
- const flatArgs = [];
28344
- for (const arg of args) {
28345
- if (isRuntimeTensor(arg)) {
28346
- for (let k = 0; k < arg.data.length; k++) {
28347
- flatArgs.push(arg.data[k]);
28348
- }
28349
- } else {
28350
- flatArgs.push(arg);
28351
- }
28352
- }
28353
- let result = "";
28354
- let argIdx = 0;
28355
- do {
28356
- const startArgIdx = argIdx;
28357
- let outOfArgs = false;
28358
- let i = 0;
28359
- while (i < fmt.length && !outOfArgs) {
28360
- if (fmt[i] === "%" && i + 1 < fmt.length) {
28361
- i++;
28362
- let spec = "%";
28363
- while (i < fmt.length && !"dfigeEsoxXuc%".includes(fmt[i])) {
28364
- spec += fmt[i];
28365
- i++;
28366
- }
28367
- if (i < fmt.length) {
28368
- const ch = fmt[i];
28369
- i++;
28370
- if (ch === "%") {
28371
- result += "%";
28372
- } else if (argIdx >= flatArgs.length) {
28373
- outOfArgs = true;
28374
- } else if (ch === "d" || ch === "i" || ch === "u") {
28375
- const raw = toNumber(flatArgs[argIdx++]);
28376
- const isInt = Number.isInteger(raw);
28377
- const canPrintAsInt = ch === "u" ? isInt && raw >= 0 : isInt;
28378
- if (!canPrintAsInt) {
28379
- let eStr = raw.toExponential(6);
28380
- eStr = eStr.replace(/e([+-])(\d)$/, "e$10$2");
28381
- result += applyWidth(spec, eStr);
28382
- } else {
28383
- const n = raw;
28384
- const flags = spec.slice(1);
28385
- const hasPlus = flags.includes("+");
28386
- const leftAlign = flags.includes("-");
28387
- const widthMatch = spec.match(/^%[^0-9]*(\d+)/);
28388
- const width = widthMatch ? parseInt(widthMatch[1]) : 0;
28389
- const zeroPad = !leftAlign && /^[-+ ]*0/.test(spec.slice(1));
28390
- const s = String(Math.abs(n));
28391
- const sign = n < 0 ? "-" : hasPlus ? "+" : "";
28392
- if (width > 0) {
28393
- const padChar = zeroPad ? "0" : " ";
28394
- const padLen = Math.max(0, width - sign.length - s.length);
28395
- const pad = padChar.repeat(padLen);
28396
- result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign + pad + s : pad + sign + s;
28397
- } else {
28398
- result += sign + s;
28399
- }
28400
- }
28401
- } else if (ch === "f") {
28402
- const n = toNumber(flatArgs[argIdx++]);
28403
- if (!isFinite(n) || isNaN(n)) {
28404
- result += applyWidth(spec, numStr(n));
28405
- } else {
28406
- const fFlags = spec.slice(1);
28407
- const fHasPlus = fFlags.includes("+");
28408
- const precMatch = spec.match(/\.(\d+)/);
28409
- const prec = precMatch ? parseInt(precMatch[1]) : 6;
28410
- const formatted = n.toFixed(prec);
28411
- const fSign = n < 0 ? "" : fHasPlus ? "+" : "";
28412
- result += applyWidth(spec, fSign + formatted);
28413
- }
28414
- } else if (ch === "e" || ch === "E") {
28415
- const n = toNumber(flatArgs[argIdx++]);
28416
- if (!isFinite(n) || isNaN(n)) {
28417
- result += applyWidth(spec, numStr(n));
28418
- } else {
28419
- const precMatch = spec.match(/\.(\d+)/);
28420
- const prec = precMatch ? parseInt(precMatch[1]) : 6;
28421
- let eStr = n.toExponential(prec);
28422
- eStr = eStr.replace(/e([+-])(\d)$/, "e$10$2");
28423
- if (ch === "E") eStr = eStr.toUpperCase();
28424
- result += applyWidth(spec, eStr);
28425
- }
28426
- } else if (ch === "x" || ch === "X") {
28427
- const n = Math.round(toNumber(flatArgs[argIdx++]));
28428
- let s = Math.abs(n).toString(16);
28429
- if (ch === "X") s = s.toUpperCase();
28430
- result += applyWidth(spec, s);
28431
- } else if (ch === "o") {
28432
- const n = Math.round(toNumber(flatArgs[argIdx++]));
28433
- result += applyWidth(spec, Math.abs(n).toString(8));
28434
- } else if (ch === "g" || ch === "G") {
28435
- const gVal = toNumber(flatArgs[argIdx++]);
28436
- if (!isFinite(gVal) || isNaN(gVal)) {
28437
- result += applyWidth(spec, numStr(gVal));
28438
- } else {
28439
- const precMatch = spec.match(/\.(\d+)/);
28440
- const gPrec = precMatch ? parseInt(precMatch[1]) : 6;
28441
- let gStr;
28442
- if (gVal === 0) {
28443
- gStr = "0";
28444
- } else {
28445
- const exp = Math.floor(Math.log10(Math.abs(gVal)));
28446
- if (exp < -4 || exp >= gPrec) {
28447
- gStr = gVal.toExponential(gPrec - 1);
28448
- const ePos = gStr.indexOf("e");
28449
- let mantissa = gStr.slice(0, ePos);
28450
- let expPart = gStr.slice(ePos);
28451
- if (mantissa.includes(".")) {
28452
- mantissa = mantissa.replace(/\.?0+$/, "");
28453
- }
28454
- expPart = expPart.replace(/e([+-])(\d)$/, "e$10$2");
28455
- gStr = mantissa + expPart;
28456
- } else {
28457
- gStr = gVal.toPrecision(gPrec);
28458
- if (gStr.includes(".")) {
28459
- gStr = gStr.replace(/\.?0+$/, "");
28460
- }
28461
- if (gStr.includes("e")) {
28462
- gStr = String(parseFloat(gStr));
28463
- }
28464
- }
28465
- }
28466
- if (ch === "G") gStr = gStr.toUpperCase();
28467
- result += applyWidth(spec, gStr);
28468
- }
28469
- } else if (ch === "s") {
28470
- const sVal = toString(flatArgs[argIdx++]);
28471
- const sFlags = spec.slice(1);
28472
- const sLeftAlign = sFlags.includes("-");
28473
- const sWidthMatch = spec.match(/^%[^0-9]*(\d+)/);
28474
- const sWidth = sWidthMatch ? parseInt(sWidthMatch[1]) : 0;
28475
- if (sWidth > sVal.length) {
28476
- const sPad = " ".repeat(sWidth - sVal.length);
28477
- result += sLeftAlign ? sVal + sPad : sPad + sVal;
28478
- } else {
28479
- result += sVal;
28480
- }
28481
- } else if (ch === "c") {
28482
- result += String.fromCharCode(
28483
- Math.round(toNumber(flatArgs[argIdx++]))
28484
- );
28485
- } else {
28486
- result += spec + ch;
28487
- argIdx++;
28488
- }
28489
- }
28490
- } else if (fmt[i] === "\\" && i + 1 < fmt.length) {
28491
- i++;
28492
- switch (fmt[i]) {
28493
- case "n":
28494
- result += "\n";
28495
- break;
28496
- case "t":
28497
- result += " ";
28498
- break;
28499
- case "\\":
28500
- result += "\\";
28501
- break;
28502
- default:
28503
- result += "\\" + fmt[i];
28504
- }
28505
- i++;
28506
- } else {
28507
- result += fmt[i];
28508
- i++;
28509
- }
28510
- }
28511
- if (argIdx === startArgIdx) break;
28512
- } while (argIdx < flatArgs.length);
28513
- return result;
28514
- }
28515
-
28516
28813
  // src/numbl-core/interpreter/builtins/misc.ts
28517
28814
  registerIBuiltin({
28518
28815
  name: "substruct",
@@ -28565,6 +28862,44 @@ registerIBuiltin({
28565
28862
  }
28566
28863
  })
28567
28864
  });
28865
+ var WEBOPTIONS_DEFAULTS = {
28866
+ CharacterEncoding: RTV.char("auto"),
28867
+ UserAgent: RTV.char("numbl"),
28868
+ Timeout: 5,
28869
+ Username: RTV.char(""),
28870
+ Password: RTV.char(""),
28871
+ KeyName: RTV.char(""),
28872
+ KeyValue: RTV.char(""),
28873
+ ContentType: RTV.char("auto"),
28874
+ MediaType: RTV.char("auto"),
28875
+ RequestMethod: RTV.char("auto"),
28876
+ ArrayFormat: RTV.char("csv"),
28877
+ CertificateFilename: RTV.char("default")
28878
+ };
28879
+ registerIBuiltin({
28880
+ name: "weboptions",
28881
+ resolve: () => ({
28882
+ outputTypes: [{ kind: "struct" }],
28883
+ apply: (args) => {
28884
+ const fields = /* @__PURE__ */ new Map();
28885
+ for (const [k, v] of Object.entries(WEBOPTIONS_DEFAULTS)) {
28886
+ fields.set(k, v);
28887
+ }
28888
+ if (args.length % 2 !== 0)
28889
+ throw new RuntimeError("weboptions: expected name-value pairs");
28890
+ for (let i = 0; i < args.length; i += 2) {
28891
+ const key = args[i];
28892
+ if (!isRuntimeChar(key) && !isRuntimeString(key))
28893
+ throw new RuntimeError("weboptions: option name must be a string");
28894
+ const name = isRuntimeChar(key) ? key.value : key;
28895
+ if (!(name in WEBOPTIONS_DEFAULTS))
28896
+ throw new RuntimeError(`weboptions: unknown option '${name}'`);
28897
+ fields.set(name, args[i + 1]);
28898
+ }
28899
+ return RTV.struct(Object.fromEntries(fields));
28900
+ }
28901
+ })
28902
+ });
28568
28903
  registerIBuiltin({
28569
28904
  name: "odeget",
28570
28905
  resolve: () => ({
@@ -28674,7 +29009,7 @@ for (const name of ["clear", "clc", "clf"]) {
28674
29009
  name,
28675
29010
  resolve: () => ({
28676
29011
  outputTypes: [],
28677
- apply: () => 0
29012
+ apply: () => void 0
28678
29013
  })
28679
29014
  });
28680
29015
  }
@@ -28808,7 +29143,7 @@ registerIBuiltin({
28808
29143
  name: "set",
28809
29144
  resolve: () => ({
28810
29145
  outputTypes: [],
28811
- apply: () => 0
29146
+ apply: () => void 0
28812
29147
  })
28813
29148
  });
28814
29149
  for (const name of [
@@ -28830,7 +29165,7 @@ for (const name of [
28830
29165
  name,
28831
29166
  resolve: () => ({
28832
29167
  outputTypes: [],
28833
- apply: () => 0
29168
+ apply: () => void 0
28834
29169
  })
28835
29170
  });
28836
29171
  }
@@ -29119,6 +29454,148 @@ registerIBuiltin({
29119
29454
  }
29120
29455
  });
29121
29456
 
29457
+ // src/numbl-core/interpreter/builtins/time-system.ts
29458
+ var ticTime = 0;
29459
+ function getTicTime() {
29460
+ return ticTime;
29461
+ }
29462
+ defineBuiltin({
29463
+ name: "tic",
29464
+ cases: [
29465
+ {
29466
+ match: (argTypes) => argTypes.length === 0 ? [{ kind: "number" }] : null,
29467
+ apply: () => {
29468
+ ticTime = performance.now();
29469
+ return RTV.num(ticTime / 1e3);
29470
+ }
29471
+ }
29472
+ ]
29473
+ });
29474
+ defineBuiltin({
29475
+ name: "clock",
29476
+ cases: [
29477
+ {
29478
+ match: (argTypes) => argTypes.length === 0 ? [{ kind: "tensor", isComplex: false, shape: [1, 6] }] : null,
29479
+ apply: () => {
29480
+ const now = /* @__PURE__ */ new Date();
29481
+ return RTV.tensor(
29482
+ new FloatXArray([
29483
+ now.getFullYear(),
29484
+ now.getMonth() + 1,
29485
+ now.getDate(),
29486
+ now.getHours(),
29487
+ now.getMinutes(),
29488
+ now.getSeconds() + now.getMilliseconds() / 1e3
29489
+ ]),
29490
+ [1, 6]
29491
+ );
29492
+ }
29493
+ }
29494
+ ]
29495
+ });
29496
+ defineBuiltin({
29497
+ name: "etime",
29498
+ cases: [
29499
+ {
29500
+ match: (argTypes) => argTypes.length === 2 ? [{ kind: "number" }] : null,
29501
+ apply: (args) => {
29502
+ const t1 = args[0];
29503
+ const t0 = args[1];
29504
+ if (!isRuntimeTensor(t1) || !isRuntimeTensor(t0))
29505
+ throw new RuntimeError("etime: arguments must be clock vectors");
29506
+ const toMs = (t) => {
29507
+ const d = new Date(
29508
+ t.data[0],
29509
+ t.data[1] - 1,
29510
+ t.data[2],
29511
+ t.data[3],
29512
+ t.data[4],
29513
+ Math.floor(t.data[5]),
29514
+ t.data[5] % 1 * 1e3
29515
+ );
29516
+ return d.getTime();
29517
+ };
29518
+ return RTV.num((toMs(t1) - toMs(t0)) / 1e3);
29519
+ }
29520
+ }
29521
+ ]
29522
+ });
29523
+ defineBuiltin({
29524
+ name: "version",
29525
+ cases: [
29526
+ {
29527
+ match: (argTypes) => argTypes.length === 0 ? [{ kind: "char" }] : null,
29528
+ apply: () => RTV.char("9.14.0")
29529
+ }
29530
+ ]
29531
+ });
29532
+ function getComputerStrings() {
29533
+ if (typeof process === "undefined") {
29534
+ return { str: "BROWSER", arch: "browser" };
29535
+ }
29536
+ const platform = process.platform;
29537
+ const cpuArch = process.arch;
29538
+ if (platform === "win32") return { str: "PCWIN64", arch: "win64" };
29539
+ if (platform === "darwin") {
29540
+ if (cpuArch === "arm64") return { str: "MACA64", arch: "maca64" };
29541
+ return { str: "MACI64", arch: "maci64" };
29542
+ }
29543
+ return { str: "GLNXA64", arch: "glnxa64" };
29544
+ }
29545
+ registerIBuiltin({
29546
+ name: "computer",
29547
+ resolve: () => ({
29548
+ outputTypes: [{ kind: "unknown" }],
29549
+ apply: (args, nargout) => {
29550
+ const info = getComputerStrings();
29551
+ if (args.length >= 1 && isRuntimeChar(args[0])) {
29552
+ const arg = toString(args[0]);
29553
+ if (arg === "arch") return RTV.char(info.arch);
29554
+ throw new RuntimeError(`computer: unknown argument '${arg}'`);
29555
+ }
29556
+ const maxsize = 2 ** 48 - 1;
29557
+ const endian = RTV.char("L");
29558
+ if (nargout <= 1) return RTV.char(info.str);
29559
+ if (nargout === 2) return [RTV.char(info.str), RTV.num(maxsize)];
29560
+ return [RTV.char(info.str), RTV.num(maxsize), endian];
29561
+ }
29562
+ })
29563
+ });
29564
+ function getMexExt() {
29565
+ if (typeof process === "undefined") return "";
29566
+ const platform = process.platform;
29567
+ const cpuArch = process.arch;
29568
+ if (platform === "win32") return "mexw64";
29569
+ if (platform === "darwin")
29570
+ return cpuArch === "arm64" ? "mexmaca64" : "mexmaci64";
29571
+ return "mexa64";
29572
+ }
29573
+ defineBuiltin({
29574
+ name: "mexext",
29575
+ cases: [
29576
+ {
29577
+ match: (argTypes) => argTypes.length === 0 ? [{ kind: "char" }] : null,
29578
+ apply: () => RTV.char(getMexExt())
29579
+ }
29580
+ ]
29581
+ });
29582
+ var _platform = typeof process !== "undefined" ? process.platform : "linux";
29583
+ for (const [name, val] of [
29584
+ ["ismac", _platform === "darwin"],
29585
+ ["ispc", _platform === "win32"],
29586
+ ["isunix", _platform !== "win32"]
29587
+ ]) {
29588
+ defineBuiltin({
29589
+ name,
29590
+ cases: [
29591
+ {
29592
+ match: (argTypes) => argTypes.length === 0 ? [{ kind: "boolean" }] : null,
29593
+ apply: () => RTV.logical(val)
29594
+ }
29595
+ ]
29596
+ });
29597
+ }
29598
+
29122
29599
  // src/numbl-core/runtime/plotUtils.ts
29123
29600
  var COLOR_SHORT = {
29124
29601
  r: [1, 0, 0],
@@ -31351,6 +31828,114 @@ function bisectEvent(eventIdx, step, events) {
31351
31828
  return [tOld + xFinal * h, denseOutputEval(yOld, Q, h, xFinal)];
31352
31829
  }
31353
31830
 
31831
+ // src/numbl-core/helpers/quadgk.ts
31832
+ var XK = [
31833
+ -0.9914553711208126,
31834
+ -0.9491079123427585,
31835
+ -0.8648644233597691,
31836
+ -0.7415311855993945,
31837
+ -0.586087235467691,
31838
+ -0.4058451513773972,
31839
+ -0.2077849550078985,
31840
+ 0,
31841
+ 0.2077849550078985,
31842
+ 0.4058451513773972,
31843
+ 0.586087235467691,
31844
+ 0.7415311855993945,
31845
+ 0.8648644233597691,
31846
+ 0.9491079123427585,
31847
+ 0.9914553711208126
31848
+ ];
31849
+ var WK = [
31850
+ 0.0229353220105292,
31851
+ 0.0630920926299786,
31852
+ 0.1047900103222502,
31853
+ 0.1406532597155259,
31854
+ 0.1690047266392679,
31855
+ 0.1903505780647854,
31856
+ 0.2044329400752989,
31857
+ 0.2094821410847278,
31858
+ 0.2044329400752989,
31859
+ 0.1903505780647854,
31860
+ 0.1690047266392679,
31861
+ 0.1406532597155259,
31862
+ 0.1047900103222502,
31863
+ 0.0630920926299786,
31864
+ 0.0229353220105292
31865
+ ];
31866
+ var WG = [
31867
+ 0.1294849661688697,
31868
+ 0.2797053914892767,
31869
+ 0.3818300505051189,
31870
+ 0.4179591836734694,
31871
+ 0.3818300505051189,
31872
+ 0.2797053914892767,
31873
+ 0.1294849661688697
31874
+ ];
31875
+ function kronrodNodes(lo, hi) {
31876
+ const m = (lo + hi) / 2;
31877
+ const h = (hi - lo) / 2;
31878
+ const out = new Array(15);
31879
+ for (let i = 0; i < 15; i++) out[i] = m + h * XK[i];
31880
+ return out;
31881
+ }
31882
+ function segmentEstimate(lo, hi, fv) {
31883
+ const h = (hi - lo) / 2;
31884
+ let K = 0;
31885
+ let G = 0;
31886
+ for (let i = 0; i < 15; i++) K += WK[i] * fv[i];
31887
+ for (let i = 0; i < 7; i++) G += WG[i] * fv[2 * i + 1];
31888
+ K *= h;
31889
+ G *= h;
31890
+ return { K, err: Math.abs(K - G) };
31891
+ }
31892
+ function quadgkAdaptive(integrand, a, b, opts = {}) {
31893
+ const relTol = opts.relTol ?? 1e-6;
31894
+ const absTol = opts.absTol ?? 1e-10;
31895
+ const maxIntervals = opts.maxIntervalCount ?? 650;
31896
+ if (a === b) return { value: 0, errbnd: 0, intervalsUsed: 0 };
31897
+ const sign = a < b ? 1 : -1;
31898
+ const lo0 = Math.min(a, b);
31899
+ const hi0 = Math.max(a, b);
31900
+ const segmentOn = (lo, hi) => {
31901
+ const pts = kronrodNodes(lo, hi);
31902
+ const fv = integrand(pts);
31903
+ if (fv.length !== 15) {
31904
+ throw new Error(
31905
+ `quadgk: integrand must return 15 values for 15 nodes, got ${fv.length}`
31906
+ );
31907
+ }
31908
+ return segmentEstimate(lo, hi, fv);
31909
+ };
31910
+ const initial = segmentOn(lo0, hi0);
31911
+ let totalK = initial.K;
31912
+ let totalErr = initial.err;
31913
+ const worklist = [{ lo: lo0, hi: hi0, ...initial }];
31914
+ const converged = () => totalErr <= Math.max(absTol, relTol * Math.abs(totalK));
31915
+ let iters = 0;
31916
+ while (!converged() && worklist.length < maxIntervals && iters < 1e4) {
31917
+ iters++;
31918
+ let worstIdx = 0;
31919
+ for (let i = 1; i < worklist.length; i++) {
31920
+ if (worklist[i].err > worklist[worstIdx].err) worstIdx = i;
31921
+ }
31922
+ const worst = worklist[worstIdx];
31923
+ if (worst.hi - worst.lo <= 1e-15 * (hi0 - lo0)) break;
31924
+ const mid = (worst.lo + worst.hi) / 2;
31925
+ const s1 = segmentOn(worst.lo, mid);
31926
+ const s2 = segmentOn(mid, worst.hi);
31927
+ totalK += s1.K + s2.K - worst.K;
31928
+ totalErr += s1.err + s2.err - worst.err;
31929
+ worklist[worstIdx] = { lo: worst.lo, hi: mid, ...s1 };
31930
+ worklist.push({ lo: mid, hi: worst.hi, ...s2 });
31931
+ }
31932
+ return {
31933
+ value: sign * totalK,
31934
+ errbnd: totalErr,
31935
+ intervalsUsed: worklist.length
31936
+ };
31937
+ }
31938
+
31354
31939
  // src/numbl-core/runtime/specialBuiltinNames.ts
31355
31940
  var SPECIAL_BUILTIN_NAMES = [
31356
31941
  "help",
@@ -31439,6 +32024,7 @@ var SPECIAL_BUILTIN_NAMES = [
31439
32024
  "webread",
31440
32025
  "delete",
31441
32026
  "rmdir",
32027
+ "movefile",
31442
32028
  "unzip",
31443
32029
  "dir",
31444
32030
  "warning",
@@ -31451,7 +32037,9 @@ var SPECIAL_BUILTIN_NAMES = [
31451
32037
  "cd",
31452
32038
  "ode45",
31453
32039
  "ode23",
31454
- "deval"
32040
+ "deval",
32041
+ "toc",
32042
+ "quadgk"
31455
32043
  ];
31456
32044
 
31457
32045
  // src/numbl-core/runtime/specialBuiltins.ts
@@ -31465,49 +32053,74 @@ function registerSpecial(name, fn) {
31465
32053
  })
31466
32054
  });
31467
32055
  }
32056
+ function registerSpecialVoid(name, fn) {
32057
+ registerDynamicIBuiltin({
32058
+ name,
32059
+ resolve: () => ({
32060
+ outputTypes: [],
32061
+ apply: (args) => {
32062
+ fn(args);
32063
+ return void 0;
32064
+ }
32065
+ })
32066
+ });
32067
+ }
31468
32068
  function registerSpecialBuiltins(rt) {
31469
- registerSpecial("help", (_nargout, args) => {
32069
+ registerSpecial("help", (nargout, args) => {
32070
+ let text = "";
32071
+ const emit = (s) => {
32072
+ text += s;
32073
+ if (nargout === 0) rt.output(s);
32074
+ };
31470
32075
  if (args.length === 0) {
31471
32076
  const names = getAllBuiltinNames().sort();
31472
- rt.output("Available builtins:\n");
31473
- rt.output(" " + names.join(", ") + "\n");
31474
- rt.output("\nType 'help <name>' for help on a specific builtin.\n");
31475
- return 0;
31476
- }
31477
- const name = toString(args[0]);
31478
- const h = getIBuiltinHelp(name);
31479
- if (!h) {
31480
- const allNames = getAllBuiltinNames();
31481
- if (allNames.includes(name)) {
31482
- rt.output(`No help available for '${name}'.
32077
+ emit("Available builtins:\n");
32078
+ emit(" " + names.join(", ") + "\n");
32079
+ emit("\nType 'help <name>' for help on a specific builtin.\n");
32080
+ } else {
32081
+ const name = toString(args[0]);
32082
+ const h = getIBuiltinHelp(name);
32083
+ if (!h) {
32084
+ const allNames = getAllBuiltinNames();
32085
+ if (allNames.includes(name)) {
32086
+ emit(`No help available for '${name}'.
31483
32087
  `);
31484
- } else {
31485
- rt.output(`Unknown function '${name}'.
32088
+ } else {
32089
+ emit(`Unknown function '${name}'.
31486
32090
  `);
31487
- }
31488
- return 0;
31489
- }
31490
- rt.output(` ${h.signatures.join("\n ")}
32091
+ }
32092
+ } else {
32093
+ emit(` ${h.signatures.join("\n ")}
31491
32094
 
31492
32095
  `);
31493
- rt.output(`${h.description}
32096
+ emit(`${h.description}
31494
32097
  `);
31495
- return 0;
32098
+ }
32099
+ }
32100
+ return nargout >= 1 ? RTV.char(text) : void 0;
31496
32101
  });
31497
- registerSpecial("disp", (_nargout, args) => {
32102
+ registerSpecialVoid("disp", (args) => {
31498
32103
  if (args.length >= 1) {
31499
32104
  const mv = ensureRuntimeValue(args[0]);
31500
- if (isRuntimeTensor(mv) && mv.data.length === 0) return 0;
32105
+ if (isRuntimeTensor(mv) && mv.data.length === 0) return;
31501
32106
  rt.output(displayValue(mv) + "\n");
31502
32107
  }
31503
- return 0;
31504
32108
  });
31505
- registerSpecial("warning", (_nargout, args) => {
31506
- if (args.length === 0) return RTV.num(0);
32109
+ registerSpecial("toc", (nargout) => {
32110
+ const elapsed = (performance.now() - getTicTime()) / 1e3;
32111
+ if (nargout === 0) {
32112
+ rt.output(`Elapsed time is ${elapsed.toFixed(6)} seconds.
32113
+ `);
32114
+ }
32115
+ return RTV.num(elapsed);
32116
+ });
32117
+ registerSpecial("warning", (nargout, args) => {
32118
+ if (args.length === 0) return nargout >= 1 ? RTV.num(0) : void 0;
31507
32119
  const margs = args.map((a) => ensureRuntimeValue(a));
31508
32120
  if (margs.length === 2 && isRuntimeChar(margs[0]) && isRuntimeChar(margs[1])) {
31509
32121
  const state = toString(margs[0]);
31510
32122
  if (state === "on" || state === "off") {
32123
+ if (nargout === 0) return void 0;
31511
32124
  return RTV.struct(
31512
32125
  /* @__PURE__ */ new Map([
31513
32126
  ["state", RTV.char("on")],
@@ -31536,9 +32149,9 @@ function registerSpecialBuiltins(rt) {
31536
32149
  } else {
31537
32150
  rt.output("Warning: " + sprintfFormat(fmt, fmtArgs) + "\n");
31538
32151
  }
31539
- return RTV.num(0);
32152
+ return nargout >= 1 ? RTV.num(0) : void 0;
31540
32153
  });
31541
- registerSpecial("fprintf", (_nargout, args) => {
32154
+ registerSpecial("fprintf", (nargout, args) => {
31542
32155
  let output = "";
31543
32156
  if (args.length >= 1) {
31544
32157
  const margs = args.map((a) => ensureRuntimeValue(a));
@@ -31549,27 +32162,7 @@ function registerSpecialBuiltins(rt) {
31549
32162
  fmtIdx = 1;
31550
32163
  }
31551
32164
  const fmt = toString(margs[fmtIdx]);
31552
- const scalarArgs = [];
31553
- for (let i = fmtIdx + 1; i < margs.length; i++) {
31554
- const a = margs[i];
31555
- if (isRuntimeTensor(a)) {
31556
- for (let j = 0; j < a.data.length; j++)
31557
- scalarArgs.push(RTV.num(a.data[j]));
31558
- } else {
31559
- scalarArgs.push(a);
31560
- }
31561
- }
31562
- const specCount = (fmt.match(/%[^%]/g) || []).length;
31563
- if (specCount === 0 || scalarArgs.length === 0) {
31564
- output = sprintfFormat(fmt, scalarArgs);
31565
- } else {
31566
- let idx = 0;
31567
- while (idx < scalarArgs.length) {
31568
- const batch = scalarArgs.slice(idx, idx + specCount);
31569
- output += sprintfFormat(fmt, batch);
31570
- idx += specCount;
31571
- }
31572
- }
32165
+ output = sprintfFormat(fmt, margs.slice(fmtIdx + 1));
31573
32166
  if (fid === 1 || fid === 2) {
31574
32167
  rt.output(output);
31575
32168
  } else {
@@ -31580,7 +32173,7 @@ function registerSpecialBuiltins(rt) {
31580
32173
  rt.fileIO.fwrite(fid, output);
31581
32174
  }
31582
32175
  }
31583
- return output.length;
32176
+ return nargout >= 1 ? output.length : void 0;
31584
32177
  });
31585
32178
  registerSpecial("arrayfun", (nargout, args) => {
31586
32179
  return arrayfunImpl(rt, nargout, args);
@@ -31612,6 +32205,55 @@ function registerSpecialBuiltins(rt) {
31612
32205
  registerSpecial("bsxfun", (nargout, args) => {
31613
32206
  return bsxfunImpl(rt, nargout, args);
31614
32207
  });
32208
+ registerSpecial("quadgk", (nargout, args) => {
32209
+ if (args.length < 3)
32210
+ throw new RuntimeError(
32211
+ "quadgk: requires at least 3 arguments (fun, a, b)"
32212
+ );
32213
+ const fnArg = ensureRuntimeValue(args[0]);
32214
+ if (!isRuntimeFunction(fnArg))
32215
+ throw new RuntimeError("quadgk: first argument must be a function");
32216
+ const a = toNumber(ensureRuntimeValue(args[1]));
32217
+ const b = toNumber(ensureRuntimeValue(args[2]));
32218
+ let relTol;
32219
+ let absTol;
32220
+ let maxIntervalCount;
32221
+ for (let i = 3; i + 1 < args.length; i += 2) {
32222
+ const keyRv = ensureRuntimeValue(args[i]);
32223
+ const key = isRuntimeChar(keyRv) ? keyRv.value : isRuntimeString(keyRv) ? keyRv : "";
32224
+ const lowerKey = key.toLowerCase();
32225
+ const valRv = ensureRuntimeValue(args[i + 1]);
32226
+ if (lowerKey === "reltol") relTol = toNumber(valRv);
32227
+ else if (lowerKey === "abstol") absTol = toNumber(valRv);
32228
+ else if (lowerKey === "maxintervalcount")
32229
+ maxIntervalCount = toNumber(valRv);
32230
+ }
32231
+ const integrand = (pts) => {
32232
+ const vecData = new FloatXArray(pts);
32233
+ const vec = RTV.tensor(vecData, [1, pts.length]);
32234
+ const resultRaw = rt.index(fnArg, [vec], 1);
32235
+ const rv = ensureRuntimeValue(resultRaw);
32236
+ if (isRuntimeNumber(rv)) {
32237
+ return new Array(pts.length).fill(rv);
32238
+ }
32239
+ if (isRuntimeTensor(rv)) {
32240
+ if (rv.data.length !== pts.length) {
32241
+ throw new RuntimeError(
32242
+ `quadgk: integrand returned ${rv.data.length} values for ${pts.length} nodes`
32243
+ );
32244
+ }
32245
+ return Array.from(rv.data);
32246
+ }
32247
+ throw new RuntimeError("quadgk: integrand must return a numeric vector");
32248
+ };
32249
+ const result = quadgkAdaptive(integrand, a, b, {
32250
+ relTol,
32251
+ absTol,
32252
+ maxIntervalCount
32253
+ });
32254
+ if (nargout >= 2) return [result.value, result.errbnd];
32255
+ return result.value;
32256
+ });
31615
32257
  registerSpecial("subsref", (nargout, args) => {
31616
32258
  return subsrefBuiltin(rt, nargout, args);
31617
32259
  });
@@ -32140,6 +32782,40 @@ function registerSpecialBuiltins(rt) {
32140
32782
  RTV.char("")
32141
32783
  ];
32142
32784
  });
32785
+ function extractWebOptions(arg) {
32786
+ if (!isRuntimeStruct(arg)) return void 0;
32787
+ const s = arg;
32788
+ if (!s.fields.has("Timeout")) return void 0;
32789
+ const opts = {};
32790
+ const t = s.fields.get("Timeout");
32791
+ if (t !== void 0) opts.timeout = toNumber(t);
32792
+ const rm = s.fields.get("RequestMethod");
32793
+ if (rm !== void 0) {
32794
+ const v = toString(rm);
32795
+ if (v !== "auto") opts.requestMethod = v;
32796
+ }
32797
+ const un = s.fields.get("Username");
32798
+ if (un !== void 0) {
32799
+ const v = toString(un);
32800
+ if (v) opts.username = v;
32801
+ }
32802
+ const pw = s.fields.get("Password");
32803
+ if (pw !== void 0) {
32804
+ const v = toString(pw);
32805
+ if (v) opts.password = v;
32806
+ }
32807
+ const kn = s.fields.get("KeyName");
32808
+ if (kn !== void 0) {
32809
+ const v = toString(kn);
32810
+ if (v) opts.keyName = v;
32811
+ }
32812
+ const kv = s.fields.get("KeyValue");
32813
+ if (kv !== void 0) {
32814
+ const v = toString(kv);
32815
+ if (v) opts.keyValue = v;
32816
+ }
32817
+ return opts;
32818
+ }
32143
32819
  registerSpecial("websave", (_nargout, args) => {
32144
32820
  const io = requireFileIO();
32145
32821
  const margs = args.map((a) => ensureRuntimeValue(a));
@@ -32149,8 +32825,14 @@ function registerSpecialBuiltins(rt) {
32149
32825
  throw new RuntimeError("websave is not available in this environment");
32150
32826
  const filename = toString(margs[0]);
32151
32827
  let url = toString(margs[1]);
32828
+ let webOpts;
32829
+ let queryEnd = margs.length;
32830
+ if (margs.length > 2) {
32831
+ webOpts = extractWebOptions(margs[margs.length - 1]);
32832
+ if (webOpts) queryEnd = margs.length - 1;
32833
+ }
32152
32834
  const queryParts = [];
32153
- for (let i = 2; i + 1 < margs.length; i += 2) {
32835
+ for (let i = 2; i + 1 < queryEnd; i += 2) {
32154
32836
  const name = encodeURIComponent(toString(margs[i]));
32155
32837
  const value = encodeURIComponent(toString(margs[i + 1]));
32156
32838
  queryParts.push(`${name}=${value}`);
@@ -32159,7 +32841,7 @@ function registerSpecialBuiltins(rt) {
32159
32841
  const sep = url.includes("?") ? "&" : "?";
32160
32842
  url += sep + queryParts.join("&");
32161
32843
  }
32162
- io.websave(url, filename);
32844
+ io.websave(url, filename, webOpts);
32163
32845
  return RTV.char(filename);
32164
32846
  });
32165
32847
  registerSpecial("webread", (_nargout, args) => {
@@ -32170,8 +32852,14 @@ function registerSpecialBuiltins(rt) {
32170
32852
  if (!io.webread)
32171
32853
  throw new RuntimeError("webread is not available in this environment");
32172
32854
  let url = toString(margs[0]);
32855
+ let webOpts;
32856
+ let queryEnd = margs.length;
32857
+ if (margs.length > 1) {
32858
+ webOpts = extractWebOptions(margs[margs.length - 1]);
32859
+ if (webOpts) queryEnd = margs.length - 1;
32860
+ }
32173
32861
  const queryParts = [];
32174
- for (let i = 1; i + 1 < margs.length; i += 2) {
32862
+ for (let i = 1; i + 1 < queryEnd; i += 2) {
32175
32863
  const name = encodeURIComponent(toString(margs[i]));
32176
32864
  const value = encodeURIComponent(toString(margs[i + 1]));
32177
32865
  queryParts.push(`${name}=${value}`);
@@ -32180,7 +32868,7 @@ function registerSpecialBuiltins(rt) {
32180
32868
  const sep = url.includes("?") ? "&" : "?";
32181
32869
  url += sep + queryParts.join("&");
32182
32870
  }
32183
- const text = io.webread(url);
32871
+ const text = io.webread(url, webOpts);
32184
32872
  try {
32185
32873
  const parsed = JSON.parse(text);
32186
32874
  return convertJsonValue(parsed);
@@ -32188,7 +32876,7 @@ function registerSpecialBuiltins(rt) {
32188
32876
  return RTV.char(text);
32189
32877
  }
32190
32878
  });
32191
- registerSpecial("delete", (_nargout, args) => {
32879
+ registerSpecialVoid("delete", (args) => {
32192
32880
  const io = requireFileIO();
32193
32881
  if (!io.deleteFile)
32194
32882
  throw new RuntimeError("delete is not available in this environment");
@@ -32198,7 +32886,6 @@ function registerSpecialBuiltins(rt) {
32198
32886
  for (const arg of margs) {
32199
32887
  io.deleteFile(toString(arg));
32200
32888
  }
32201
- return 0;
32202
32889
  });
32203
32890
  registerSpecial("rmdir", (nargout, args) => {
32204
32891
  const io = requireFileIO();
@@ -32221,6 +32908,34 @@ function registerSpecialBuiltins(rt) {
32221
32908
  RTV.char("")
32222
32909
  ];
32223
32910
  });
32911
+ registerSpecial("movefile", (nargout, args) => {
32912
+ const io = requireFileIO();
32913
+ if (!io.movefile)
32914
+ throw new RuntimeError("movefile is not available in this environment");
32915
+ const margs = args.map((a) => ensureRuntimeValue(a));
32916
+ if (margs.length < 1)
32917
+ throw new RuntimeError("movefile requires at least 1 argument");
32918
+ const source = toString(margs[0]);
32919
+ const destination = margs.length >= 2 ? toString(margs[1]) : rt.system?.cwd() ?? ".";
32920
+ let force = false;
32921
+ if (margs.length >= 3) {
32922
+ const third = toString(margs[2]);
32923
+ if (third.toLowerCase() === "f") force = true;
32924
+ }
32925
+ const ok = io.movefile(source, destination, force);
32926
+ if (nargout === 0) {
32927
+ if (!ok)
32928
+ throw new RuntimeError(
32929
+ `movefile: cannot move '${source}' to '${destination}'`
32930
+ );
32931
+ return void 0;
32932
+ }
32933
+ return nargout <= 1 ? RTV.num(ok ? 1 : 0) : [
32934
+ RTV.num(ok ? 1 : 0),
32935
+ RTV.char(ok ? "" : `Cannot move '${source}' to '${destination}'`),
32936
+ RTV.char("")
32937
+ ];
32938
+ });
32224
32939
  registerSpecial("unzip", (nargout, args) => {
32225
32940
  const io = requireFileIO();
32226
32941
  if (!io.unzip)
@@ -32272,7 +32987,7 @@ function registerSpecialBuiltins(rt) {
32272
32987
  const cellData = extracted.map((f) => RTV.char(f));
32273
32988
  return RTV.cell(cellData, [1, cellData.length]);
32274
32989
  }
32275
- return 0;
32990
+ return void 0;
32276
32991
  });
32277
32992
  registerSpecial("dir", (nargout, args) => {
32278
32993
  const io = requireFileIO();
@@ -32369,7 +33084,7 @@ function registerSpecialBuiltins(rt) {
32369
33084
  const parts = margs.map((a) => toString(a));
32370
33085
  return RTV.char(parts.join("/"));
32371
33086
  });
32372
- registerSpecial("assignin", (_nargout, args) => {
33087
+ registerSpecialVoid("assignin", (args) => {
32373
33088
  if (args.length < 3)
32374
33089
  throw new RuntimeError("assignin requires 3 arguments");
32375
33090
  const margs = args.map((a) => ensureRuntimeValue(a));
@@ -32384,7 +33099,6 @@ function registerSpecialBuiltins(rt) {
32384
33099
  } else {
32385
33100
  rt.setWorkspaceVariable(varName, args[2]);
32386
33101
  }
32387
- return 0;
32388
33102
  });
32389
33103
  registerSpecial("evalin", (_nargout, args) => {
32390
33104
  if (args.length < 2)
@@ -32405,13 +33119,12 @@ function registerSpecialBuiltins(rt) {
32405
33119
  }
32406
33120
  return val;
32407
33121
  });
32408
- registerSpecial("drawnow", () => {
33122
+ registerSpecialVoid("drawnow", () => {
32409
33123
  rt.drawnow();
32410
- return 0;
32411
33124
  });
32412
- registerSpecial("pause", (_nargout, args) => {
33125
+ registerSpecial("pause", (nargout, args) => {
32413
33126
  rt.pause(args[0] ?? 0);
32414
- return 0;
33127
+ return nargout >= 1 ? RTV.char("on") : void 0;
32415
33128
  });
32416
33129
  registerSpecial("mfilename", (_nargout, args) => {
32417
33130
  const file = rt.$file ?? "";
@@ -32455,7 +33168,7 @@ function registerSpecialBuiltins(rt) {
32455
33168
  }
32456
33169
  }
32457
33170
  if (nargout >= 1) return RTV.char(rt.searchPaths.join(";"));
32458
- return 0;
33171
+ return void 0;
32459
33172
  });
32460
33173
  registerSpecial("rmpath", (nargout, args) => {
32461
33174
  if (!rt.onPathChange) {
@@ -32475,11 +33188,11 @@ function registerSpecialBuiltins(rt) {
32475
33188
  }
32476
33189
  }
32477
33190
  if (nargout >= 1) return RTV.char(rt.searchPaths.join(";"));
32478
- return 0;
33191
+ return void 0;
32479
33192
  });
32480
- registerSpecial("savepath", () => {
33193
+ registerSpecial("savepath", (nargout) => {
32481
33194
  rt.output("Warning: savepath is a no-op in numbl\n");
32482
- return 0;
33195
+ return nargout >= 1 ? RTV.num(0) : void 0;
32483
33196
  });
32484
33197
  registerSpecial("input", (_nargout, args) => {
32485
33198
  const margs = args.map((a) => ensureRuntimeValue(a));
@@ -32542,11 +33255,11 @@ function registerSpecialBuiltins(rt) {
32542
33255
  }
32543
33256
  return RTV.char(sys?.getEnv(toString(args[0])) ?? "");
32544
33257
  });
32545
- registerSpecial("setenv", (_nargout, args) => {
33258
+ registerSpecialVoid("setenv", (args) => {
32546
33259
  const sys = rt.system;
32547
33260
  if (args.length === 2) {
32548
33261
  sys?.setEnv(toString(args[0]), toString(args[1]));
32549
- return 0;
33262
+ return;
32550
33263
  }
32551
33264
  if (args.length === 1) {
32552
33265
  const d = args[0];
@@ -32554,20 +33267,26 @@ function registerSpecialBuiltins(rt) {
32554
33267
  for (const { key, value } of d.entries.values()) {
32555
33268
  sys?.setEnv(toString(key), toString(value));
32556
33269
  }
32557
- return 0;
33270
+ return;
32558
33271
  }
32559
33272
  sys?.setEnv(toString(d), "");
32560
- return 0;
33273
+ return;
32561
33274
  }
32562
33275
  throw new RuntimeError("setenv: invalid arguments");
32563
33276
  });
32564
33277
  registerSpecial("pwd", () => {
32565
33278
  return RTV.char(rt.system?.cwd() ?? "/");
32566
33279
  });
32567
- registerSpecial("cd", (_nargout, args) => {
33280
+ registerSpecial("cd", (nargout, args) => {
32568
33281
  const sys = rt.system;
32569
33282
  const curDir = sys?.cwd() ?? "/";
32570
- if (args.length === 0) return RTV.char(curDir);
33283
+ if (args.length === 0) {
33284
+ if (nargout === 0) {
33285
+ rt.output(curDir + "\n");
33286
+ return void 0;
33287
+ }
33288
+ return RTV.char(curDir);
33289
+ }
32571
33290
  const target = toString(args[0]);
32572
33291
  if (sys) {
32573
33292
  try {
@@ -32575,15 +33294,18 @@ function registerSpecialBuiltins(rt) {
32575
33294
  } catch {
32576
33295
  throw new RuntimeError(`Cannot change directory to '${target}'`);
32577
33296
  }
33297
+ if (rt.onCwdChange) {
33298
+ rt.onCwdChange(sys.cwd());
33299
+ }
32578
33300
  }
32579
- return RTV.char(curDir);
33301
+ return nargout >= 1 ? RTV.char(curDir) : void 0;
32580
33302
  });
32581
- registerSpecial("figure", (_nargout, args) => {
33303
+ registerSpecial("figure", (nargout, args) => {
32582
33304
  const handle = args.length > 0 ? args[0] : 1;
32583
33305
  plotInstr(rt.plotInstructions, { type: "set_figure_handle", handle });
32584
- return 0;
33306
+ return nargout >= 1 ? RTV.num(toNumber(ensureRuntimeValue(handle))) : void 0;
32585
33307
  });
32586
- registerSpecial("subplot", (_nargout, args) => {
33308
+ registerSpecial("subplot", (nargout, args) => {
32587
33309
  if (args.length >= 3) {
32588
33310
  plotInstr(rt.plotInstructions, {
32589
33311
  type: "set_subplot",
@@ -32592,43 +33314,41 @@ function registerSpecialBuiltins(rt) {
32592
33314
  index: args[2]
32593
33315
  });
32594
33316
  }
32595
- return 0;
33317
+ return nargout >= 1 ? RTV.num(0) : void 0;
32596
33318
  });
32597
- registerSpecial("title", (_nargout, args) => {
33319
+ registerSpecial("title", (nargout, args) => {
32598
33320
  if (args.length > 0) {
32599
33321
  plotInstr(rt.plotInstructions, { type: "set_title", text: args[0] });
32600
33322
  }
32601
- return 0;
33323
+ return nargout >= 1 ? RTV.num(0) : void 0;
32602
33324
  });
32603
- registerSpecial("xlabel", (_nargout, args) => {
33325
+ registerSpecial("xlabel", (nargout, args) => {
32604
33326
  if (args.length > 0) {
32605
33327
  plotInstr(rt.plotInstructions, { type: "set_xlabel", text: args[0] });
32606
33328
  }
32607
- return 0;
33329
+ return nargout >= 1 ? RTV.num(0) : void 0;
32608
33330
  });
32609
- registerSpecial("ylabel", (_nargout, args) => {
33331
+ registerSpecial("ylabel", (nargout, args) => {
32610
33332
  if (args.length > 0) {
32611
33333
  plotInstr(rt.plotInstructions, { type: "set_ylabel", text: args[0] });
32612
33334
  }
32613
- return 0;
33335
+ return nargout >= 1 ? RTV.num(0) : void 0;
32614
33336
  });
32615
- registerSpecial("hold", (_nargout, args) => {
33337
+ registerSpecialVoid("hold", (args) => {
32616
33338
  if (args.length > 0) {
32617
33339
  plotInstr(rt.plotInstructions, { type: "set_hold", value: args[0] });
32618
33340
  }
32619
- return 0;
32620
33341
  });
32621
- registerSpecial("grid", (_nargout, args) => {
33342
+ registerSpecialVoid("grid", (args) => {
32622
33343
  if (args.length > 0) {
32623
33344
  plotInstr(rt.plotInstructions, { type: "set_grid", value: args[0] });
32624
33345
  }
32625
- return 0;
32626
33346
  });
32627
- registerSpecial("legend", (_nargout, args) => {
33347
+ registerSpecial("legend", (nargout, args) => {
32628
33348
  legendCall(rt.plotInstructions, args);
32629
- return 0;
33349
+ return nargout >= 1 ? RTV.num(0) : void 0;
32630
33350
  });
32631
- registerSpecial("close", (_nargout, args) => {
33351
+ registerSpecial("close", (nargout, args) => {
32632
33352
  if (args.length > 0) {
32633
33353
  const val = toString(args[0]);
32634
33354
  if (val === "all") {
@@ -32639,26 +33359,25 @@ function registerSpecialBuiltins(rt) {
32639
33359
  } else {
32640
33360
  plotInstr(rt.plotInstructions, { type: "close" });
32641
33361
  }
32642
- return 0;
33362
+ return nargout >= 1 ? RTV.num(1) : void 0;
32643
33363
  });
32644
- registerSpecial("sgtitle", (_nargout, args) => {
33364
+ registerSpecial("sgtitle", (nargout, args) => {
32645
33365
  if (args.length > 0) {
32646
33366
  plotInstr(rt.plotInstructions, { type: "set_sgtitle", text: args[0] });
32647
33367
  }
32648
- return 0;
33368
+ return nargout >= 1 ? RTV.num(0) : void 0;
32649
33369
  });
32650
- registerSpecial("shading", (_nargout, args) => {
33370
+ registerSpecialVoid("shading", (args) => {
32651
33371
  if (args.length > 0) {
32652
33372
  plotInstr(rt.plotInstructions, {
32653
33373
  type: "set_shading",
32654
33374
  shading: args[0]
32655
33375
  });
32656
33376
  }
32657
- return 0;
32658
33377
  });
32659
- registerSpecial("clf", () => {
33378
+ registerSpecial("clf", (nargout) => {
32660
33379
  plotInstr(rt.plotInstructions, { type: "clf" });
32661
- return 0;
33380
+ return nargout >= 1 ? RTV.num(1) : void 0;
32662
33381
  });
32663
33382
  registerSpecial("ode45", (nargout, args) => {
32664
33383
  return _ode45Impl(rt, nargout, args, dormandPrince45);
@@ -33114,6 +33833,8 @@ var Runtime = class _Runtime {
33114
33833
  classMethodCache = /* @__PURE__ */ new Map();
33115
33834
  /** Callback for addpath/rmpath — mutates search paths and rebuilds function index. */
33116
33835
  onPathChange = null;
33836
+ /** Callback invoked after cd() to update the implicit cwd search path. */
33837
+ onCwdChange = null;
33117
33838
  /** Reference to the active search paths (set by executeCode). */
33118
33839
  searchPaths = [];
33119
33840
  // Workspace accessors: varName → { get, set } closures over script-level vars
@@ -33393,23 +34114,26 @@ var Runtime = class _Runtime {
33393
34114
  if (e instanceof RuntimeError) {
33394
34115
  return RTV.struct(
33395
34116
  /* @__PURE__ */ new Map([
33396
- ["message", RTV.string(e.message)],
33397
- ["identifier", RTV.string(e.identifier)]
34117
+ ["message", RTV.char(e.message)],
34118
+ ["identifier", RTV.char(e.identifier)],
34119
+ ["stack", buildStackField(e)]
33398
34120
  ])
33399
34121
  );
33400
34122
  }
33401
34123
  if (e instanceof Error) {
33402
34124
  return RTV.struct(
33403
34125
  /* @__PURE__ */ new Map([
33404
- ["message", RTV.string(e.message)],
33405
- ["identifier", RTV.string("")]
34126
+ ["message", RTV.char(e.message)],
34127
+ ["identifier", RTV.char("")],
34128
+ ["stack", emptyStackField()]
33406
34129
  ])
33407
34130
  );
33408
34131
  }
33409
34132
  return RTV.struct(
33410
34133
  /* @__PURE__ */ new Map([
33411
- ["message", RTV.string(String(e))],
33412
- ["identifier", RTV.string("")]
34134
+ ["message", RTV.char(String(e))],
34135
+ ["identifier", RTV.char("")],
34136
+ ["stack", emptyStackField()]
33413
34137
  ])
33414
34138
  );
33415
34139
  }
@@ -34241,6 +34965,63 @@ var rstr = (s) => {
34241
34965
  if (isRuntimeChar(s)) return s.value;
34242
34966
  throw new RuntimeError(`Expected string or char, got ${kstr(s)}`);
34243
34967
  };
34968
+ function emptyStackField() {
34969
+ return RTV.structArray(["file", "name", "line"], []);
34970
+ }
34971
+ function buildStackField(e) {
34972
+ const fieldNames = ["file", "name", "line"];
34973
+ const frames = e.callStack;
34974
+ if (!frames || frames.length === 0) {
34975
+ if (e.file || e.line !== null) {
34976
+ return RTV.structArray(fieldNames, [
34977
+ RTV.struct(
34978
+ /* @__PURE__ */ new Map([
34979
+ ["file", RTV.char(e.file ?? "")],
34980
+ ["name", RTV.char("")],
34981
+ ["line", e.line ?? 0]
34982
+ ])
34983
+ )
34984
+ ]);
34985
+ }
34986
+ return emptyStackField();
34987
+ }
34988
+ const elements = [];
34989
+ const N = frames.length;
34990
+ for (let i = N - 1; i >= 0; i--) {
34991
+ let frameFile;
34992
+ let frameLine;
34993
+ if (i === N - 1) {
34994
+ frameFile = e.file;
34995
+ frameLine = e.line ?? 0;
34996
+ } else {
34997
+ const callerFrame = frames[i + 1];
34998
+ frameFile = callerFrame.callerFile;
34999
+ frameLine = callerFrame.callerLine;
35000
+ }
35001
+ elements.push(
35002
+ RTV.struct(
35003
+ /* @__PURE__ */ new Map([
35004
+ ["file", RTV.char(frameFile ?? "")],
35005
+ ["name", RTV.char(frames[i].name)],
35006
+ ["line", frameLine]
35007
+ ])
35008
+ )
35009
+ );
35010
+ }
35011
+ const outermost = frames[0];
35012
+ if (outermost.callerFile && outermost.callerLine > 0) {
35013
+ elements.push(
35014
+ RTV.struct(
35015
+ /* @__PURE__ */ new Map([
35016
+ ["file", RTV.char(outermost.callerFile)],
35017
+ ["name", RTV.char("")],
35018
+ ["line", outermost.callerLine]
35019
+ ])
35020
+ )
35021
+ );
35022
+ }
35023
+ return RTV.structArray(fieldNames, elements);
35024
+ }
34244
35025
 
34245
35026
  // src/numbl-core/helpers/reduction-helpers.ts
34246
35027
  function squeezeTrailing(shape) {
@@ -35248,6 +36029,89 @@ defineBuiltin({
35248
36029
  }
35249
36030
  });
35250
36031
 
36032
+ // src/numbl-core/interpreter/builtins/logical.ts
36033
+ var LOGICAL_KINDS = /* @__PURE__ */ new Set([
36034
+ "number",
36035
+ "boolean",
36036
+ "tensor",
36037
+ "sparse_matrix"
36038
+ ]);
36039
+ function binaryLogicalMatch(argTypes) {
36040
+ if (argTypes.length !== 2) return null;
36041
+ if (!LOGICAL_KINDS.has(argTypes[0].kind)) return null;
36042
+ if (!LOGICAL_KINDS.has(argTypes[1].kind)) return null;
36043
+ if (argTypes[0].kind === "tensor" || argTypes[1].kind === "tensor") {
36044
+ return [{ kind: "tensor", isComplex: false, isLogical: true }];
36045
+ }
36046
+ if (argTypes[0].kind === "sparse_matrix" || argTypes[1].kind === "sparse_matrix") {
36047
+ return [{ kind: "tensor", isComplex: false, isLogical: true }];
36048
+ }
36049
+ return [{ kind: "boolean" }];
36050
+ }
36051
+ function isTensorLike(v) {
36052
+ return isRuntimeTensor(v) || isRuntimeSparseMatrix(v);
36053
+ }
36054
+ function applyBinaryLogical(args, op, scalarFn) {
36055
+ const a = args[0];
36056
+ const b = args[1];
36057
+ if (isTensorLike(a) || isTensorLike(b)) {
36058
+ return elementWiseLogicalOp(a, b, op);
36059
+ }
36060
+ return RTV.logical(scalarFn(toBool(a), toBool(b)));
36061
+ }
36062
+ var orCase = {
36063
+ match: binaryLogicalMatch,
36064
+ apply: (args) => applyBinaryLogical(
36065
+ args,
36066
+ (x, y) => x !== 0 || y !== 0 ? 1 : 0,
36067
+ (a, b) => a || b
36068
+ )
36069
+ };
36070
+ defineBuiltin({
36071
+ name: "or",
36072
+ help: {
36073
+ signatures: ["TF = or(A, B)"],
36074
+ description: "Logical OR. Functional form of A | B; returns a logical scalar or tensor."
36075
+ },
36076
+ cases: [orCase]
36077
+ });
36078
+ var andCase = {
36079
+ match: binaryLogicalMatch,
36080
+ apply: (args) => applyBinaryLogical(
36081
+ args,
36082
+ (x, y) => x !== 0 && y !== 0 ? 1 : 0,
36083
+ (a, b) => a && b
36084
+ )
36085
+ };
36086
+ defineBuiltin({
36087
+ name: "and",
36088
+ help: {
36089
+ signatures: ["TF = and(A, B)"],
36090
+ description: "Logical AND. Functional form of A & B; returns a logical scalar or tensor."
36091
+ },
36092
+ cases: [andCase]
36093
+ });
36094
+ defineBuiltin({
36095
+ name: "not",
36096
+ help: {
36097
+ signatures: ["TF = not(A)"],
36098
+ description: "Logical negation. Functional form of ~A; returns a logical scalar or tensor."
36099
+ },
36100
+ cases: [
36101
+ {
36102
+ match: (argTypes) => {
36103
+ if (argTypes.length !== 1) return null;
36104
+ if (!LOGICAL_KINDS.has(argTypes[0].kind)) return null;
36105
+ if (argTypes[0].kind === "tensor" || argTypes[0].kind === "sparse_matrix") {
36106
+ return [{ kind: "tensor", isComplex: false, isLogical: true }];
36107
+ }
36108
+ return [{ kind: "boolean" }];
36109
+ },
36110
+ apply: (args) => not(args[0])
36111
+ }
36112
+ ]
36113
+ });
36114
+
35251
36115
  // src/numbl-core/interpreter/builtins/utility.ts
35252
36116
  function sparseToDense2(S) {
35253
36117
  const data = new FloatXArray(S.m * S.n);
@@ -35356,7 +36220,7 @@ defineBuiltin({
35356
36220
  {
35357
36221
  match: (argTypes) => {
35358
36222
  if (argTypes.length < 1) return null;
35359
- return [{ kind: "number" }];
36223
+ return [];
35360
36224
  },
35361
36225
  apply: (args) => {
35362
36226
  const v = args[0];
@@ -35377,7 +36241,7 @@ defineBuiltin({
35377
36241
  const msg = args.length > 1 ? textValue(args[1]) ?? String(args[1]) : "Assertion failed";
35378
36242
  throw new Error(msg);
35379
36243
  }
35380
- return 0;
36244
+ return void 0;
35381
36245
  }
35382
36246
  }
35383
36247
  ]
@@ -35388,7 +36252,7 @@ defineBuiltin({
35388
36252
  {
35389
36253
  match: (argTypes) => {
35390
36254
  if (argTypes.length === 0) return null;
35391
- return [{ kind: "number" }];
36255
+ return [];
35392
36256
  },
35393
36257
  apply: (args) => {
35394
36258
  const first = textValue(args[0]) ?? String(args[0]);
@@ -36060,6 +36924,19 @@ defineBuiltin({
36060
36924
  name: "NaN",
36061
36925
  cases: arrayConstructorCases(nanFill, NaN)
36062
36926
  });
36927
+ function infFill(shape) {
36928
+ const data = new FloatXArray(numel(shape));
36929
+ data.fill(Infinity);
36930
+ return makeTensor(data, void 0, shape);
36931
+ }
36932
+ defineBuiltin({
36933
+ name: "inf",
36934
+ cases: arrayConstructorCases(infFill, Infinity)
36935
+ });
36936
+ defineBuiltin({
36937
+ name: "Inf",
36938
+ cases: arrayConstructorCases(infFill, Infinity)
36939
+ });
36063
36940
  defineBuiltin({
36064
36941
  name: "eye",
36065
36942
  cases: arrayConstructorCases(
@@ -36897,19 +37774,33 @@ function preserveTextType(t) {
36897
37774
  if (t.kind === "string") return { kind: "string" };
36898
37775
  return null;
36899
37776
  }
37777
+ function applyTextFn(v, fn) {
37778
+ if (isRuntimeCell(v)) {
37779
+ const out = new Array(v.data.length);
37780
+ for (let i = 0; i < v.data.length; i++) {
37781
+ out[i] = applyTextFn(v.data[i], fn);
37782
+ }
37783
+ return RTV.cell(out, [...v.shape]);
37784
+ }
37785
+ if (isRuntimeChar(v)) return RTV.char(fn(v.value));
37786
+ if (isRuntimeString(v)) return RTV.string(fn(toString(v)));
37787
+ return v;
37788
+ }
36900
37789
  function textPreserveResolve(fn) {
36901
37790
  return (argTypes) => {
36902
37791
  if (argTypes.length !== 1) return null;
36903
- const out = preserveTextType(argTypes[0]);
37792
+ const t = argTypes[0];
37793
+ if (t.kind === "cell") {
37794
+ return {
37795
+ outputTypes: [{ kind: "cell" }],
37796
+ apply: (args) => applyTextFn(args[0], fn)
37797
+ };
37798
+ }
37799
+ const out = preserveTextType(t);
36904
37800
  if (!out) return null;
36905
37801
  return {
36906
37802
  outputTypes: [out],
36907
- apply: (args) => {
36908
- const v = args[0];
36909
- const s = toString(v);
36910
- const result = fn(s);
36911
- return isRuntimeChar(v) ? RTV.char(result) : RTV.string(result);
36912
- }
37803
+ apply: (args) => applyTextFn(args[0], fn)
36913
37804
  };
36914
37805
  };
36915
37806
  }
@@ -38960,7 +39851,7 @@ defineBuiltin({
38960
39851
  cases: [
38961
39852
  {
38962
39853
  match: (argTypes, nargout) => {
38963
- if (nargout !== 1 || argTypes.length < 1 || argTypes.length > 2)
39854
+ if (nargout > 1 || argTypes.length < 1 || argTypes.length > 2)
38964
39855
  return null;
38965
39856
  if (!isNumericJitType(argTypes[0])) return null;
38966
39857
  return [NUM];
@@ -39077,7 +39968,7 @@ defineBuiltin({
39077
39968
  cases: [
39078
39969
  {
39079
39970
  match: (argTypes, nargout) => {
39080
- if (nargout !== 1 || argTypes.length < 1 || argTypes.length > 3)
39971
+ if (nargout > 1 || argTypes.length < 1 || argTypes.length > 3)
39081
39972
  return null;
39082
39973
  if (!isNumericJitType(argTypes[0])) return null;
39083
39974
  const a = argTypes[0];
@@ -39156,7 +40047,7 @@ defineBuiltin({
39156
40047
  cases: [
39157
40048
  {
39158
40049
  match: (argTypes, nargout) => {
39159
- if (nargout !== 1 || argTypes.length !== 2) return null;
40050
+ if (nargout > 1 || argTypes.length !== 2) return null;
39160
40051
  if (!isNumericJitType(argTypes[0]) || !isNumericJitType(argTypes[1]))
39161
40052
  return null;
39162
40053
  const hasTensor = argTypes.some((t) => t.kind === "tensor");
@@ -39240,7 +40131,7 @@ defineBuiltin({
39240
40131
  cases: [
39241
40132
  {
39242
40133
  match: (argTypes, nargout) => {
39243
- if (argTypes.length !== 1 || nargout !== 1) return null;
40134
+ if (argTypes.length !== 1 || nargout > 1) return null;
39244
40135
  if (!isNumericJitType(argTypes[0])) return null;
39245
40136
  const hasComplex = argTypes[0].kind === "complex_or_number" || argTypes[0].kind === "tensor" && argTypes[0].isComplex;
39246
40137
  return [hasComplex ? COMPLEX_OR_NUM : NUM];
@@ -39352,7 +40243,7 @@ defineBuiltin({
39352
40243
  cases: [
39353
40244
  {
39354
40245
  match: (argTypes, nargout) => {
39355
- if (argTypes.length !== 1 || nargout !== 1) return null;
40246
+ if (argTypes.length !== 1 || nargout > 1) return null;
39356
40247
  if (!isNumericJitType(argTypes[0])) return null;
39357
40248
  return [NUM];
39358
40249
  },
@@ -39377,7 +40268,7 @@ defineBuiltin({
39377
40268
  cases: [
39378
40269
  {
39379
40270
  match: (argTypes, nargout) => {
39380
- if (nargout !== 1) return null;
40271
+ if (nargout > 1) return null;
39381
40272
  if (argTypes.length !== 2 && argTypes.length !== 3) return null;
39382
40273
  if (!isNumericJitType(argTypes[0]) || !isNumericJitType(argTypes[1]))
39383
40274
  return null;
@@ -39443,7 +40334,7 @@ defineBuiltin({
39443
40334
  cases: [
39444
40335
  {
39445
40336
  match: (argTypes, nargout) => {
39446
- if (argTypes.length !== 1 || nargout !== 1) return null;
40337
+ if (argTypes.length !== 1 || nargout > 1) return null;
39447
40338
  if (!isNumericJitType(argTypes[0])) return null;
39448
40339
  const a = argTypes[0];
39449
40340
  if (a.kind === "number" || a.kind === "boolean") return [NUM];
@@ -39556,11 +40447,11 @@ function invComplexJS(dataRe, dataIm, n) {
39556
40447
  registerIBuiltin({
39557
40448
  name: "svd",
39558
40449
  resolve: (argTypes, nargout) => {
39559
- if (nargout < 1 || nargout > 3 || argTypes.length < 1 || argTypes.length > 2)
40450
+ if (nargout < 0 || nargout > 3 || argTypes.length < 1 || argTypes.length > 2)
39560
40451
  return null;
39561
40452
  if (!isNumericJitType(argTypes[0])) return null;
39562
40453
  const c = tensorType();
39563
- if (nargout === 1)
40454
+ if (nargout <= 1)
39564
40455
  return { outputTypes: [c], apply: (args, n) => svdApply(args, n) };
39565
40456
  return { outputTypes: [c, c, c], apply: (args, n) => svdApply(args, n) };
39566
40457
  }
@@ -39571,7 +40462,7 @@ function svdApply(args, nargout) {
39571
40462
  const A = args[0];
39572
40463
  if (isRuntimeNumber(A)) {
39573
40464
  const val = Math.abs(A);
39574
- if (nargout === 1) return RTV.tensor(new FloatXArray([val]), [1, 1]);
40465
+ if (nargout <= 1) return RTV.tensor(new FloatXArray([val]), [1, 1]);
39575
40466
  return [
39576
40467
  RTV.tensor(new FloatXArray([A >= 0 ? 1 : -1]), [1, 1]),
39577
40468
  RTV.tensor(new FloatXArray([val]), [1, 1]),
@@ -39598,7 +40489,7 @@ function svdApply(args, nargout) {
39598
40489
  nargout === 3
39599
40490
  );
39600
40491
  if (!result) throw new RuntimeError("svd: complex SVD failed");
39601
- if (nargout === 1) return RTV.tensor(new FloatXArray(result.S), [k, 1]);
40492
+ if (nargout <= 1) return RTV.tensor(new FloatXArray(result.S), [k, 1]);
39602
40493
  const uCols = econ ? k : m;
39603
40494
  const vCols = econ ? k : n;
39604
40495
  return [
@@ -39619,7 +40510,7 @@ function svdApply(args, nargout) {
39619
40510
  if (bridge?.svd) {
39620
40511
  const result = bridge.svd(toF64(A.data), m, n, econ, nargout === 3);
39621
40512
  if (result) {
39622
- if (nargout === 1) return RTV.tensor(new FloatXArray(result.S), [k, 1]);
40513
+ if (nargout <= 1) return RTV.tensor(new FloatXArray(result.S), [k, 1]);
39623
40514
  const uCols = econ ? k : m;
39624
40515
  const vCols = econ ? k : n;
39625
40516
  return [
@@ -39689,12 +40580,12 @@ function powerIterationEigenvalues(A_data, n, numEigenvalues) {
39689
40580
  registerIBuiltin({
39690
40581
  name: "qr",
39691
40582
  resolve: (argTypes, nargout) => {
39692
- if (nargout < 1 || nargout > 3 || argTypes.length < 1 || argTypes.length > 2)
40583
+ if (nargout < 0 || nargout > 3 || argTypes.length < 1 || argTypes.length > 2)
39693
40584
  return null;
39694
40585
  if (!isNumericJitType(argTypes[0])) return null;
39695
40586
  const isComplex2 = argTypes[0].kind === "tensor" && argTypes[0].isComplex;
39696
40587
  const t = tensorType(isComplex2 || void 0);
39697
- if (nargout === 1)
40588
+ if (nargout <= 1)
39698
40589
  return { outputTypes: [t], apply: (args, n) => qrApply(args, n) };
39699
40590
  if (nargout === 3)
39700
40591
  return {
@@ -39711,7 +40602,7 @@ function qrApply(args, nargout) {
39711
40602
  if (isRuntimeNumber(A)) {
39712
40603
  const val = A;
39713
40604
  const s = val >= 0 ? 1 : -1;
39714
- if (nargout === 1) return RTV.tensor(new FloatXArray([s * val]), [1, 1]);
40605
+ if (nargout <= 1) return RTV.tensor(new FloatXArray([s * val]), [1, 1]);
39715
40606
  if (nargout === 3)
39716
40607
  return [
39717
40608
  RTV.tensor(new FloatXArray([s]), [1, 1]),
@@ -39744,7 +40635,7 @@ function qrApply(args, nargout) {
39744
40635
  nargout === 2
39745
40636
  );
39746
40637
  if (!result) throw new RuntimeError("qr: complex QR failed");
39747
- if (nargout === 1) {
40638
+ if (nargout <= 1) {
39748
40639
  const rRows = econ ? k : m;
39749
40640
  return RTV.tensor(
39750
40641
  new FloatXArray(result.RRe),
@@ -39770,7 +40661,7 @@ function qrApply(args, nargout) {
39770
40661
  if (bridge?.qr) {
39771
40662
  const result = bridge.qr(toF64(A.data), m, n, econ, nargout === 2);
39772
40663
  if (result) {
39773
- if (nargout === 1)
40664
+ if (nargout <= 1)
39774
40665
  return RTV.tensor(new FloatXArray(result.R), [econ ? k : m, n]);
39775
40666
  const qCols = econ ? k : m;
39776
40667
  return [
@@ -39813,7 +40704,7 @@ function qrApply(args, nargout) {
39813
40704
  R_data[colMajorIndex(j + i, c, m)] -= scale * v[i];
39814
40705
  }
39815
40706
  }
39816
- if (nargout === 1) {
40707
+ if (nargout <= 1) {
39817
40708
  if (econ) {
39818
40709
  const R_econ = new FloatXArray(k * n);
39819
40710
  for (let r = 0; r < k; r++)
@@ -40029,11 +40920,11 @@ function qrPivotApply(A, m, n, k, econ) {
40029
40920
  registerIBuiltin({
40030
40921
  name: "lu",
40031
40922
  resolve: (argTypes, nargout) => {
40032
- if (nargout < 1 || nargout > 3) return null;
40923
+ if (nargout < 0 || nargout > 3) return null;
40033
40924
  if (argTypes.length < 1 || argTypes.length > 2) return null;
40034
40925
  if (!isNumericJitType(argTypes[0])) return null;
40035
40926
  const t = tensorType();
40036
- if (nargout === 1)
40927
+ if (nargout <= 1)
40037
40928
  return { outputTypes: [t], apply: (args, n) => luApply(args, n) };
40038
40929
  if (nargout === 2)
40039
40930
  return { outputTypes: [t, t], apply: (args, n) => luApply(args, n) };
@@ -40052,7 +40943,7 @@ function luApply(args, nargout) {
40052
40943
  if (nargout <= 2) {
40053
40944
  const L2 = RTV.tensor(new FloatXArray([1]), [1, 1]);
40054
40945
  const U2 = RTV.tensor(new FloatXArray([val]), [1, 1]);
40055
- if (nargout === 1) return L2;
40946
+ if (nargout <= 1) return L2;
40056
40947
  return [L2, U2];
40057
40948
  }
40058
40949
  const L = RTV.tensor(new FloatXArray([1]), [1, 1]);
@@ -40090,7 +40981,7 @@ function luApply(args, nargout) {
40090
40981
  if (U_im && LU_im) U_im[i + j * k] = LU_im[i + j * m];
40091
40982
  }
40092
40983
  }
40093
- if (nargout === 1)
40984
+ if (nargout <= 1)
40094
40985
  return RTV.tensor(
40095
40986
  new FloatXArray(LU_re),
40096
40987
  [m, n],
@@ -40166,11 +41057,11 @@ function ipivToPermVector(ipiv, m) {
40166
41057
  registerIBuiltin({
40167
41058
  name: "eig",
40168
41059
  resolve: (argTypes, nargout) => {
40169
- if (nargout < 1 || nargout > 3 || argTypes.length < 1 || argTypes.length > 3)
41060
+ if (nargout < 0 || nargout > 3 || argTypes.length < 1 || argTypes.length > 3)
40170
41061
  return null;
40171
41062
  if (!isNumericJitType(argTypes[0])) return null;
40172
41063
  const c = tensorType(true);
40173
- if (nargout === 1)
41064
+ if (nargout <= 1)
40174
41065
  return { outputTypes: [c], apply: (args, n) => eigApply(args, n) };
40175
41066
  if (nargout === 2)
40176
41067
  return { outputTypes: [c, c], apply: (args, n) => eigApply(args, n) };
@@ -40184,7 +41075,7 @@ function eigApply(args, nargout) {
40184
41075
  const { balance, outputForm } = parseEigOptionsRuntime(args);
40185
41076
  if (isRuntimeNumber(A)) {
40186
41077
  const val = A;
40187
- if (nargout === 1) return RTV.num(val);
41078
+ if (nargout <= 1) return RTV.num(val);
40188
41079
  const V = RTV.tensor(new FloatXArray([1]), [1, 1]);
40189
41080
  if (nargout === 2) {
40190
41081
  if (outputForm === "vector") return [V, RTV.num(val)];
@@ -40213,7 +41104,7 @@ function eigApply(args, nargout) {
40213
41104
  );
40214
41105
  if (!result2) throw new RuntimeError("eig: complex eig failed");
40215
41106
  const { wRe, wIm, VLRe, VLIm, VRRe, VRIm } = result2;
40216
- if (nargout === 1) return maybeComplexTensor(wRe, [n, 1], wIm);
41107
+ if (nargout <= 1) return maybeComplexTensor(wRe, [n, 1], wIm);
40217
41108
  const Vout2 = computeVR && VRRe && VRIm ? maybeComplexTensor(VRRe, [n, n], VRIm) : RTV.tensor(new FloatXArray(n * n), [n, n]);
40218
41109
  const Dout2 = outputForm === "vector" ? maybeComplexTensor(wRe, [n, 1], wIm) : buildDiagMatrix(wRe, wIm, n);
40219
41110
  if (nargout === 2) return [Vout2, Dout2];
@@ -40226,7 +41117,7 @@ function eigApply(args, nargout) {
40226
41117
  if (!result) throw new RuntimeError("eig: LAPACK eig failed");
40227
41118
  const { wr, wi, VL, VR } = result;
40228
41119
  const hasComplex = wi.some((v) => v !== 0);
40229
- if (nargout === 1) return maybeComplexTensor(wr, [n, 1], wi);
41120
+ if (nargout <= 1) return maybeComplexTensor(wr, [n, 1], wi);
40230
41121
  const Vout = computeVR && VR ? buildEigenvectorMatrix(VR, wi, n, hasComplex) : RTV.tensor(new FloatXArray(n * n), [n, n]);
40231
41122
  const Dout = outputForm === "vector" ? maybeComplexTensor(wr, [n, 1], wi) : buildDiagMatrix(wr, wi, n);
40232
41123
  if (nargout === 2) return [Vout, Dout];
@@ -40250,11 +41141,11 @@ function parseEigOptionsRuntime(args) {
40250
41141
  registerIBuiltin({
40251
41142
  name: "chol",
40252
41143
  resolve: (argTypes, nargout) => {
40253
- if (nargout < 1 || nargout > 3 || argTypes.length < 1 || argTypes.length > 3)
41144
+ if (nargout < 0 || nargout > 3 || argTypes.length < 1 || argTypes.length > 3)
40254
41145
  return null;
40255
41146
  if (!isNumericJitType(argTypes[0])) return null;
40256
41147
  const t = tensorType();
40257
- if (nargout === 1)
41148
+ if (nargout <= 1)
40258
41149
  return { outputTypes: [t], apply: (args, n) => cholApply(args, n) };
40259
41150
  if (nargout === 2)
40260
41151
  return { outputTypes: [t, NUM], apply: (args, n) => cholApply(args, n) };
@@ -40415,7 +41306,7 @@ defineBuiltin({
40415
41306
  cases: [
40416
41307
  {
40417
41308
  match: (argTypes, nargout) => {
40418
- if (argTypes.length !== 2 || nargout !== 1) return null;
41309
+ if (argTypes.length !== 2 || nargout > 1) return null;
40419
41310
  if (!isNumericJitType(argTypes[0]) || !isNumericJitType(argTypes[1]))
40420
41311
  return null;
40421
41312
  return [tensorType()];
@@ -40458,7 +41349,7 @@ defineBuiltin({
40458
41349
  cases: [
40459
41350
  {
40460
41351
  match: (argTypes, nargout) => {
40461
- if (nargout !== 1 || argTypes.length < 1 || argTypes.length > 2)
41352
+ if (nargout > 1 || argTypes.length < 1 || argTypes.length > 2)
40462
41353
  return null;
40463
41354
  if (!isNumericJitType(argTypes[0])) return null;
40464
41355
  return [NUM];
@@ -40519,7 +41410,7 @@ defineBuiltin({
40519
41410
  cases: [
40520
41411
  {
40521
41412
  match: (argTypes, nargout) => {
40522
- if (nargout !== 1 || argTypes.length < 1 || argTypes.length > 2)
41413
+ if (nargout > 1 || argTypes.length < 1 || argTypes.length > 2)
40523
41414
  return null;
40524
41415
  if (!isNumericJitType(argTypes[0])) return null;
40525
41416
  return [NUM];
@@ -40567,7 +41458,7 @@ defineBuiltin({
40567
41458
  cases: [
40568
41459
  {
40569
41460
  match: (argTypes, nargout) => {
40570
- if (nargout !== 1 || argTypes.length < 1 || argTypes.length > 2)
41461
+ if (nargout > 1 || argTypes.length < 1 || argTypes.length > 2)
40571
41462
  return null;
40572
41463
  if (!isNumericJitType(argTypes[0])) return null;
40573
41464
  const a = argTypes[0];
@@ -40664,7 +41555,7 @@ defineBuiltin({
40664
41555
  cases: [
40665
41556
  {
40666
41557
  match: (argTypes, nargout) => {
40667
- if (nargout !== 1 || argTypes.length !== 2) return null;
41558
+ if (nargout > 1 || argTypes.length !== 2) return null;
40668
41559
  if (!isNumericJitType(argTypes[0]) || !isNumericJitType(argTypes[1]))
40669
41560
  return null;
40670
41561
  return [tensorType()];
@@ -40672,11 +41563,15 @@ defineBuiltin({
40672
41563
  apply: (args) => {
40673
41564
  if (args.length !== 2)
40674
41565
  throw new RuntimeError("kron requires 2 arguments");
40675
- const a = args[0], b = args[1];
40676
- const A = isRuntimeNumber(a) ? RTV.tensor(new FloatXArray([a]), [1, 1]) : a;
40677
- const B = isRuntimeNumber(b) ? RTV.tensor(new FloatXArray([b]), [1, 1]) : b;
40678
- if (!isRuntimeTensor(A) || !isRuntimeTensor(B))
41566
+ const coerce = (v) => {
41567
+ if (isRuntimeNumber(v))
41568
+ return RTV.tensor(new FloatXArray([v]), [1, 1]);
41569
+ if (isRuntimeSparseMatrix(v)) return sparseToDense(v);
41570
+ if (isRuntimeTensor(v)) return v;
40679
41571
  throw new RuntimeError("kron: arguments must be numeric");
41572
+ };
41573
+ const A = coerce(args[0]);
41574
+ const B = coerce(args[1]);
40680
41575
  const [m, n] = tensorSize2D(A);
40681
41576
  const [p2, q] = tensorSize2D(B);
40682
41577
  const rows = m * p2, cols = n * q;
@@ -40700,7 +41595,7 @@ defineBuiltin({
40700
41595
  cases: [
40701
41596
  {
40702
41597
  match: (argTypes, nargout) => {
40703
- if (nargout !== 1 || argTypes.length === 0) return null;
41598
+ if (nargout > 1 || argTypes.length === 0) return null;
40704
41599
  if (!argTypes.every(isNumericJitType)) return null;
40705
41600
  return [tensorType()];
40706
41601
  },
@@ -40743,7 +41638,7 @@ defineBuiltin({
40743
41638
  cases: [
40744
41639
  {
40745
41640
  match: (argTypes, nargout) => {
40746
- if (nargout !== 1) return null;
41641
+ if (nargout > 1) return null;
40747
41642
  if (argTypes.length !== 2 && argTypes.length !== 4) return null;
40748
41643
  const xIdx = 0, yIdx = argTypes.length === 4 ? 2 : 1;
40749
41644
  if (!isNumericJitType(argTypes[xIdx]) || !isNumericJitType(argTypes[yIdx]))
@@ -40872,7 +41767,7 @@ defineBuiltin({
40872
41767
  cases: [
40873
41768
  {
40874
41769
  match: (argTypes, nargout) => {
40875
- if (nargout !== 1 || argTypes.length !== 1) return null;
41770
+ if (nargout > 1 || argTypes.length !== 1) return null;
40876
41771
  if (argTypes[0].kind !== "tensor") return null;
40877
41772
  return [tensorType(argTypes[0].isComplex)];
40878
41773
  },
@@ -42994,6 +43889,65 @@ defineBuiltin({
42994
43889
  }
42995
43890
  ]
42996
43891
  });
43892
+ defineBuiltin({
43893
+ name: "bitget",
43894
+ cases: [
43895
+ {
43896
+ match: (argTypes) => {
43897
+ if (argTypes.length !== 2) return null;
43898
+ return [{ kind: "unknown" }];
43899
+ },
43900
+ // bitget(A, bit) returns bit number `bit` (1-based, 1 = LSB) of each
43901
+ // element of A. MATLAB supports vector `bit` with broadcasting; we
43902
+ // match the scalar-or-same-shape rules used by the other bitwise ops.
43903
+ apply: (args) => bitwiseOp(
43904
+ args[0],
43905
+ args[1],
43906
+ (a, bit) => {
43907
+ const b = Math.round(bit);
43908
+ if (b < 1) return 0;
43909
+ if (b <= 31) return a >>> b - 1 & 1;
43910
+ const bi = BigInt(a);
43911
+ return Number(bi >> BigInt(b - 1) & 1n);
43912
+ },
43913
+ "bitget"
43914
+ )
43915
+ }
43916
+ ]
43917
+ });
43918
+ defineBuiltin({
43919
+ name: "bitset",
43920
+ cases: [
43921
+ {
43922
+ match: (argTypes) => {
43923
+ if (argTypes.length < 2 || argTypes.length > 3) return null;
43924
+ return [{ kind: "unknown" }];
43925
+ },
43926
+ // bitset(A, bit) → set bit to 1
43927
+ // bitset(A, bit, v) → set bit to v (0 or 1)
43928
+ apply: (args) => {
43929
+ const v = args.length >= 3 ? Math.round(toNumber(args[2])) : 1;
43930
+ return bitwiseOp(
43931
+ args[0],
43932
+ args[1],
43933
+ (a, bit) => {
43934
+ const b = Math.round(bit);
43935
+ if (b < 1) return a;
43936
+ if (b <= 31) {
43937
+ const mask2 = 1 << b - 1;
43938
+ return v ? a | mask2 : a & ~mask2;
43939
+ }
43940
+ const bi = BigInt(a);
43941
+ const mask = 1n << BigInt(b - 1);
43942
+ const out = v ? bi | mask : bi & ~mask;
43943
+ return Number(out);
43944
+ },
43945
+ "bitset"
43946
+ );
43947
+ }
43948
+ }
43949
+ ]
43950
+ });
42997
43951
  function coordTransform(name, nArgs, nOut, fn) {
42998
43952
  defineBuiltin({
42999
43953
  name,
@@ -44123,6 +45077,131 @@ defineBuiltin({
44123
45077
  }
44124
45078
  ]
44125
45079
  });
45080
+ var INT_RANGES = [
45081
+ { name: "int8", min: -128, max: 127 },
45082
+ { name: "int16", min: -32768, max: 32767 },
45083
+ { name: "int32", min: -2147483648, max: 2147483647 },
45084
+ // int64/uint64 can't represent their full native range as doubles;
45085
+ // clamp at Number.MAX_SAFE_INTEGER to avoid silent precision loss.
45086
+ {
45087
+ name: "int64",
45088
+ min: -Number.MAX_SAFE_INTEGER,
45089
+ max: Number.MAX_SAFE_INTEGER
45090
+ },
45091
+ { name: "uint8", min: 0, max: 255 },
45092
+ { name: "uint16", min: 0, max: 65535 },
45093
+ { name: "uint32", min: 0, max: 4294967295 },
45094
+ { name: "uint64", min: 0, max: Number.MAX_SAFE_INTEGER }
45095
+ ];
45096
+ function saturateRoundToward(x, min, max) {
45097
+ if (isNaN(x)) return 0;
45098
+ const r = x >= 0 ? Math.floor(x + 0.5) : -Math.floor(-x + 0.5);
45099
+ if (r < min) return min;
45100
+ if (r > max) return max;
45101
+ return r;
45102
+ }
45103
+ for (const { name, min, max } of INT_RANGES) {
45104
+ defineBuiltin({
45105
+ name,
45106
+ cases: [
45107
+ {
45108
+ match: (argTypes) => {
45109
+ if (argTypes.length !== 1) return null;
45110
+ const a = argTypes[0];
45111
+ if (a.kind === "number" || a.kind === "boolean" || a.kind === "char" || a.kind === "complex_or_number")
45112
+ return [{ kind: "number" }];
45113
+ if (a.kind === "tensor")
45114
+ return [
45115
+ {
45116
+ kind: "tensor",
45117
+ isComplex: false,
45118
+ shape: a.shape,
45119
+ ndim: a.ndim
45120
+ }
45121
+ ];
45122
+ return null;
45123
+ },
45124
+ apply: (args) => {
45125
+ const v = args[0];
45126
+ if (isRuntimeNumber(v))
45127
+ return RTV.num(saturateRoundToward(v, min, max));
45128
+ if (isRuntimeLogical(v)) return RTV.num(v ? 1 : 0);
45129
+ if (isRuntimeComplexNumber(v))
45130
+ return RTV.num(saturateRoundToward(v.re, min, max));
45131
+ if (isRuntimeChar(v)) {
45132
+ if (v.value.length === 0)
45133
+ return RTV.tensor(new FloatXArray(0), [0, 0]);
45134
+ if (v.value.length === 1)
45135
+ return RTV.num(
45136
+ saturateRoundToward(v.value.charCodeAt(0), min, max)
45137
+ );
45138
+ const out = new FloatXArray(v.value.length);
45139
+ for (let i = 0; i < v.value.length; i++) {
45140
+ out[i] = saturateRoundToward(v.value.charCodeAt(i), min, max);
45141
+ }
45142
+ return RTV.row(Array.from(out));
45143
+ }
45144
+ if (isRuntimeTensor(v)) {
45145
+ const data = new FloatXArray(v.data.length);
45146
+ for (let i = 0; i < v.data.length; i++) {
45147
+ data[i] = saturateRoundToward(v.data[i], min, max);
45148
+ }
45149
+ return RTV.tensor(data, [...v.shape]);
45150
+ }
45151
+ return RTV.num(saturateRoundToward(toNumber(v), min, max));
45152
+ }
45153
+ }
45154
+ ]
45155
+ });
45156
+ }
45157
+ defineBuiltin({
45158
+ name: "idivide",
45159
+ cases: [
45160
+ {
45161
+ match: (argTypes) => {
45162
+ if (argTypes.length < 2 || argTypes.length > 3) return null;
45163
+ return [{ kind: "unknown" }];
45164
+ },
45165
+ apply: (args) => {
45166
+ const divFix = (a2, b2) => {
45167
+ if (b2 === 0) {
45168
+ return 0;
45169
+ }
45170
+ const q = a2 / b2;
45171
+ return q >= 0 ? Math.floor(q) : -Math.floor(-q);
45172
+ };
45173
+ const a = args[0];
45174
+ const b = args[1];
45175
+ if (isRuntimeNumber(a) && isRuntimeNumber(b)) {
45176
+ return RTV.num(divFix(a, b));
45177
+ }
45178
+ if (isRuntimeTensor(a) && isRuntimeNumber(b)) {
45179
+ const bv = b;
45180
+ const data = new FloatXArray(a.data.length);
45181
+ for (let i = 0; i < a.data.length; i++)
45182
+ data[i] = divFix(a.data[i], bv);
45183
+ return RTV.tensor(data, [...a.shape]);
45184
+ }
45185
+ if (isRuntimeNumber(a) && isRuntimeTensor(b)) {
45186
+ const av = a;
45187
+ const data = new FloatXArray(b.data.length);
45188
+ for (let i = 0; i < b.data.length; i++)
45189
+ data[i] = divFix(av, b.data[i]);
45190
+ return RTV.tensor(data, [...b.shape]);
45191
+ }
45192
+ if (isRuntimeTensor(a) && isRuntimeTensor(b)) {
45193
+ if (a.data.length !== b.data.length)
45194
+ throw new RuntimeError("idivide: arrays must be the same size");
45195
+ const data = new FloatXArray(a.data.length);
45196
+ for (let i = 0; i < a.data.length; i++)
45197
+ data[i] = divFix(a.data[i], b.data[i]);
45198
+ return RTV.tensor(data, [...a.shape]);
45199
+ }
45200
+ throw new RuntimeError("idivide: arguments must be numeric");
45201
+ }
45202
+ }
45203
+ ]
45204
+ });
44126
45205
  defineBuiltin({
44127
45206
  name: "logical",
44128
45207
  cases: [
@@ -44734,9 +45813,11 @@ registerIBuiltin({
44734
45813
  // src/numbl-core/helpers/prng.ts
44735
45814
  var _rngState = null;
44736
45815
  var _rngSeed = 0;
45816
+ var _bmSpare = null;
44737
45817
  function setRngShuffle() {
44738
45818
  _rngState = null;
44739
45819
  _rngSeed = 0;
45820
+ _bmSpare = null;
44740
45821
  }
44741
45822
  function setRngSeed(seed) {
44742
45823
  _rngSeed = seed;
@@ -44752,6 +45833,7 @@ function splitmix32(seed) {
44752
45833
  };
44753
45834
  }
44754
45835
  function seedRng(seed) {
45836
+ _bmSpare = null;
44755
45837
  const sm = splitmix32(seed);
44756
45838
  _rngState = new Uint32Array([sm(), sm(), sm(), sm()]);
44757
45839
  if (_rngState[0] === 0 && _rngState[1] === 0 && _rngState[2] === 0 && _rngState[3] === 0) {
@@ -44778,10 +45860,60 @@ function rngRandom() {
44778
45860
  return (xoshiro128ss() >>> 0) / 4294967296;
44779
45861
  }
44780
45862
  function boxMullerRandom() {
44781
- let u = 0, v = 0;
44782
- while (u === 0) u = rngRandom();
44783
- while (v === 0) v = rngRandom();
44784
- return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
45863
+ if (_bmSpare !== null) {
45864
+ const s2 = _bmSpare;
45865
+ _bmSpare = null;
45866
+ return s2;
45867
+ }
45868
+ let u, v, s;
45869
+ do {
45870
+ u = 2 * rngRandom() - 1;
45871
+ v = 2 * rngRandom() - 1;
45872
+ s = u * u + v * v;
45873
+ } while (s >= 1 || s === 0);
45874
+ const mul = Math.sqrt(-2 * Math.log(s) / s);
45875
+ _bmSpare = v * mul;
45876
+ return u * mul;
45877
+ }
45878
+ function fillRandn(data) {
45879
+ if (_rngState !== null) {
45880
+ const bridge = getLapackBridge();
45881
+ if (bridge?.fillRandn) {
45882
+ const r = bridge.fillRandn(
45883
+ _rngState,
45884
+ data.length,
45885
+ _bmSpare ?? 0,
45886
+ _bmSpare !== null
45887
+ );
45888
+ _bmSpare = r.hasSpare ? r.spare : null;
45889
+ if (data instanceof Float64Array) {
45890
+ data.set(r.data);
45891
+ } else {
45892
+ for (let i2 = 0; i2 < data.length; i2++) data[i2] = r.data[i2];
45893
+ }
45894
+ return;
45895
+ }
45896
+ }
45897
+ const n = data.length;
45898
+ let i = 0;
45899
+ if (_bmSpare !== null && i < n) {
45900
+ data[i++] = _bmSpare;
45901
+ _bmSpare = null;
45902
+ }
45903
+ for (; i + 1 < n; i += 2) {
45904
+ let u, v, s;
45905
+ do {
45906
+ u = 2 * rngRandom() - 1;
45907
+ v = 2 * rngRandom() - 1;
45908
+ s = u * u + v * v;
45909
+ } while (s >= 1 || s === 0);
45910
+ const mul = Math.sqrt(-2 * Math.log(s) / s);
45911
+ data[i] = u * mul;
45912
+ data[i + 1] = v * mul;
45913
+ }
45914
+ if (i < n) {
45915
+ data[i] = boxMullerRandom();
45916
+ }
44785
45917
  }
44786
45918
  function getRngStateStruct() {
44787
45919
  const stateArray = _rngState ? RTV.tensor(new FloatXArray(Array.from(_rngState).map((v) => v)), [4, 1]) : RTV.tensor(new FloatXArray(0), [0, 1]);
@@ -44849,7 +45981,7 @@ registerIBuiltin({
44849
45981
  };
44850
45982
  }
44851
45983
  });
44852
- function registerRandBuiltin(name, gen) {
45984
+ function registerRandBuiltin(name, gen, bulkFill) {
44853
45985
  defineBuiltin({
44854
45986
  name,
44855
45987
  cases: [
@@ -44888,7 +46020,11 @@ function registerRandBuiltin(name, gen) {
44888
46020
  if (shape.length === 1) shape.push(shape[0]);
44889
46021
  const n = numel(shape);
44890
46022
  const data = new FloatXArray(n);
44891
- for (let i = 0; i < n; i++) data[i] = gen();
46023
+ if (bulkFill) {
46024
+ bulkFill(data);
46025
+ } else {
46026
+ for (let i = 0; i < n; i++) data[i] = gen();
46027
+ }
44892
46028
  return RTV.tensor(data, shape);
44893
46029
  }
44894
46030
  }
@@ -44896,7 +46032,7 @@ function registerRandBuiltin(name, gen) {
44896
46032
  });
44897
46033
  }
44898
46034
  registerRandBuiltin("rand", rngRandom);
44899
- registerRandBuiltin("randn", boxMullerRandom);
46035
+ registerRandBuiltin("randn", boxMullerRandom, fillRandn);
44900
46036
  defineBuiltin({
44901
46037
  name: "randi",
44902
46038
  cases: [
@@ -45341,136 +46477,6 @@ registerIBuiltin({
45341
46477
  }
45342
46478
  });
45343
46479
 
45344
- // src/numbl-core/interpreter/builtins/time-system.ts
45345
- var ticTime = 0;
45346
- defineBuiltin({
45347
- name: "tic",
45348
- cases: [
45349
- {
45350
- match: (argTypes) => argTypes.length === 0 ? [{ kind: "number" }] : null,
45351
- apply: () => {
45352
- ticTime = performance.now();
45353
- return RTV.num(ticTime / 1e3);
45354
- }
45355
- }
45356
- ]
45357
- });
45358
- defineBuiltin({
45359
- name: "toc",
45360
- cases: [
45361
- {
45362
- match: (argTypes) => argTypes.length === 0 ? [{ kind: "number" }] : null,
45363
- apply: () => RTV.num((performance.now() - ticTime) / 1e3)
45364
- }
45365
- ]
45366
- });
45367
- defineBuiltin({
45368
- name: "clock",
45369
- cases: [
45370
- {
45371
- match: (argTypes) => argTypes.length === 0 ? [{ kind: "tensor", isComplex: false, shape: [1, 6] }] : null,
45372
- apply: () => {
45373
- const now = /* @__PURE__ */ new Date();
45374
- return RTV.tensor(
45375
- new FloatXArray([
45376
- now.getFullYear(),
45377
- now.getMonth() + 1,
45378
- now.getDate(),
45379
- now.getHours(),
45380
- now.getMinutes(),
45381
- now.getSeconds() + now.getMilliseconds() / 1e3
45382
- ]),
45383
- [1, 6]
45384
- );
45385
- }
45386
- }
45387
- ]
45388
- });
45389
- defineBuiltin({
45390
- name: "etime",
45391
- cases: [
45392
- {
45393
- match: (argTypes) => argTypes.length === 2 ? [{ kind: "number" }] : null,
45394
- apply: (args) => {
45395
- const t1 = args[0];
45396
- const t0 = args[1];
45397
- if (!isRuntimeTensor(t1) || !isRuntimeTensor(t0))
45398
- throw new RuntimeError("etime: arguments must be clock vectors");
45399
- const toMs = (t) => {
45400
- const d = new Date(
45401
- t.data[0],
45402
- t.data[1] - 1,
45403
- t.data[2],
45404
- t.data[3],
45405
- t.data[4],
45406
- Math.floor(t.data[5]),
45407
- t.data[5] % 1 * 1e3
45408
- );
45409
- return d.getTime();
45410
- };
45411
- return RTV.num((toMs(t1) - toMs(t0)) / 1e3);
45412
- }
45413
- }
45414
- ]
45415
- });
45416
- defineBuiltin({
45417
- name: "version",
45418
- cases: [
45419
- {
45420
- match: (argTypes) => argTypes.length === 0 ? [{ kind: "char" }] : null,
45421
- apply: () => RTV.char("9.14.0")
45422
- }
45423
- ]
45424
- });
45425
- function getComputerStrings() {
45426
- if (typeof process === "undefined") {
45427
- return { str: "BROWSER", arch: "browser" };
45428
- }
45429
- const platform = process.platform;
45430
- const cpuArch = process.arch;
45431
- if (platform === "win32") return { str: "PCWIN64", arch: "win64" };
45432
- if (platform === "darwin") {
45433
- if (cpuArch === "arm64") return { str: "MACA64", arch: "maca64" };
45434
- return { str: "MACI64", arch: "maci64" };
45435
- }
45436
- return { str: "GLNXA64", arch: "glnxa64" };
45437
- }
45438
- registerIBuiltin({
45439
- name: "computer",
45440
- resolve: () => ({
45441
- outputTypes: [{ kind: "unknown" }],
45442
- apply: (args, nargout) => {
45443
- const info = getComputerStrings();
45444
- if (args.length >= 1 && isRuntimeChar(args[0])) {
45445
- const arg = toString(args[0]);
45446
- if (arg === "arch") return RTV.char(info.arch);
45447
- throw new RuntimeError(`computer: unknown argument '${arg}'`);
45448
- }
45449
- const maxsize = 2 ** 48 - 1;
45450
- const endian = RTV.char("L");
45451
- if (nargout <= 1) return RTV.char(info.str);
45452
- if (nargout === 2) return [RTV.char(info.str), RTV.num(maxsize)];
45453
- return [RTV.char(info.str), RTV.num(maxsize), endian];
45454
- }
45455
- })
45456
- });
45457
- var _platform = typeof process !== "undefined" ? process.platform : "linux";
45458
- for (const [name, val] of [
45459
- ["ismac", _platform === "darwin"],
45460
- ["ispc", _platform === "win32"],
45461
- ["isunix", _platform !== "win32"]
45462
- ]) {
45463
- defineBuiltin({
45464
- name,
45465
- cases: [
45466
- {
45467
- match: (argTypes) => argTypes.length === 0 ? [{ kind: "boolean" }] : null,
45468
- apply: () => RTV.logical(val)
45469
- }
45470
- ]
45471
- });
45472
- }
45473
-
45474
46480
  // src/numbl-core/interpreter/builtins/sparse.ts
45475
46481
  function toNumericArray(v, name) {
45476
46482
  if (isRuntimeNumber(v)) return [v];
@@ -48330,7 +49336,7 @@ function getSourceLine(getSource, file, line) {
48330
49336
  }
48331
49337
 
48332
49338
  // src/numbl-core/version.ts
48333
- var NUMBL_VERSION = "0.1.2";
49339
+ var NUMBL_VERSION = "0.1.4";
48334
49340
 
48335
49341
  // src/cli-repl.ts
48336
49342
  import { createInterface } from "readline";
@@ -49592,9 +50598,7 @@ function lowerStmt(ctx, stmt) {
49592
50598
  result = lowerAssign(ctx, stmt);
49593
50599
  break;
49594
50600
  case "ExprStmt":
49595
- if (!stmt.suppressed) return null;
49596
- result = lowerExprStmt(ctx, stmt);
49597
- break;
50601
+ return null;
49598
50602
  case "If":
49599
50603
  result = lowerIf(ctx, stmt);
49600
50604
  break;
@@ -49669,11 +50673,6 @@ function lowerMultiAssign(ctx, stmt) {
49669
50673
  }
49670
50674
  ];
49671
50675
  }
49672
- function lowerExprStmt(ctx, stmt) {
49673
- const expr = lowerExpr(ctx, stmt.expr);
49674
- if (!expr) return null;
49675
- return [{ tag: "ExprStmt", expr }];
49676
- }
49677
50676
  function lowerIf(ctx, stmt) {
49678
50677
  const cond = lowerExpr(ctx, stmt.cond);
49679
50678
  if (!cond) return null;
@@ -50742,10 +51741,14 @@ function execStmt(stmt) {
50742
51741
  }
50743
51742
  switch (stmt.type) {
50744
51743
  case "ExprStmt": {
50745
- const val = this.evalExpr(stmt.expr);
51744
+ const val = this.evalExprNargout(stmt.expr, 0);
50746
51745
  const singleVal = Array.isArray(val) ? val[0] : val;
51746
+ if (singleVal === void 0) {
51747
+ return null;
51748
+ }
50747
51749
  const rv = ensureRuntimeValue(singleVal);
50748
51750
  this.ans = rv;
51751
+ this.env.set("ans", rv);
50749
51752
  if (!stmt.suppressed && !this.isOutputExpr(stmt.expr)) {
50750
51753
  this.rt.displayResult(rv);
50751
51754
  }
@@ -50766,19 +51769,25 @@ function execStmt(stmt) {
50766
51769
  if (stmt.lvalues.length === 1 && stmt.lvalues[0].type === "IndexCell") {
50767
51770
  const lv = stmt.lvalues[0];
50768
51771
  const cellBase = lv.base.type === "Ident" ? this.env.get(lv.base.name) ?? RTV.cell([], [0, 0]) : this.evalExpr(lv.base);
50769
- const indices = lv.indices.map((idx) => this.evalExpr(idx));
50770
- const idxVal = ensureRuntimeValue(indices[0]);
51772
+ const indices = this.evalIndicesWithEnd(cellBase, lv.indices);
50771
51773
  let expandedCount = 1;
50772
- if (isRuntimeTensor(idxVal)) {
50773
- expandedCount = idxVal.data.length;
50774
- } else if (typeof idxVal === "number") {
50775
- expandedCount = 1;
51774
+ const idx0 = indices[0];
51775
+ if (idx0 === COLON_SENTINEL) {
51776
+ const baseRv = ensureRuntimeValue(cellBase);
51777
+ expandedCount = isRuntimeCell(baseRv) ? baseRv.data.length : 0;
51778
+ } else {
51779
+ const idxVal = ensureRuntimeValue(idx0);
51780
+ if (isRuntimeTensor(idxVal)) {
51781
+ expandedCount = idxVal.data.length;
51782
+ } else if (typeof idxVal === "number") {
51783
+ expandedCount = 1;
51784
+ }
50776
51785
  }
50777
51786
  const val2 = this.evalExprNargout(stmt.expr, expandedCount);
50778
51787
  const values2 = Array.isArray(val2) ? val2 : [val2];
50779
51788
  const result = this.rt.multiOutputCellAssign(
50780
51789
  cellBase,
50781
- indices[0],
51790
+ idx0,
50782
51791
  values2.map((v) => ensureRuntimeValue(v))
50783
51792
  );
50784
51793
  if (lv.base.type === "Ident") {
@@ -50795,10 +51804,12 @@ function execStmt(stmt) {
50795
51804
  const rv = this.rt.share(i < values.length ? values[i] : void 0);
50796
51805
  this.assignLValue(lv, rv);
50797
51806
  }
50798
- if (!stmt.suppressed && values.length > 0) {
50799
- const firstLv = stmt.lvalues[0];
50800
- if (firstLv.type === "Var") {
50801
- this.rt.displayAssign(firstLv.name, ensureRuntimeValue(values[0]));
51807
+ if (!stmt.suppressed) {
51808
+ for (let i = 0; i < stmt.lvalues.length; i++) {
51809
+ const lv = stmt.lvalues[i];
51810
+ if (lv.type === "Var" && i < values.length) {
51811
+ this.rt.displayAssign(lv.name, ensureRuntimeValue(values[i]));
51812
+ }
50802
51813
  }
50803
51814
  }
50804
51815
  return null;
@@ -51155,6 +52166,18 @@ function evalArgs(argExprs) {
51155
52166
  }
51156
52167
  return args;
51157
52168
  }
52169
+ var binopProfileName = {
52170
+ ["Add" /* Add */]: "plus",
52171
+ ["Sub" /* Sub */]: "minus",
52172
+ ["Mul" /* Mul */]: "mtimes",
52173
+ ["ElemMul" /* ElemMul */]: "times",
52174
+ ["Div" /* Div */]: "mrdivide",
52175
+ ["ElemDiv" /* ElemDiv */]: "rdivide",
52176
+ ["LeftDiv" /* LeftDiv */]: "mldivide",
52177
+ ["ElemLeftDiv" /* ElemLeftDiv */]: "ldivide",
52178
+ ["Pow" /* Pow */]: "mpower",
52179
+ ["ElemPow" /* ElemPow */]: "power"
52180
+ };
51158
52181
  function evalBinary(expr) {
51159
52182
  if (expr.op === "AndAnd" /* AndAnd */) {
51160
52183
  const left2 = this.evalExpr(expr.left);
@@ -51180,6 +52203,13 @@ function evalBinary(expr) {
51180
52203
  if (!isNaN(r)) return r;
51181
52204
  return mPow(ensureRuntimeValue(left), ensureRuntimeValue(right));
51182
52205
  }
52206
+ if (this.rt.profilingEnabled && (typeof left !== "number" || typeof right !== "number")) {
52207
+ const opName = binopProfileName[expr.op] ?? expr.op;
52208
+ this.rt.profileEnter("builtin:interp:" + opName);
52209
+ const result = binop(expr.op, left, right);
52210
+ this.rt.profileLeave();
52211
+ return result;
52212
+ }
51183
52213
  return binop(expr.op, left, right);
51184
52214
  }
51185
52215
  function evalUnary(expr) {
@@ -51319,7 +52349,11 @@ function evalAnonFunc(expr) {
51319
52349
  capturedMethodName,
51320
52350
  () => {
51321
52351
  try {
51322
- return this.evalExprNargout(bodyExpr, narg);
52352
+ const result = this.evalExprNargout(bodyExpr, narg);
52353
+ if (narg > 1 && !(Array.isArray(result) && result.length >= narg)) {
52354
+ throw new RuntimeError("Too many output arguments.");
52355
+ }
52356
+ return result;
51323
52357
  } finally {
51324
52358
  this.env = savedEnv;
51325
52359
  }
@@ -51578,7 +52612,6 @@ function switchMatch2(switchVal, caseVal) {
51578
52612
  return switchMatch(switchVal, caseVal);
51579
52613
  }
51580
52614
  function isOutputExpr(expr) {
51581
- if (expr.type !== "FuncCall") return false;
51582
52615
  const outputFunctions = [
51583
52616
  "disp",
51584
52617
  "display",
@@ -51586,9 +52619,12 @@ function isOutputExpr(expr) {
51586
52619
  "warning",
51587
52620
  "assert",
51588
52621
  "tic",
52622
+ "toc",
51589
52623
  "help"
51590
52624
  ];
51591
- return outputFunctions.includes(expr.name);
52625
+ if (expr.type === "FuncCall") return outputFunctions.includes(expr.name);
52626
+ if (expr.type === "Ident") return outputFunctions.includes(expr.name);
52627
+ return false;
51592
52628
  }
51593
52629
 
51594
52630
  // src/numbl-core/interpreter/interpreterFunctions.ts
@@ -51797,6 +52833,17 @@ register("exist", (ctx, args) => {
51797
52833
  }
51798
52834
  return FALL_THROUGH;
51799
52835
  });
52836
+ register("which", (ctx, args) => {
52837
+ if (args.length < 1) return FALL_THROUGH;
52838
+ const nameArg = toString(ensureRuntimeValue(args[0]));
52839
+ if (ctx.env.has(nameArg)) return RTV.char("variable");
52840
+ const filePath = ctx.lookupWorkspaceFile(nameArg);
52841
+ if (filePath) return RTV.char(filePath);
52842
+ if (ctx.rt.builtins[nameArg] || getIBuiltin(nameArg)) {
52843
+ return RTV.char("built-in");
52844
+ }
52845
+ return RTV.char("");
52846
+ });
51800
52847
  register("isfolder", (ctx, args) => {
51801
52848
  if (args.length < 1) return FALL_THROUGH;
51802
52849
  const fio = ctx.rt.fileIO;
@@ -51899,6 +52946,9 @@ register("run", (ctx, args) => {
51899
52946
  } catch {
51900
52947
  throw new RuntimeError(`Cannot change directory to '${scriptDir}'`);
51901
52948
  }
52949
+ if (ctx.rt.onCwdChange) {
52950
+ ctx.rt.onCwdChange(sys.cwd());
52951
+ }
51902
52952
  }
51903
52953
  const cwdAfterCd = sys?.cwd() ?? "/";
51904
52954
  try {
@@ -51910,6 +52960,9 @@ register("run", (ctx, args) => {
51910
52960
  sys.chdir(oldCwd);
51911
52961
  } catch {
51912
52962
  }
52963
+ if (ctx.rt.onCwdChange) {
52964
+ ctx.rt.onCwdChange(sys.cwd());
52965
+ }
51913
52966
  }
51914
52967
  }
51915
52968
  return void 0;
@@ -51929,7 +52982,14 @@ function callFunction(name, args, nargout) {
51929
52982
  workspaceEnv: this.workspaceEnv,
51930
52983
  evalInLocalScope: (codeArg, fileName) => this.evalInLocalScope(codeArg, fileName),
51931
52984
  callFunction: (n, a, no) => this.callFunction(n, a, no),
51932
- rt: this.rt
52985
+ rt: this.rt,
52986
+ lookupWorkspaceFile: (n) => {
52987
+ const entry = this.ctx.registry.filesByFuncName.get(n);
52988
+ if (entry) return entry.fileName;
52989
+ const classInfo = this.ctx.getClassInfo(n);
52990
+ if (classInfo) return classInfo.fileName;
52991
+ return void 0;
52992
+ }
51933
52993
  };
51934
52994
  const result = specialHandler(ctx, args, nargout);
51935
52995
  if (result !== FALL_THROUGH) return result;
@@ -51963,13 +53023,18 @@ function interpretTarget(target, args, nargout) {
51963
53023
  const argTypes = margs.map(inferJitType);
51964
53024
  const resolution = ib.resolve(argTypes, nargout);
51965
53025
  if (resolution) {
53026
+ const isVoid = resolution.outputTypes.length === 0;
53027
+ if (isVoid && nargout > 0) {
53028
+ throw new RuntimeError("Too many output arguments.");
53029
+ }
51966
53030
  if (this.rt.profilingEnabled) {
51967
53031
  this.rt.profileEnter("builtin:interp:" + target.name);
51968
- const result = resolution.apply(margs, nargout);
53032
+ const result2 = resolution.apply(margs, nargout);
51969
53033
  this.rt.profileLeave();
51970
- return result;
53034
+ return isVoid ? void 0 : result2;
51971
53035
  }
51972
- return resolution.apply(margs, nargout);
53036
+ const result = resolution.apply(margs, nargout);
53037
+ return isVoid ? void 0 : result;
51973
53038
  }
51974
53039
  }
51975
53040
  const builtin = this.rt.builtins[target.name];
@@ -52061,7 +53126,19 @@ function interpretLocalFunction(target, args, nargout) {
52061
53126
  function interpretWorkspaceFunction(target, args, nargout) {
52062
53127
  const dotIdx = target.name.lastIndexOf(".");
52063
53128
  const primaryName = dotIdx >= 0 ? target.name.slice(dotIdx + 1) : target.name;
52064
- const fn = this.findFunctionInWorkspaceFile(target.name, primaryName);
53129
+ let fn = this.findFunctionInWorkspaceFile(target.name, primaryName);
53130
+ if (!fn) {
53131
+ const entry = this.ctx.registry.filesByFuncName.get(target.name);
53132
+ if (entry) {
53133
+ const ast = this.ctx.getCachedAST(entry.fileName);
53134
+ for (const stmt of ast.body) {
53135
+ if (stmt.type === "Function") {
53136
+ fn = funcDefFromStmt(stmt);
53137
+ break;
53138
+ }
53139
+ }
53140
+ }
53141
+ }
52065
53142
  if (!fn) {
52066
53143
  const entry = this.ctx.registry.filesByFuncName.get(target.name);
52067
53144
  if (entry) {
@@ -52205,6 +53282,11 @@ function interpretConstructor(classInfo, args, nargout) {
52205
53282
  return args[0];
52206
53283
  }
52207
53284
  function callUserFunction(fn, args, nargout, narginOverride) {
53285
+ const hasVarargoutDecl = fn.outputs.length > 0 && fn.outputs[fn.outputs.length - 1] === "varargout";
53286
+ const declaredRegularOutputs = hasVarargoutDecl ? fn.outputs.length - 1 : fn.outputs.length;
53287
+ if (!hasVarargoutDecl && nargout > declaredRegularOutputs) {
53288
+ throw new RuntimeError("Too many output arguments.");
53289
+ }
52208
53290
  if (this.optimization >= 1 && narginOverride === void 0) {
52209
53291
  const jitResult = tryJitCall(this, fn, args, nargout);
52210
53292
  if (jitResult !== JIT_SKIP) return jitResult;
@@ -52254,10 +53336,11 @@ function callUserFunction(fn, args, nargout, narginOverride) {
52254
53336
  }
52255
53337
  }
52256
53338
  }
52257
- const hasVarargout = fn.outputs.length > 0 && fn.outputs[fn.outputs.length - 1] === "varargout";
53339
+ const hasVarargout = hasVarargoutDecl;
52258
53340
  const regularOutputs = hasVarargout ? fn.outputs.slice(0, -1) : fn.outputs;
53341
+ const collectCount = nargout === 0 && regularOutputs.length > 0 ? 1 : Math.min(regularOutputs.length, nargout);
52259
53342
  const outputs = [];
52260
- for (let i = 0; i < Math.min(regularOutputs.length, nargout); i++) {
53343
+ for (let i = 0; i < collectCount; i++) {
52261
53344
  const val = this.env.get(regularOutputs[i]);
52262
53345
  if (val === void 0 && nargout >= i + 1) {
52263
53346
  throw new RuntimeError(
@@ -53827,10 +54910,17 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
53827
54910
  if (options.log) {
53828
54911
  options.log("AST parsed, starting interpretation");
53829
54912
  }
54913
+ const isRepl = mainFileName === "repl";
53830
54914
  const localFunctions = [];
53831
54915
  const localClasses = [];
53832
54916
  for (const stmt of ast.body) {
53833
54917
  if (stmt.type === "Function") {
54918
+ if (isRepl) {
54919
+ throw new RuntimeError(
54920
+ "Function definitions are not supported in the REPL. Save the function to a .m file instead.",
54921
+ stmt.span
54922
+ );
54923
+ }
53834
54924
  localFunctions.push(stmt);
53835
54925
  } else if (stmt.type === "ClassDef") {
53836
54926
  localClasses.push(stmt);
@@ -53851,6 +54941,31 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
53851
54941
  }
53852
54942
  }
53853
54943
  }
54944
+ let implicitCwdPath = null;
54945
+ if (options.implicitCwdPath !== null && options.system && options.fileIO?.scanDirectory) {
54946
+ try {
54947
+ const cwd = options.implicitCwdPath ?? options.system.cwd();
54948
+ const absCwd = options.fileIO.resolvePath?.(cwd) ?? cwd;
54949
+ const explicitPaths = searchPaths ?? [];
54950
+ if (!explicitPaths.includes(absCwd)) {
54951
+ implicitCwdPath = absCwd;
54952
+ const prefix = absCwd.endsWith("/") ? absCwd : absCwd + "/";
54953
+ const alreadyHave = mWorkspaceFiles.some(
54954
+ (f) => f.name === absCwd || f.name.startsWith(prefix)
54955
+ );
54956
+ if (!alreadyHave) {
54957
+ const cwdFiles = options.fileIO.scanDirectory(absCwd);
54958
+ for (const f of cwdFiles) {
54959
+ if (f.name.endsWith(".m")) {
54960
+ mWorkspaceFiles.push(f);
54961
+ }
54962
+ }
54963
+ }
54964
+ }
54965
+ } catch {
54966
+ implicitCwdPath = null;
54967
+ }
54968
+ }
53854
54969
  const jsUserFunctions = loadJsUserFunctions(
53855
54970
  jsWorkspaceFiles,
53856
54971
  wasmWorkspaceFiles,
@@ -53868,6 +54983,9 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
53868
54983
  stdlibShimNames.add(shimName);
53869
54984
  }
53870
54985
  ctx.registry.searchPaths = [...searchPaths ?? [], SHIM_SEARCH_PATH];
54986
+ if (implicitCwdPath !== null) {
54987
+ ctx.registry.searchPaths.unshift(implicitCwdPath);
54988
+ }
53871
54989
  ctx.fileASTCache.set(mainFileName, ast);
53872
54990
  const skippedFiles = /* @__PURE__ */ new Set();
53873
54991
  for (const f of mWorkspaceFiles) {
@@ -53901,6 +55019,11 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
53901
55019
  ctx.registerWorkspaceFiles(mWorkspaceFiles);
53902
55020
  }
53903
55021
  const functionIndex = ctx.buildFunctionIndex(jsUserFunctionNames);
55022
+ const savedSpecialBuiltins = /* @__PURE__ */ new Map();
55023
+ for (const name of SPECIAL_BUILTIN_NAMES) {
55024
+ const existing = getIBuiltin(name);
55025
+ if (existing) savedSpecialBuiltins.set(name, existing);
55026
+ }
53904
55027
  const rt = new Runtime(options, options.initialVariableValues);
53905
55028
  const savedIBuiltins = /* @__PURE__ */ new Map();
53906
55029
  for (const ib of jsUserFunctions) {
@@ -53942,13 +55065,39 @@ ${jsCode}`
53942
55065
  interpreter.installRuntimeCallbacks();
53943
55066
  rt.searchPaths = ctx.registry.searchPaths;
53944
55067
  let pathsModified = false;
55068
+ const rebuildWorkspace = () => {
55069
+ const paths = ctx.registry.searchPaths;
55070
+ const priorityOf = (name) => {
55071
+ let bestIdx = paths.length;
55072
+ let bestLen = -1;
55073
+ for (let i = 0; i < paths.length; i++) {
55074
+ const p2 = paths[i];
55075
+ const withSep = p2.endsWith("/") ? p2 : p2 + "/";
55076
+ if (name === p2 || name.startsWith(withSep)) {
55077
+ if (p2.length > bestLen) {
55078
+ bestLen = p2.length;
55079
+ bestIdx = i;
55080
+ }
55081
+ }
55082
+ }
55083
+ return bestIdx;
55084
+ };
55085
+ mWorkspaceFiles.sort((a, b) => priorityOf(a.name) - priorityOf(b.name));
55086
+ ctx.clearWorkspaceRegistrations();
55087
+ ctx.registerWorkspaceFiles(mWorkspaceFiles);
55088
+ const newIndex = ctx.buildFunctionIndex(jsUserFunctionNames);
55089
+ interpreter.functionIndex = newIndex;
55090
+ interpreter.clearAllCaches();
55091
+ pathsModified = true;
55092
+ };
53945
55093
  rt.onPathChange = (action, dir, position) => {
53946
55094
  const fileIO = options.fileIO;
53947
55095
  const absDir = fileIO?.resolvePath?.(dir) ?? dir;
53948
55096
  if (action === "add") {
53949
55097
  if (ctx.registry.searchPaths.includes(absDir)) return;
53950
55098
  if (position === "begin") {
53951
- ctx.registry.searchPaths.unshift(absDir);
55099
+ const cwdIsFirst = implicitCwdPath !== null && ctx.registry.searchPaths[0] === implicitCwdPath;
55100
+ ctx.registry.searchPaths.splice(cwdIsFirst ? 1 : 0, 0, absDir);
53952
55101
  } else {
53953
55102
  const shimIdx = ctx.registry.searchPaths.indexOf(SHIM_SEARCH_PATH);
53954
55103
  if (shimIdx >= 0) {
@@ -53966,10 +55115,14 @@ ${jsCode}`
53966
55115
  try {
53967
55116
  ctx.fileASTCache.set(f.name, parseMFile(f.source, f.name));
53968
55117
  } catch (e) {
53969
- if (e instanceof SyntaxError && e.file === null) {
53970
- e.file = f.name;
55118
+ if (e instanceof SyntaxError) {
55119
+ console.warn(
55120
+ `Warning: skipping ${f.name} (syntax error at line ${e.line ?? "?"})`
55121
+ );
55122
+ } else {
55123
+ console.warn(`Warning: skipping ${f.name} (parse error)`);
53971
55124
  }
53972
- throw e;
55125
+ continue;
53973
55126
  }
53974
55127
  interpreter.fileSources.set(f.name, f.source);
53975
55128
  mWorkspaceFiles.push(f);
@@ -54009,26 +55162,76 @@ ${jsCode}`
54009
55162
  }
54010
55163
  }
54011
55164
  }
54012
- const paths = ctx.registry.searchPaths;
54013
- mWorkspaceFiles.sort((a, b) => {
54014
- const ai = paths.findIndex(
54015
- (p2) => a.name.startsWith(p2.endsWith("/") ? p2 : p2 + "/") || a.name === p2
54016
- );
54017
- const bi = paths.findIndex(
54018
- (p2) => b.name.startsWith(p2.endsWith("/") ? p2 : p2 + "/") || b.name === p2
55165
+ rebuildWorkspace();
55166
+ };
55167
+ rt.onCwdChange = (newCwd) => {
55168
+ const fileIO = options.fileIO;
55169
+ const absNewCwd = fileIO?.resolvePath?.(newCwd) ?? newCwd;
55170
+ if (implicitCwdPath === absNewCwd) return;
55171
+ if (implicitCwdPath !== null) {
55172
+ const oldPrefix = implicitCwdPath.endsWith("/") ? implicitCwdPath : implicitCwdPath + "/";
55173
+ const deeperPaths = ctx.registry.searchPaths.filter(
55174
+ (p2) => p2 !== implicitCwdPath && p2 !== SHIM_SEARCH_PATH && (p2 === implicitCwdPath || p2.startsWith(oldPrefix))
54019
55175
  );
54020
- const aPri = ai >= 0 ? ai : paths.length;
54021
- const bPri = bi >= 0 ? bi : paths.length;
54022
- return aPri - bPri;
54023
- });
54024
- ctx.clearWorkspaceRegistrations();
54025
- ctx.registerWorkspaceFiles(mWorkspaceFiles);
54026
- const newIndex = ctx.buildFunctionIndex(jsUserFunctionNames);
54027
- interpreter.functionIndex = newIndex;
54028
- interpreter.clearAllCaches();
54029
- pathsModified = true;
55176
+ const fileBelongsToDeeperPath = (fname) => {
55177
+ for (const p2 of deeperPaths) {
55178
+ const withSep = p2.endsWith("/") ? p2 : p2 + "/";
55179
+ if (fname === p2 || fname.startsWith(withSep)) return true;
55180
+ }
55181
+ return false;
55182
+ };
55183
+ for (let i = mWorkspaceFiles.length - 1; i >= 0; i--) {
55184
+ const fname = mWorkspaceFiles[i].name;
55185
+ if ((fname === implicitCwdPath || fname.startsWith(oldPrefix)) && !fileBelongsToDeeperPath(fname)) {
55186
+ ctx.fileASTCache.delete(fname);
55187
+ interpreter.fileSources.delete(fname);
55188
+ mWorkspaceFiles.splice(i, 1);
55189
+ }
55190
+ }
55191
+ const oldIdx = ctx.registry.searchPaths.indexOf(implicitCwdPath);
55192
+ if (oldIdx >= 0) ctx.registry.searchPaths.splice(oldIdx, 1);
55193
+ implicitCwdPath = null;
55194
+ }
55195
+ if (ctx.registry.searchPaths.includes(absNewCwd)) {
55196
+ rebuildWorkspace();
55197
+ return;
55198
+ }
55199
+ ctx.registry.searchPaths.unshift(absNewCwd);
55200
+ implicitCwdPath = absNewCwd;
55201
+ if (fileIO?.scanDirectory) {
55202
+ let newFiles = [];
55203
+ try {
55204
+ newFiles = fileIO.scanDirectory(absNewCwd);
55205
+ } catch {
55206
+ }
55207
+ for (const f of newFiles) {
55208
+ if (f.name.endsWith(".m") && !ctx.fileASTCache.has(f.name)) {
55209
+ try {
55210
+ ctx.fileASTCache.set(f.name, parseMFile(f.source, f.name));
55211
+ } catch (e) {
55212
+ if (e instanceof SyntaxError) {
55213
+ console.warn(
55214
+ `Warning: skipping ${f.name} (syntax error at line ${e.line ?? "?"})`
55215
+ );
55216
+ } else {
55217
+ console.warn(`Warning: skipping ${f.name} (parse error)`);
55218
+ }
55219
+ continue;
55220
+ }
55221
+ interpreter.fileSources.set(f.name, f.source);
55222
+ mWorkspaceFiles.push(f);
55223
+ }
55224
+ }
55225
+ }
55226
+ rebuildWorkspace();
54030
55227
  };
54031
55228
  rt.evalLocalCallback = (code, initialVars, onOutput, fileName) => {
55229
+ const nestedSearchPaths = ctx.registry.searchPaths.filter(
55230
+ (p2) => p2 !== SHIM_SEARCH_PATH && p2 !== implicitCwdPath
55231
+ );
55232
+ const nestedWorkspaceFiles = mWorkspaceFiles.filter(
55233
+ (f) => !stdlibShimNames.has(f.name)
55234
+ );
54032
55235
  const evalResult = executeCode(
54033
55236
  code,
54034
55237
  {
@@ -54036,11 +55239,18 @@ ${jsCode}`
54036
55239
  displayResults: false,
54037
55240
  initialVariableValues: initialVars,
54038
55241
  fileIO: options.fileIO,
54039
- onInput: options.onInput
55242
+ system: options.system,
55243
+ onInput: options.onInput,
55244
+ implicitCwdPath
54040
55245
  },
54041
- void 0,
54042
- fileName
55246
+ nestedWorkspaceFiles,
55247
+ fileName,
55248
+ nestedSearchPaths,
55249
+ nativeBridge2
54043
55250
  );
55251
+ if (evalResult.implicitCwdPath !== void 0) {
55252
+ implicitCwdPath = evalResult.implicitCwdPath;
55253
+ }
54044
55254
  return {
54045
55255
  returnValue: evalResult.returnValue,
54046
55256
  variableValues: evalResult.variableValues,
@@ -54056,7 +55266,7 @@ ${jsCode}`
54056
55266
  output: rt.outputLines,
54057
55267
  generatedJS: jitSections.length > 0 ? `// Interpreter mode \u2014 JIT compiled sections:
54058
55268
 
54059
- ${jitSections.join("\n\n")}` : "// interpreted mode \u2014 no JS generated",
55269
+ ${jitSections.join("\n\n")}` : "// No JS generated",
54060
55270
  plotInstructions: rt.plotInstructions,
54061
55271
  returnValue: interpreter.ans ?? RTV.num(0),
54062
55272
  variableValues: interpreter.getVariableValues(),
@@ -54072,17 +55282,18 @@ ${jitSections.join("\n\n")}` : "// interpreted mode \u2014 no JS generated",
54072
55282
  }
54073
55283
  if (pathsModified) {
54074
55284
  result.searchPaths = ctx.registry.searchPaths.filter(
54075
- (p2) => p2 !== SHIM_SEARCH_PATH
55285
+ (p2) => p2 !== SHIM_SEARCH_PATH && p2 !== implicitCwdPath
54076
55286
  );
54077
55287
  result.workspaceFiles = mWorkspaceFiles.filter(
54078
55288
  (f) => !stdlibShimNames.has(f.name)
54079
55289
  );
54080
55290
  }
55291
+ result.implicitCwdPath = implicitCwdPath;
54081
55292
  return result;
54082
55293
  } catch (e) {
54083
55294
  const generatedJS = jitSections.length > 0 ? `// Interpreter mode \u2014 JIT compiled sections:
54084
55295
 
54085
- ${jitSections.join("\n\n")}` : "// interpreted mode \u2014 no JS generated";
55296
+ ${jitSections.join("\n\n")}` : "// No JS generated";
54086
55297
  if (e instanceof RuntimeError) {
54087
55298
  if (e.line === null && rt.$file && rt.$line > 0) {
54088
55299
  e.file = rt.$file;
@@ -54113,6 +55324,9 @@ ${jitSections.join("\n\n")}` : "// interpreted mode \u2014 no JS generated";
54113
55324
  unregisterIBuiltin(ib.name);
54114
55325
  }
54115
55326
  }
55327
+ for (const [, ib] of savedSpecialBuiltins) {
55328
+ registerDynamicIBuiltin(ib);
55329
+ }
54116
55330
  }
54117
55331
  }
54118
55332
 
@@ -54130,9 +55344,11 @@ import {
54130
55344
  unlinkSync,
54131
55345
  readdirSync as readdirSync2,
54132
55346
  rmSync,
54133
- rmdirSync
55347
+ rmdirSync,
55348
+ renameSync,
55349
+ chmodSync
54134
55350
  } from "fs";
54135
- import { inflateRawSync } from "zlib";
55351
+ import { unzipSync } from "fflate";
54136
55352
  import { execFileSync } from "child_process";
54137
55353
  import { homedir, tmpdir } from "os";
54138
55354
  import { join as join3, resolve, dirname, basename } from "path";
@@ -54189,6 +55405,18 @@ function expandTilde(filepath) {
54189
55405
  }
54190
55406
  return filepath;
54191
55407
  }
55408
+ function copyDirRecursive(src, dst) {
55409
+ mkdirSync(dst, { recursive: true });
55410
+ for (const entry of readdirSync2(src, { withFileTypes: true })) {
55411
+ const s = join3(src, entry.name);
55412
+ const d = join3(dst, entry.name);
55413
+ if (entry.isDirectory()) {
55414
+ copyDirRecursive(s, d);
55415
+ } else {
55416
+ writeFileSync(d, readFileSync3(s));
55417
+ }
55418
+ }
55419
+ }
54192
55420
  function permissionToFlags(permission) {
54193
55421
  switch (permission) {
54194
55422
  case "r":
@@ -54208,6 +55436,21 @@ function permissionToFlags(permission) {
54208
55436
  }
54209
55437
  }
54210
55438
  var READ_CHUNK_SIZE = 8192;
55439
+ function buildFetchOptions(options) {
55440
+ const init = {};
55441
+ if (options?.requestMethod) {
55442
+ init.method = options.requestMethod.toUpperCase();
55443
+ }
55444
+ const headers = {};
55445
+ if (options?.username && options?.password) {
55446
+ headers["Authorization"] = "Basic " + Buffer.from(`${options.username}:${options.password}`).toString("base64");
55447
+ }
55448
+ if (options?.keyName && options?.keyValue) {
55449
+ headers[options.keyName] = options.keyValue;
55450
+ }
55451
+ if (Object.keys(headers).length > 0) init.headers = headers;
55452
+ return init;
55453
+ }
54211
55454
  var NodeFileIOAdapter = class {
54212
55455
  nextFid = 3;
54213
55456
  // 0=stdin, 1=stdout, 2=stderr reserved
@@ -54381,35 +55624,43 @@ var NodeFileIOAdapter = class {
54381
55624
  tempdir() {
54382
55625
  return tmpdir();
54383
55626
  }
54384
- websave(url, filename) {
55627
+ websave(url, filename, options) {
54385
55628
  const dest = expandTilde(filename);
55629
+ const timeoutMs = options?.timeout ? Math.round(options.timeout * 1e3) : 3e4;
55630
+ const fetchOpts = buildFetchOptions(options);
54386
55631
  const script = `
54387
- fetch(${JSON.stringify(url)})
54388
- .then(r => { if (!r.ok) throw new Error('HTTP ' + r.status); return r.arrayBuffer(); })
55632
+ const ac = new AbortController();
55633
+ const t = setTimeout(() => ac.abort(), ${timeoutMs});
55634
+ fetch(${JSON.stringify(url)}, { ...${JSON.stringify(fetchOpts)}, signal: ac.signal })
55635
+ .then(r => { clearTimeout(t); if (!r.ok) throw new Error('HTTP ' + r.status); return r.arrayBuffer(); })
54389
55636
  .then(buf => require('fs').writeFileSync(${JSON.stringify(dest)}, Buffer.from(buf)))
54390
55637
  .catch(e => { process.stderr.write(e.message + '\\n'); process.exit(1); });
54391
55638
  `;
54392
55639
  try {
54393
55640
  execFileSync(process.execPath, ["-e", script], {
54394
55641
  stdio: ["ignore", "ignore", "pipe"],
54395
- timeout: 3e4
55642
+ timeout: timeoutMs + 5e3
54396
55643
  });
54397
55644
  } catch (e) {
54398
55645
  const msg = e instanceof Error && "stderr" in e ? e.stderr.toString().trim() : String(e);
54399
55646
  throw new Error(`websave: failed to download ${url}: ${msg}`);
54400
55647
  }
54401
55648
  }
54402
- webread(url) {
55649
+ webread(url, options) {
55650
+ const timeoutMs = options?.timeout ? Math.round(options.timeout * 1e3) : 3e4;
55651
+ const fetchOpts = buildFetchOptions(options);
54403
55652
  const script = `
54404
- fetch(${JSON.stringify(url)})
54405
- .then(r => { if (!r.ok) throw new Error('HTTP ' + r.status); return r.text(); })
55653
+ const ac = new AbortController();
55654
+ const t = setTimeout(() => ac.abort(), ${timeoutMs});
55655
+ fetch(${JSON.stringify(url)}, { ...${JSON.stringify(fetchOpts)}, signal: ac.signal })
55656
+ .then(r => { clearTimeout(t); if (!r.ok) throw new Error('HTTP ' + r.status); return r.text(); })
54406
55657
  .then(t => process.stdout.write(t))
54407
55658
  .catch(e => { process.stderr.write(e.message + '\\n'); process.exit(1); });
54408
55659
  `;
54409
55660
  try {
54410
55661
  const result = execFileSync(process.execPath, ["-e", script], {
54411
55662
  stdio: ["ignore", "pipe", "pipe"],
54412
- timeout: 3e4,
55663
+ timeout: timeoutMs + 5e3,
54413
55664
  maxBuffer: 50 * 1024 * 1024
54414
55665
  });
54415
55666
  return result.toString();
@@ -54431,6 +55682,59 @@ var NodeFileIOAdapter = class {
54431
55682
  return false;
54432
55683
  }
54433
55684
  }
55685
+ movefile(source, destination, force) {
55686
+ try {
55687
+ const src = expandTilde(source);
55688
+ const srcStat = statSync2(src);
55689
+ let dst = expandTilde(destination);
55690
+ let dstType = null;
55691
+ try {
55692
+ const s = statSync2(dst);
55693
+ dstType = s.isDirectory() ? "dir" : "file";
55694
+ } catch {
55695
+ dstType = null;
55696
+ }
55697
+ if (dstType === "dir") {
55698
+ dst = join3(dst, basename(src));
55699
+ try {
55700
+ dstType = statSync2(dst).isDirectory() ? "dir" : "file";
55701
+ } catch {
55702
+ dstType = null;
55703
+ }
55704
+ }
55705
+ if (dstType === "file" && force) {
55706
+ try {
55707
+ chmodSync(dst, 438);
55708
+ } catch {
55709
+ }
55710
+ }
55711
+ if (srcStat.isDirectory() && dstType === "file") {
55712
+ return false;
55713
+ }
55714
+ const parent = dirname(dst);
55715
+ if (parent && parent !== "." && parent !== "/") {
55716
+ try {
55717
+ mkdirSync(parent, { recursive: true });
55718
+ } catch {
55719
+ }
55720
+ }
55721
+ try {
55722
+ renameSync(src, dst);
55723
+ return true;
55724
+ } catch {
55725
+ if (srcStat.isDirectory()) {
55726
+ copyDirRecursive(src, dst);
55727
+ rmSync(src, { recursive: true });
55728
+ } else {
55729
+ writeFileSync(dst, readFileSync3(src));
55730
+ unlinkSync(src);
55731
+ }
55732
+ return true;
55733
+ }
55734
+ } catch {
55735
+ return false;
55736
+ }
55737
+ }
54434
55738
  deleteFile(pattern) {
54435
55739
  const p2 = expandTilde(pattern);
54436
55740
  if (p2.includes("*") || p2.includes("?")) {
@@ -54466,56 +55770,18 @@ var NodeFileIOAdapter = class {
54466
55770
  const dest = resolve(expandTilde(outputfolder));
54467
55771
  mkdirSync(dest, { recursive: true });
54468
55772
  const buf = readFileSync3(src);
54469
- let eocdOffset = -1;
54470
- for (let i = buf.length - 22; i >= 0; i--) {
54471
- if (buf[i] === 80 && buf[i + 1] === 75 && buf[i + 2] === 5 && buf[i + 3] === 6) {
54472
- eocdOffset = i;
54473
- break;
54474
- }
54475
- }
54476
- if (eocdOffset === -1) throw new Error("unzip: invalid ZIP file");
54477
- const cdOffset = buf.readUInt32LE(eocdOffset + 16);
54478
- const cdEntries = buf.readUInt16LE(eocdOffset + 10);
55773
+ const files = unzipSync(
55774
+ new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)
55775
+ );
54479
55776
  const extracted = [];
54480
- let pos = cdOffset;
54481
- for (let i = 0; i < cdEntries; i++) {
54482
- if (buf.readUInt32LE(pos) !== 33639248)
54483
- throw new Error("unzip: corrupt central directory");
54484
- const method = buf.readUInt16LE(pos + 10);
54485
- const nameLen = buf.readUInt16LE(pos + 28);
54486
- const extraLen = buf.readUInt16LE(pos + 30);
54487
- const commentLen = buf.readUInt16LE(pos + 32);
54488
- const localHeaderOffset = buf.readUInt32LE(pos + 42);
54489
- const entryName = buf.toString("utf-8", pos + 46, pos + 46 + nameLen);
54490
- pos += 46 + nameLen + extraLen + commentLen;
55777
+ for (const [entryName, data] of Object.entries(files)) {
54491
55778
  if (entryName.endsWith("/")) {
54492
55779
  mkdirSync(join3(dest, entryName), { recursive: true });
54493
55780
  continue;
54494
55781
  }
54495
- const localPos = localHeaderOffset;
54496
- if (buf.readUInt32LE(localPos) !== 67324752)
54497
- throw new Error("unzip: corrupt local header");
54498
- const localNameLen = buf.readUInt16LE(localPos + 26);
54499
- const localExtraLen = buf.readUInt16LE(localPos + 28);
54500
- const compressedSize = buf.readUInt32LE(localPos + 18);
54501
- const dataStart = localPos + 30 + localNameLen + localExtraLen;
54502
- const compressedData = buf.subarray(
54503
- dataStart,
54504
- dataStart + compressedSize
54505
- );
54506
- let fileData;
54507
- if (method === 0) {
54508
- fileData = Buffer.from(compressedData);
54509
- } else if (method === 8) {
54510
- fileData = inflateRawSync(compressedData);
54511
- } else {
54512
- throw new Error(
54513
- `unzip: unsupported compression method ${method} for ${entryName}`
54514
- );
54515
- }
54516
55782
  const outPath = join3(dest, entryName);
54517
55783
  mkdirSync(dirname(outPath), { recursive: true });
54518
- writeFileSync(outPath, fileData);
55784
+ writeFileSync(outPath, data);
54519
55785
  extracted.push(outPath);
54520
55786
  }
54521
55787
  return extracted;
@@ -54796,6 +56062,7 @@ function saveHistoryEntry(entry, hist) {
54796
56062
  async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths, nativeBridge2, optimization) {
54797
56063
  let variableValues = {};
54798
56064
  let holdState = false;
56065
+ let implicitCwdPath;
54799
56066
  const workspaceFiles = [...initialWorkspaceFiles];
54800
56067
  const searchPaths = [...initialSearchPaths ?? []];
54801
56068
  const fileIO = new NodeFileIOAdapter();
@@ -54848,7 +56115,8 @@ async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths, nat
54848
56115
  initialHoldState: holdState,
54849
56116
  optimization,
54850
56117
  fileIO,
54851
- system
56118
+ system,
56119
+ implicitCwdPath
54852
56120
  },
54853
56121
  workspaceFiles,
54854
56122
  "repl",
@@ -54863,6 +56131,9 @@ async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths, nat
54863
56131
  workspaceFiles.length = 0;
54864
56132
  workspaceFiles.push(...result.workspaceFiles ?? []);
54865
56133
  }
56134
+ if (result.implicitCwdPath !== void 0) {
56135
+ implicitCwdPath = result.implicitCwdPath;
56136
+ }
54866
56137
  if (result.plotInstructions.length > 0 && onDrawnow) {
54867
56138
  onDrawnow(result.plotInstructions);
54868
56139
  }
@@ -54961,7 +56232,8 @@ async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths, nat
54961
56232
  initialHoldState: holdState,
54962
56233
  optimization,
54963
56234
  fileIO,
54964
- system
56235
+ system,
56236
+ implicitCwdPath
54965
56237
  },
54966
56238
  workspaceFiles,
54967
56239
  "repl",
@@ -54976,6 +56248,9 @@ async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths, nat
54976
56248
  workspaceFiles.length = 0;
54977
56249
  workspaceFiles.push(...result.workspaceFiles ?? []);
54978
56250
  }
56251
+ if (result.implicitCwdPath !== void 0) {
56252
+ implicitCwdPath = result.implicitCwdPath;
56253
+ }
54979
56254
  if (result.plotInstructions.length > 0 && onDrawnow) {
54980
56255
  onDrawnow(result.plotInstructions);
54981
56256
  }
@@ -55241,65 +56516,15 @@ async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths, nat
55241
56516
  }
55242
56517
 
55243
56518
  // src/vfs/unzipToFiles.ts
55244
- import { inflateSync } from "fflate";
55245
- var TEXT_DECODER = new TextDecoder("utf-8");
56519
+ import { unzipSync as unzipSync2 } from "fflate";
55246
56520
  function unzipToFiles(zipData) {
55247
- let eocdOffset = -1;
55248
- for (let i = zipData.length - 22; i >= 0; i--) {
55249
- if (zipData[i] === 80 && zipData[i + 1] === 75 && zipData[i + 2] === 5 && zipData[i + 3] === 6) {
55250
- eocdOffset = i;
55251
- break;
55252
- }
55253
- }
55254
- if (eocdOffset === -1) throw new Error("Invalid ZIP file");
55255
- const view = new DataView(
55256
- zipData.buffer,
55257
- zipData.byteOffset,
55258
- zipData.byteLength
55259
- );
55260
- const cdOffset = view.getUint32(eocdOffset + 16, true);
55261
- const cdEntries = view.getUint16(eocdOffset + 10, true);
55262
- const files = [];
55263
- let pos = cdOffset;
55264
- for (let i = 0; i < cdEntries; i++) {
55265
- if (view.getUint32(pos, true) !== 33639248) {
55266
- throw new Error("Corrupt ZIP central directory");
55267
- }
55268
- const method = view.getUint16(pos + 10, true);
55269
- const nameLen = view.getUint16(pos + 28, true);
55270
- const extraLen = view.getUint16(pos + 30, true);
55271
- const commentLen = view.getUint16(pos + 32, true);
55272
- const localHeaderOffset = view.getUint32(pos + 42, true);
55273
- const entryName = TEXT_DECODER.decode(
55274
- zipData.subarray(pos + 46, pos + 46 + nameLen)
55275
- );
55276
- pos += 46 + nameLen + extraLen + commentLen;
55277
- if (entryName.endsWith("/")) continue;
55278
- const localPos = localHeaderOffset;
55279
- if (view.getUint32(localPos, true) !== 67324752) {
55280
- throw new Error("Corrupt ZIP local header");
55281
- }
55282
- const localNameLen = view.getUint16(localPos + 26, true);
55283
- const localExtraLen = view.getUint16(localPos + 28, true);
55284
- const compressedSize = view.getUint32(localPos + 18, true);
55285
- const dataStart = localPos + 30 + localNameLen + localExtraLen;
55286
- const compressedData = zipData.subarray(
55287
- dataStart,
55288
- dataStart + compressedSize
55289
- );
55290
- let content;
55291
- if (method === 0) {
55292
- content = new Uint8Array(compressedData);
55293
- } else if (method === 8) {
55294
- content = inflateSync(compressedData);
55295
- } else {
55296
- throw new Error(
55297
- `Unsupported ZIP compression method ${method} for ${entryName}`
55298
- );
55299
- }
55300
- files.push({ path: entryName, content });
56521
+ const files = unzipSync2(zipData);
56522
+ const out = [];
56523
+ for (const [path, content] of Object.entries(files)) {
56524
+ if (path.endsWith("/")) continue;
56525
+ out.push({ path, content });
55301
56526
  }
55302
- return files;
56527
+ return out;
55303
56528
  }
55304
56529
 
55305
56530
  // src/cli.ts
@@ -55527,7 +56752,6 @@ Options (for run and eval):
55527
56752
  --path <dir> Add extra workspace directory
55528
56753
  --plot Enable plot server
55529
56754
  --plot-port <port> Set plot server port (implies --plot)
55530
- --add-script-path Add the script's directory to the workspace (run only)
55531
56755
  --opt <level> Optimization level (0=none, 1=JIT scalar functions; default: 1)
55532
56756
 
55533
56757
  Environment variables:
@@ -55541,7 +56765,6 @@ function parseOptions(args) {
55541
56765
  stream: false,
55542
56766
  plot: false,
55543
56767
  plotPort: void 0,
55544
- addScriptPath: false,
55545
56768
  extraPaths: [],
55546
56769
  positional: [],
55547
56770
  profileOutput: void 0,
@@ -55581,9 +56804,6 @@ function parseOptions(args) {
55581
56804
  case "--plot":
55582
56805
  opts.plot = true;
55583
56806
  break;
55584
- case "--add-script-path":
55585
- opts.addScriptPath = true;
55586
- break;
55587
56807
  case "--plot-port":
55588
56808
  i++;
55589
56809
  if (i >= args.length) {
@@ -55649,13 +56869,9 @@ async function cmdRun(args) {
55649
56869
  const filepath = resolve2(process.cwd(), opts.positional[0]);
55650
56870
  const code = readFileSync5(filepath, "utf-8");
55651
56871
  const mainFileName = filepath;
56872
+ process.chdir(dirname2(filepath));
55652
56873
  const searchPaths = [];
55653
- let workspaceFiles = [];
55654
- if (opts.addScriptPath) {
55655
- const scriptDir = dirname2(filepath);
55656
- searchPaths.push(scriptDir);
55657
- workspaceFiles = scanMFiles(scriptDir, filepath);
55658
- }
56874
+ const workspaceFiles = [];
55659
56875
  for (const p2 of opts.extraPaths) {
55660
56876
  searchPaths.push(p2);
55661
56877
  workspaceFiles.push(...scanMFiles(p2));