numbl 0.1.3 → 0.1.5
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 +1603 -415
- package/dist-lib/lib.js +1514 -393
- package/dist-lib/numbl-core/executeCode.d.ts +9 -0
- package/dist-lib/numbl-core/fileIOAdapter.d.ts +2 -0
- package/dist-lib/numbl-core/helpers/quadgk.d.ts +32 -0
- package/dist-lib/numbl-core/helpers/string.d.ts +6 -0
- package/dist-lib/numbl-core/interpreter/builtins/index.d.ts +1 -0
- package/dist-lib/numbl-core/interpreter/builtins/logical.d.ts +9 -0
- package/dist-lib/numbl-core/interpreter/interpreterSpecialBuiltins.d.ts +3 -0
- package/dist-lib/numbl-core/runtime/runtime.d.ts +9 -0
- package/dist-lib/numbl-core/version.d.ts +1 -1
- package/package.json +1 -1
package/dist-lib/lib.js
CHANGED
|
@@ -18789,6 +18789,258 @@ function coerceToTensor(v, name) {
|
|
|
18789
18789
|
throw new RuntimeError(`${name}: argument must be numeric`);
|
|
18790
18790
|
}
|
|
18791
18791
|
|
|
18792
|
+
// src/numbl-core/helpers/string.ts
|
|
18793
|
+
function numStr(n) {
|
|
18794
|
+
if (n === Infinity) return "Inf";
|
|
18795
|
+
if (n === -Infinity) return "-Inf";
|
|
18796
|
+
if (isNaN(n)) return "NaN";
|
|
18797
|
+
if (n === 0) return "0";
|
|
18798
|
+
const prec = 5;
|
|
18799
|
+
const exp = Math.floor(Math.log10(Math.abs(n)));
|
|
18800
|
+
let s;
|
|
18801
|
+
if (exp < -4 || exp >= prec) {
|
|
18802
|
+
s = n.toExponential(prec - 1);
|
|
18803
|
+
const ePos = s.indexOf("e");
|
|
18804
|
+
let mantissa = s.slice(0, ePos);
|
|
18805
|
+
const expPart0 = s.slice(ePos);
|
|
18806
|
+
if (mantissa.includes(".")) mantissa = mantissa.replace(/\.?0+$/, "");
|
|
18807
|
+
const expPart = expPart0.replace(/([eE][+-])(\d)$/, "$10$2");
|
|
18808
|
+
s = mantissa + expPart;
|
|
18809
|
+
} else {
|
|
18810
|
+
if (Number.isInteger(n)) return String(n);
|
|
18811
|
+
s = n.toPrecision(prec);
|
|
18812
|
+
if (s.includes(".")) s = s.replace(/\.?0+$/, "");
|
|
18813
|
+
}
|
|
18814
|
+
return s;
|
|
18815
|
+
}
|
|
18816
|
+
function num2strScalar(n) {
|
|
18817
|
+
if (n === Infinity) return "Inf";
|
|
18818
|
+
if (n === -Infinity) return "-Inf";
|
|
18819
|
+
if (isNaN(n)) return "NaN";
|
|
18820
|
+
if (n === 0) return "0";
|
|
18821
|
+
if (Number.isInteger(n)) return String(n);
|
|
18822
|
+
const prec = 5;
|
|
18823
|
+
const exp = Math.floor(Math.log10(Math.abs(n)));
|
|
18824
|
+
let s;
|
|
18825
|
+
if (exp < -4 || exp >= prec) {
|
|
18826
|
+
s = n.toExponential(prec - 1);
|
|
18827
|
+
const ePos = s.indexOf("e");
|
|
18828
|
+
let mantissa = s.slice(0, ePos);
|
|
18829
|
+
const expPart0 = s.slice(ePos);
|
|
18830
|
+
if (mantissa.includes(".")) mantissa = mantissa.replace(/\.?0+$/, "");
|
|
18831
|
+
const expPart = expPart0.replace(/([eE][+-])(\d)$/, "$10$2");
|
|
18832
|
+
s = mantissa + expPart;
|
|
18833
|
+
} else {
|
|
18834
|
+
s = n.toPrecision(prec);
|
|
18835
|
+
if (s.includes(".")) s = s.replace(/\.?0+$/, "");
|
|
18836
|
+
}
|
|
18837
|
+
return s;
|
|
18838
|
+
}
|
|
18839
|
+
function applyWidth(spec, str) {
|
|
18840
|
+
const m = spec.match(/^%([-+ #]*)0?(\d+)?/);
|
|
18841
|
+
if (!m) return str;
|
|
18842
|
+
const explicitFlags = m[1] || "";
|
|
18843
|
+
const leftAlign = explicitFlags.includes("-");
|
|
18844
|
+
const afterPercent = spec.slice(1);
|
|
18845
|
+
const flagAndWidth = afterPercent.match(/^([-+ #]*)(0?)(\d+)?/);
|
|
18846
|
+
const zeroFlag = flagAndWidth ? flagAndWidth[2] === "0" : false;
|
|
18847
|
+
const width = flagAndWidth && flagAndWidth[3] ? parseInt(flagAndWidth[3]) : 0;
|
|
18848
|
+
if (width <= str.length) return str;
|
|
18849
|
+
const zeroPad = !leftAlign && zeroFlag;
|
|
18850
|
+
const padLen = width - str.length;
|
|
18851
|
+
if (leftAlign) return str + " ".repeat(padLen);
|
|
18852
|
+
if (zeroPad) {
|
|
18853
|
+
if (str[0] === "-" || str[0] === "+") {
|
|
18854
|
+
return str[0] + "0".repeat(padLen) + str.slice(1);
|
|
18855
|
+
}
|
|
18856
|
+
return "0".repeat(padLen) + str;
|
|
18857
|
+
}
|
|
18858
|
+
return " ".repeat(padLen) + str;
|
|
18859
|
+
}
|
|
18860
|
+
function sprintfFormat(fmt, args) {
|
|
18861
|
+
const flatArgs = [];
|
|
18862
|
+
for (const arg of args) {
|
|
18863
|
+
if (isRuntimeTensor(arg)) {
|
|
18864
|
+
for (let k = 0; k < arg.data.length; k++) {
|
|
18865
|
+
flatArgs.push(arg.data[k]);
|
|
18866
|
+
}
|
|
18867
|
+
} else {
|
|
18868
|
+
flatArgs.push(arg);
|
|
18869
|
+
}
|
|
18870
|
+
}
|
|
18871
|
+
let result = "";
|
|
18872
|
+
let argIdx = 0;
|
|
18873
|
+
do {
|
|
18874
|
+
const startArgIdx = argIdx;
|
|
18875
|
+
let outOfArgs = false;
|
|
18876
|
+
let i = 0;
|
|
18877
|
+
while (i < fmt.length && !outOfArgs) {
|
|
18878
|
+
if (fmt[i] === "%" && i + 1 < fmt.length) {
|
|
18879
|
+
i++;
|
|
18880
|
+
let spec = "%";
|
|
18881
|
+
while (i < fmt.length && !"dfigeEsoxXuc%".includes(fmt[i])) {
|
|
18882
|
+
if (fmt[i] === "*") {
|
|
18883
|
+
if (argIdx >= flatArgs.length) {
|
|
18884
|
+
outOfArgs = true;
|
|
18885
|
+
break;
|
|
18886
|
+
}
|
|
18887
|
+
spec += String(Math.round(toNumber(flatArgs[argIdx++])));
|
|
18888
|
+
i++;
|
|
18889
|
+
} else {
|
|
18890
|
+
spec += fmt[i];
|
|
18891
|
+
i++;
|
|
18892
|
+
}
|
|
18893
|
+
}
|
|
18894
|
+
if (outOfArgs) break;
|
|
18895
|
+
if (i < fmt.length) {
|
|
18896
|
+
const ch = fmt[i];
|
|
18897
|
+
i++;
|
|
18898
|
+
if (ch === "%") {
|
|
18899
|
+
result += "%";
|
|
18900
|
+
} else if (argIdx >= flatArgs.length) {
|
|
18901
|
+
outOfArgs = true;
|
|
18902
|
+
} else if (ch === "d" || ch === "i" || ch === "u") {
|
|
18903
|
+
const raw = toNumber(flatArgs[argIdx++]);
|
|
18904
|
+
const isInt = Number.isInteger(raw);
|
|
18905
|
+
const canPrintAsInt = ch === "u" ? isInt && raw >= 0 : isInt;
|
|
18906
|
+
if (!canPrintAsInt) {
|
|
18907
|
+
let eStr = raw.toExponential(6);
|
|
18908
|
+
eStr = eStr.replace(/e([+-])(\d)$/, "e$10$2");
|
|
18909
|
+
result += applyWidth(spec, eStr);
|
|
18910
|
+
} else {
|
|
18911
|
+
const n = raw;
|
|
18912
|
+
const flags = spec.slice(1);
|
|
18913
|
+
const hasPlus = flags.includes("+");
|
|
18914
|
+
const leftAlign = flags.includes("-");
|
|
18915
|
+
const widthMatch = spec.match(/^%[^0-9]*(\d+)/);
|
|
18916
|
+
const width = widthMatch ? parseInt(widthMatch[1]) : 0;
|
|
18917
|
+
const zeroPad = !leftAlign && /^[-+ ]*0/.test(spec.slice(1));
|
|
18918
|
+
const s = String(Math.abs(n));
|
|
18919
|
+
const sign = n < 0 ? "-" : hasPlus ? "+" : "";
|
|
18920
|
+
if (width > 0) {
|
|
18921
|
+
const padChar = zeroPad ? "0" : " ";
|
|
18922
|
+
const padLen = Math.max(0, width - sign.length - s.length);
|
|
18923
|
+
const pad = padChar.repeat(padLen);
|
|
18924
|
+
result += leftAlign ? sign + s + " ".repeat(padLen) : zeroPad ? sign + pad + s : pad + sign + s;
|
|
18925
|
+
} else {
|
|
18926
|
+
result += sign + s;
|
|
18927
|
+
}
|
|
18928
|
+
}
|
|
18929
|
+
} else if (ch === "f") {
|
|
18930
|
+
const n = toNumber(flatArgs[argIdx++]);
|
|
18931
|
+
if (!isFinite(n) || isNaN(n)) {
|
|
18932
|
+
result += applyWidth(spec, numStr(n));
|
|
18933
|
+
} else {
|
|
18934
|
+
const fFlags = spec.slice(1);
|
|
18935
|
+
const fHasPlus = fFlags.includes("+");
|
|
18936
|
+
const precMatch = spec.match(/\.(\d+)/);
|
|
18937
|
+
const prec = precMatch ? parseInt(precMatch[1]) : 6;
|
|
18938
|
+
const formatted = n.toFixed(prec);
|
|
18939
|
+
const fSign = n < 0 ? "" : fHasPlus ? "+" : "";
|
|
18940
|
+
result += applyWidth(spec, fSign + formatted);
|
|
18941
|
+
}
|
|
18942
|
+
} else if (ch === "e" || ch === "E") {
|
|
18943
|
+
const n = toNumber(flatArgs[argIdx++]);
|
|
18944
|
+
if (!isFinite(n) || isNaN(n)) {
|
|
18945
|
+
result += applyWidth(spec, numStr(n));
|
|
18946
|
+
} else {
|
|
18947
|
+
const precMatch = spec.match(/\.(\d+)/);
|
|
18948
|
+
const prec = precMatch ? parseInt(precMatch[1]) : 6;
|
|
18949
|
+
let eStr = n.toExponential(prec);
|
|
18950
|
+
eStr = eStr.replace(/e([+-])(\d)$/, "e$10$2");
|
|
18951
|
+
if (ch === "E") eStr = eStr.toUpperCase();
|
|
18952
|
+
result += applyWidth(spec, eStr);
|
|
18953
|
+
}
|
|
18954
|
+
} else if (ch === "x" || ch === "X") {
|
|
18955
|
+
const n = Math.round(toNumber(flatArgs[argIdx++]));
|
|
18956
|
+
let s = Math.abs(n).toString(16);
|
|
18957
|
+
if (ch === "X") s = s.toUpperCase();
|
|
18958
|
+
result += applyWidth(spec, s);
|
|
18959
|
+
} else if (ch === "o") {
|
|
18960
|
+
const n = Math.round(toNumber(flatArgs[argIdx++]));
|
|
18961
|
+
result += applyWidth(spec, Math.abs(n).toString(8));
|
|
18962
|
+
} else if (ch === "g" || ch === "G") {
|
|
18963
|
+
const gVal = toNumber(flatArgs[argIdx++]);
|
|
18964
|
+
if (!isFinite(gVal) || isNaN(gVal)) {
|
|
18965
|
+
result += applyWidth(spec, numStr(gVal));
|
|
18966
|
+
} else {
|
|
18967
|
+
const precMatch = spec.match(/\.(\d+)/);
|
|
18968
|
+
const gPrec = precMatch ? parseInt(precMatch[1]) : 6;
|
|
18969
|
+
let gStr;
|
|
18970
|
+
if (gVal === 0) {
|
|
18971
|
+
gStr = "0";
|
|
18972
|
+
} else {
|
|
18973
|
+
const exp = Math.floor(Math.log10(Math.abs(gVal)));
|
|
18974
|
+
if (exp < -4 || exp >= gPrec) {
|
|
18975
|
+
gStr = gVal.toExponential(gPrec - 1);
|
|
18976
|
+
const ePos = gStr.indexOf("e");
|
|
18977
|
+
let mantissa = gStr.slice(0, ePos);
|
|
18978
|
+
let expPart = gStr.slice(ePos);
|
|
18979
|
+
if (mantissa.includes(".")) {
|
|
18980
|
+
mantissa = mantissa.replace(/\.?0+$/, "");
|
|
18981
|
+
}
|
|
18982
|
+
expPart = expPart.replace(/e([+-])(\d)$/, "e$10$2");
|
|
18983
|
+
gStr = mantissa + expPart;
|
|
18984
|
+
} else {
|
|
18985
|
+
gStr = gVal.toPrecision(gPrec);
|
|
18986
|
+
if (gStr.includes(".")) {
|
|
18987
|
+
gStr = gStr.replace(/\.?0+$/, "");
|
|
18988
|
+
}
|
|
18989
|
+
if (gStr.includes("e")) {
|
|
18990
|
+
gStr = String(parseFloat(gStr));
|
|
18991
|
+
}
|
|
18992
|
+
}
|
|
18993
|
+
}
|
|
18994
|
+
if (ch === "G") gStr = gStr.toUpperCase();
|
|
18995
|
+
result += applyWidth(spec, gStr);
|
|
18996
|
+
}
|
|
18997
|
+
} else if (ch === "s") {
|
|
18998
|
+
const sVal = toString(flatArgs[argIdx++]);
|
|
18999
|
+
const sFlags = spec.slice(1);
|
|
19000
|
+
const sLeftAlign = sFlags.includes("-");
|
|
19001
|
+
const sWidthMatch = spec.match(/^%[^0-9]*(\d+)/);
|
|
19002
|
+
const sWidth = sWidthMatch ? parseInt(sWidthMatch[1]) : 0;
|
|
19003
|
+
if (sWidth > sVal.length) {
|
|
19004
|
+
const sPad = " ".repeat(sWidth - sVal.length);
|
|
19005
|
+
result += sLeftAlign ? sVal + sPad : sPad + sVal;
|
|
19006
|
+
} else {
|
|
19007
|
+
result += sVal;
|
|
19008
|
+
}
|
|
19009
|
+
} else if (ch === "c") {
|
|
19010
|
+
result += String.fromCharCode(
|
|
19011
|
+
Math.round(toNumber(flatArgs[argIdx++]))
|
|
19012
|
+
);
|
|
19013
|
+
} else {
|
|
19014
|
+
result += spec + ch;
|
|
19015
|
+
argIdx++;
|
|
19016
|
+
}
|
|
19017
|
+
}
|
|
19018
|
+
} else if (fmt[i] === "\\" && i + 1 < fmt.length) {
|
|
19019
|
+
i++;
|
|
19020
|
+
switch (fmt[i]) {
|
|
19021
|
+
case "n":
|
|
19022
|
+
result += "\n";
|
|
19023
|
+
break;
|
|
19024
|
+
case "t":
|
|
19025
|
+
result += " ";
|
|
19026
|
+
break;
|
|
19027
|
+
case "\\":
|
|
19028
|
+
result += "\\";
|
|
19029
|
+
break;
|
|
19030
|
+
default:
|
|
19031
|
+
result += "\\" + fmt[i];
|
|
19032
|
+
}
|
|
19033
|
+
i++;
|
|
19034
|
+
} else {
|
|
19035
|
+
result += fmt[i];
|
|
19036
|
+
i++;
|
|
19037
|
+
}
|
|
19038
|
+
}
|
|
19039
|
+
if (argIdx === startArgIdx) break;
|
|
19040
|
+
} while (argIdx < flatArgs.length);
|
|
19041
|
+
return result;
|
|
19042
|
+
}
|
|
19043
|
+
|
|
18792
19044
|
// src/numbl-core/helpers/arithmetic.ts
|
|
18793
19045
|
function toComplex(v) {
|
|
18794
19046
|
if (isRuntimeComplexNumber(v)) return { re: v.re, im: v.im };
|
|
@@ -19016,7 +19268,26 @@ function tensorElemwiseComplex(at, bt, opCode, jsOp) {
|
|
|
19016
19268
|
const isReal = resultIm.every((x) => x === 0);
|
|
19017
19269
|
return RTV.tensor(resultRe, at.shape, isReal ? void 0 : resultIm);
|
|
19018
19270
|
}
|
|
19271
|
+
function coerceToConcatString(v) {
|
|
19272
|
+
if (isRuntimeString(v)) return v;
|
|
19273
|
+
if (isRuntimeChar(v)) return v.value;
|
|
19274
|
+
if (isRuntimeLogical(v)) return v ? "true" : "false";
|
|
19275
|
+
if (isRuntimeNumber(v)) return num2strScalar(v);
|
|
19276
|
+
if (isRuntimeTensor(v) && v.data.length === 1 && !v.imag) {
|
|
19277
|
+
const x = v.data[0];
|
|
19278
|
+
if (v._isLogical === true) return x ? "true" : "false";
|
|
19279
|
+
return num2strScalar(x);
|
|
19280
|
+
}
|
|
19281
|
+
return null;
|
|
19282
|
+
}
|
|
19019
19283
|
function mAdd(a, b) {
|
|
19284
|
+
if (isRuntimeString(a) || isRuntimeString(b)) {
|
|
19285
|
+
const aStr = coerceToConcatString(a);
|
|
19286
|
+
const bStr = coerceToConcatString(b);
|
|
19287
|
+
if (aStr !== null && bStr !== null) {
|
|
19288
|
+
return RTV.string(aStr + bStr);
|
|
19289
|
+
}
|
|
19290
|
+
}
|
|
19020
19291
|
const m = matchSameShapeTensors(a, b);
|
|
19021
19292
|
if (m) {
|
|
19022
19293
|
const [at, bt] = m;
|
|
@@ -19911,6 +20182,7 @@ function extractTensorElement(base, i) {
|
|
|
19911
20182
|
const im2 = base.imag[i];
|
|
19912
20183
|
return im2 === 0 ? RTV.num(base.data[i]) : RTV.complex(base.data[i], im2);
|
|
19913
20184
|
}
|
|
20185
|
+
if (base._isLogical === true) return base.data[i] !== 0;
|
|
19914
20186
|
return RTV.num(base.data[i]);
|
|
19915
20187
|
}
|
|
19916
20188
|
function resolveIndex(idx, dimSize, boundsLimit = dimSize) {
|
|
@@ -19964,17 +20236,35 @@ function growTensor2D(base, newRows, newCols) {
|
|
|
19964
20236
|
}
|
|
19965
20237
|
function assignSlice(base, rowIndices, colIndices, rhs, curRows) {
|
|
19966
20238
|
if (isRuntimeTensor(rhs)) {
|
|
20239
|
+
const nR = rowIndices.length;
|
|
20240
|
+
const nC = colIndices.length;
|
|
19967
20241
|
const [rhsRows, rhsCols] = tensorSize2D(rhs);
|
|
19968
|
-
|
|
20242
|
+
const shapeMatches = rhsRows === nR && rhsCols === nC;
|
|
20243
|
+
const sliceIsVector = nR === 1 || nC === 1;
|
|
20244
|
+
const rhsIsVector = rhsRows === 1 || rhsCols === 1;
|
|
20245
|
+
const countMatches = rhs.data.length === nR * nC;
|
|
20246
|
+
if (!shapeMatches && !(sliceIsVector && rhsIsVector && countMatches)) {
|
|
19969
20247
|
throw new RuntimeError("Subscripted assignment dimension mismatch");
|
|
19970
20248
|
}
|
|
19971
20249
|
if (rhs.imag || base.imag) ensureImag(base);
|
|
19972
|
-
|
|
19973
|
-
for (let
|
|
19974
|
-
|
|
19975
|
-
|
|
19976
|
-
|
|
19977
|
-
|
|
20250
|
+
if (shapeMatches) {
|
|
20251
|
+
for (let ri = 0; ri < nR; ri++) {
|
|
20252
|
+
for (let ci = 0; ci < nC; ci++) {
|
|
20253
|
+
const dstLi = colMajorIndex(rowIndices[ri], colIndices[ci], curRows);
|
|
20254
|
+
const srcLi = colMajorIndex(ri, ci, rhsRows);
|
|
20255
|
+
base.data[dstLi] = rhs.data[srcLi];
|
|
20256
|
+
if (base.imag) base.imag[dstLi] = rhs.imag ? rhs.imag[srcLi] : 0;
|
|
20257
|
+
}
|
|
20258
|
+
}
|
|
20259
|
+
} else {
|
|
20260
|
+
let k = 0;
|
|
20261
|
+
for (let ci = 0; ci < nC; ci++) {
|
|
20262
|
+
for (let ri = 0; ri < nR; ri++) {
|
|
20263
|
+
const dstLi = colMajorIndex(rowIndices[ri], colIndices[ci], curRows);
|
|
20264
|
+
base.data[dstLi] = rhs.data[k];
|
|
20265
|
+
if (base.imag) base.imag[dstLi] = rhs.imag ? rhs.imag[k] : 0;
|
|
20266
|
+
k++;
|
|
20267
|
+
}
|
|
19978
20268
|
}
|
|
19979
20269
|
}
|
|
19980
20270
|
} else {
|
|
@@ -20311,6 +20601,23 @@ function indexIntoScalar(base, indices) {
|
|
|
20311
20601
|
return RTV.tensor(out, [1, count]);
|
|
20312
20602
|
}
|
|
20313
20603
|
}
|
|
20604
|
+
if (indices.length === 1 && isRuntimeTensor(indices[0])) {
|
|
20605
|
+
const idx = indices[0];
|
|
20606
|
+
for (let i = 0; i < idx.data.length; i++) {
|
|
20607
|
+
const k = Math.round(idx.data[i]);
|
|
20608
|
+
if (k !== 1) throw new RuntimeError("Index exceeds array bounds");
|
|
20609
|
+
}
|
|
20610
|
+
const n = idx.data.length;
|
|
20611
|
+
const scalarRe = isRuntimeNumber(base) ? base : base.re;
|
|
20612
|
+
const data = new FloatXArray(n);
|
|
20613
|
+
data.fill(scalarRe);
|
|
20614
|
+
if (isRuntimeComplexNumber(base) && base.im !== 0) {
|
|
20615
|
+
const im2 = new FloatXArray(n);
|
|
20616
|
+
im2.fill(base.im);
|
|
20617
|
+
return RTV.tensor(data, [...idx.shape], im2);
|
|
20618
|
+
}
|
|
20619
|
+
return RTV.tensor(data, [...idx.shape]);
|
|
20620
|
+
}
|
|
20314
20621
|
for (const idx of indices) {
|
|
20315
20622
|
if (isColonIndex(idx)) continue;
|
|
20316
20623
|
const i = toNumber(idx);
|
|
@@ -20322,6 +20629,22 @@ function indexIntoTensor(base, indices) {
|
|
|
20322
20629
|
if (indices.length === 1) {
|
|
20323
20630
|
return indexIntoTensor1D(base, indices[0]);
|
|
20324
20631
|
}
|
|
20632
|
+
if (base.shape.length > indices.length) {
|
|
20633
|
+
const collapsedShape = [];
|
|
20634
|
+
for (let d = 0; d < indices.length - 1; d++) {
|
|
20635
|
+
collapsedShape.push(base.shape[d]);
|
|
20636
|
+
}
|
|
20637
|
+
let tail = 1;
|
|
20638
|
+
for (let d = indices.length - 1; d < base.shape.length; d++) {
|
|
20639
|
+
tail *= base.shape[d];
|
|
20640
|
+
}
|
|
20641
|
+
collapsedShape.push(tail);
|
|
20642
|
+
const view = { ...base, shape: collapsedShape };
|
|
20643
|
+
if (indices.length === 2) {
|
|
20644
|
+
return indexIntoTensor2D(view, indices[0], indices[1]);
|
|
20645
|
+
}
|
|
20646
|
+
return indexIntoTensorND(view, indices);
|
|
20647
|
+
}
|
|
20325
20648
|
if (indices.length === 2) {
|
|
20326
20649
|
return indexIntoTensor2D(base, indices[0], indices[1]);
|
|
20327
20650
|
}
|
|
@@ -20350,6 +20673,11 @@ function indexIntoTensor1D(base, idx) {
|
|
|
20350
20673
|
}
|
|
20351
20674
|
function indexIntoTensor2D(base, rowIdx, colIdx) {
|
|
20352
20675
|
const [rows, cols] = tensorSize2D(base);
|
|
20676
|
+
const baseLogical = base._isLogical === true;
|
|
20677
|
+
const markLogical = (t) => {
|
|
20678
|
+
if (baseLogical && isRuntimeTensor(t)) t._isLogical = true;
|
|
20679
|
+
return t;
|
|
20680
|
+
};
|
|
20353
20681
|
if (isRuntimeNumber(rowIdx) && isColonIndex(colIdx)) {
|
|
20354
20682
|
const r = Math.round(rowIdx) - 1;
|
|
20355
20683
|
if (r < 0 || r >= rows)
|
|
@@ -20360,7 +20688,7 @@ function indexIntoTensor2D(base, rowIdx, colIdx) {
|
|
|
20360
20688
|
resultData2[ci] = base.data[r + ci * rows];
|
|
20361
20689
|
if (resultImag2 && base.imag) resultImag2[ci] = base.imag[r + ci * rows];
|
|
20362
20690
|
}
|
|
20363
|
-
return RTV.tensor(resultData2, [1, cols], resultImag2);
|
|
20691
|
+
return markLogical(RTV.tensor(resultData2, [1, cols], resultImag2));
|
|
20364
20692
|
}
|
|
20365
20693
|
if (isColonIndex(rowIdx) && isRuntimeNumber(colIdx)) {
|
|
20366
20694
|
const c = Math.round(colIdx) - 1;
|
|
@@ -20372,7 +20700,7 @@ function indexIntoTensor2D(base, rowIdx, colIdx) {
|
|
|
20372
20700
|
const resultImag2 = base.imag ? new FloatXArray(rows) : void 0;
|
|
20373
20701
|
if (resultImag2 && base.imag)
|
|
20374
20702
|
for (let ri = 0; ri < rows; ri++) resultImag2[ri] = base.imag[offset + ri];
|
|
20375
|
-
return RTV.tensor(resultData2, [rows, 1], resultImag2);
|
|
20703
|
+
return markLogical(RTV.tensor(resultData2, [rows, 1], resultImag2));
|
|
20376
20704
|
}
|
|
20377
20705
|
const rowIdxArr = resolveIndex(rowIdx, rows);
|
|
20378
20706
|
const colIdxArr = resolveIndex(colIdx, cols);
|
|
@@ -20394,7 +20722,7 @@ function indexIntoTensor2D(base, rowIdx, colIdx) {
|
|
|
20394
20722
|
}
|
|
20395
20723
|
}
|
|
20396
20724
|
}
|
|
20397
|
-
return RTV.tensor(resultData, [numR, numC], resultImag);
|
|
20725
|
+
return markLogical(RTV.tensor(resultData, [numR, numC], resultImag));
|
|
20398
20726
|
}
|
|
20399
20727
|
function indexIntoTensorND(base, indices) {
|
|
20400
20728
|
const shape = base.shape;
|
|
@@ -20442,7 +20770,13 @@ function indexIntoTensorND(base, indices) {
|
|
|
20442
20770
|
subs[d] = 0;
|
|
20443
20771
|
}
|
|
20444
20772
|
}
|
|
20445
|
-
|
|
20773
|
+
const result = RTV.tensor(
|
|
20774
|
+
resultData,
|
|
20775
|
+
resultShape,
|
|
20776
|
+
resultImag
|
|
20777
|
+
);
|
|
20778
|
+
if (base._isLogical === true) result._isLogical = true;
|
|
20779
|
+
return result;
|
|
20446
20780
|
}
|
|
20447
20781
|
function indexIntoCell(base, indices) {
|
|
20448
20782
|
if (indices.length === 1) {
|
|
@@ -20607,6 +20941,7 @@ function indexIntoLogical(base, indices) {
|
|
|
20607
20941
|
return base;
|
|
20608
20942
|
}
|
|
20609
20943
|
function indexIntoTensorWithTensor(base, idx) {
|
|
20944
|
+
const baseLogical = base._isLogical === true;
|
|
20610
20945
|
if (idx._isLogical) {
|
|
20611
20946
|
const selected = [];
|
|
20612
20947
|
const selectedIm = [];
|
|
@@ -20620,12 +20955,19 @@ function indexIntoTensorWithTensor(base, idx) {
|
|
|
20620
20955
|
if (selected.length === 1) {
|
|
20621
20956
|
if (hasImag2 && selectedIm[0] !== 0)
|
|
20622
20957
|
return RTV.complex(selected[0], selectedIm[0]);
|
|
20958
|
+
if (baseLogical) return selected[0] !== 0;
|
|
20623
20959
|
return RTV.num(selected[0]);
|
|
20624
20960
|
}
|
|
20625
20961
|
const imOut2 = hasImag2 && selectedIm.some((x) => x !== 0) ? new FloatXArray(selectedIm) : void 0;
|
|
20626
20962
|
const isRow = base.shape.length === 2 && base.shape[0] === 1;
|
|
20627
20963
|
const outShape2 = isRow ? [1, selected.length] : [selected.length, 1];
|
|
20628
|
-
|
|
20964
|
+
const result2 = RTV.tensor(
|
|
20965
|
+
new FloatXArray(selected),
|
|
20966
|
+
outShape2,
|
|
20967
|
+
imOut2
|
|
20968
|
+
);
|
|
20969
|
+
if (baseLogical) result2._isLogical = true;
|
|
20970
|
+
return result2;
|
|
20629
20971
|
}
|
|
20630
20972
|
const resultData = [];
|
|
20631
20973
|
const hasImag = base.imag !== void 0;
|
|
@@ -20641,7 +20983,13 @@ function indexIntoTensorWithTensor(base, idx) {
|
|
|
20641
20983
|
const baseIsVector = base.shape.length <= 2 && (base.shape[0] === 1 || base.shape[1] === 1 || base.shape.length === 1);
|
|
20642
20984
|
const outShape = idxIs0x0 ? [0, 0] : baseIsVector ? base.shape[0] === 1 ? [1, resultData.length] : [resultData.length, 1] : idx.shape;
|
|
20643
20985
|
const imOut = hasImag && imIndices.some((x) => x !== 0) ? new FloatXArray(imIndices) : void 0;
|
|
20644
|
-
|
|
20986
|
+
const result = RTV.tensor(
|
|
20987
|
+
new FloatXArray(resultData),
|
|
20988
|
+
outShape,
|
|
20989
|
+
imOut
|
|
20990
|
+
);
|
|
20991
|
+
if (baseLogical) result._isLogical = true;
|
|
20992
|
+
return result;
|
|
20645
20993
|
}
|
|
20646
20994
|
function indexIntoRTValue(base, indices) {
|
|
20647
20995
|
if (isRuntimeNumber(base) || isRuntimeComplexNumber(base)) {
|
|
@@ -20991,10 +21339,18 @@ function storeIntoTensor2D(base, indices, rhs) {
|
|
|
20991
21339
|
return storeIntoTensorColonCol(base, indices[0], rhs, rows, cols);
|
|
20992
21340
|
}
|
|
20993
21341
|
if (rowIsTensor || colIsTensor) {
|
|
20994
|
-
const
|
|
20995
|
-
|
|
20996
|
-
|
|
20997
|
-
|
|
21342
|
+
const isEmpty = base.data.length === 0;
|
|
21343
|
+
let effectiveCols = cols;
|
|
21344
|
+
let effectiveRows = rows;
|
|
21345
|
+
if (isEmpty && isRuntimeTensor(rhs)) {
|
|
21346
|
+
const [rhsRowsG, rhsColsG] = tensorSize2D(rhs);
|
|
21347
|
+
if (rowIsColon && !colIsColon) effectiveRows = rhsRowsG;
|
|
21348
|
+
if (colIsColon && !rowIsColon) effectiveCols = rhsColsG;
|
|
21349
|
+
}
|
|
21350
|
+
const rowIndices = rowIsColon ? Array.from({ length: effectiveRows }, (_, i) => i) : resolveIndex(indices[0], rows, 0);
|
|
21351
|
+
const colIndices = colIsColon ? Array.from({ length: effectiveCols }, (_, i) => i) : resolveIndex(indices[1], cols, 0);
|
|
21352
|
+
const maxRow = rowIndices.length > 0 ? Math.max(...rowIndices) + 1 : effectiveRows;
|
|
21353
|
+
const maxCol = colIndices.length > 0 ? Math.max(...colIndices) + 1 : effectiveCols;
|
|
20998
21354
|
base = growTensor2D(base, maxRow, maxCol);
|
|
20999
21355
|
const [curRows] = tensorSize2D(base);
|
|
21000
21356
|
assignSlice(base, rowIndices, colIndices, rhs, curRows);
|
|
@@ -21422,6 +21778,9 @@ function horzcat(...values) {
|
|
|
21422
21778
|
if (values.some((v) => isRuntimeCell(v))) {
|
|
21423
21779
|
return cellCatAlongDim(values, 1);
|
|
21424
21780
|
}
|
|
21781
|
+
if (values.some((v) => isRuntimeStruct(v) || isRuntimeStructArray(v))) {
|
|
21782
|
+
return structCat(values);
|
|
21783
|
+
}
|
|
21425
21784
|
return catAlongDim(values, 1);
|
|
21426
21785
|
}
|
|
21427
21786
|
function vertcat(...values) {
|
|
@@ -21433,8 +21792,47 @@ function vertcat(...values) {
|
|
|
21433
21792
|
if (values.some((v) => isRuntimeCell(v))) {
|
|
21434
21793
|
return cellCatAlongDim(values, 0);
|
|
21435
21794
|
}
|
|
21795
|
+
if (values.some((v) => isRuntimeStruct(v) || isRuntimeStructArray(v))) {
|
|
21796
|
+
return structCat(values);
|
|
21797
|
+
}
|
|
21436
21798
|
return catAlongDim(values, 0);
|
|
21437
21799
|
}
|
|
21800
|
+
function structCat(values) {
|
|
21801
|
+
const elements = [];
|
|
21802
|
+
let fieldNames = null;
|
|
21803
|
+
for (const v of values) {
|
|
21804
|
+
if (isRuntimeStruct(v)) {
|
|
21805
|
+
const keys = Array.from(v.fields.keys());
|
|
21806
|
+
if (fieldNames === null) fieldNames = keys;
|
|
21807
|
+
else if (!arraysEqual(fieldNames, keys)) {
|
|
21808
|
+
throw new RuntimeError(
|
|
21809
|
+
"Cannot concatenate structs with different field names"
|
|
21810
|
+
);
|
|
21811
|
+
}
|
|
21812
|
+
elements.push(v);
|
|
21813
|
+
} else if (isRuntimeStructArray(v)) {
|
|
21814
|
+
if (fieldNames === null) fieldNames = [...v.fieldNames];
|
|
21815
|
+
else if (!arraysEqual(fieldNames, v.fieldNames)) {
|
|
21816
|
+
throw new RuntimeError(
|
|
21817
|
+
"Cannot concatenate struct arrays with different field names"
|
|
21818
|
+
);
|
|
21819
|
+
}
|
|
21820
|
+
for (const e of v.elements) elements.push(e);
|
|
21821
|
+
} else {
|
|
21822
|
+
if (isRuntimeTensor(v) && v.data.length === 0 && v.shape.every((d) => d === 0)) {
|
|
21823
|
+
continue;
|
|
21824
|
+
}
|
|
21825
|
+
throw new RuntimeError(`Cannot concatenate ${kstr(v)} into struct`);
|
|
21826
|
+
}
|
|
21827
|
+
}
|
|
21828
|
+
if (fieldNames === null) fieldNames = [];
|
|
21829
|
+
return RTV.structArray(fieldNames, elements);
|
|
21830
|
+
}
|
|
21831
|
+
function arraysEqual(a, b) {
|
|
21832
|
+
if (a.length !== b.length) return false;
|
|
21833
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
21834
|
+
return true;
|
|
21835
|
+
}
|
|
21438
21836
|
function toSparseForCat(v) {
|
|
21439
21837
|
if (isRuntimeSparseMatrix(v)) return v;
|
|
21440
21838
|
if (isRuntimeNumber(v)) {
|
|
@@ -22042,7 +22440,7 @@ var token_config_default = {
|
|
|
22042
22440
|
stripUnderscores: true,
|
|
22043
22441
|
integerToken: "Integer",
|
|
22044
22442
|
floatToken: "Float",
|
|
22045
|
-
exponentChars: ["e", "E"],
|
|
22443
|
+
exponentChars: ["e", "E", "d", "D"],
|
|
22046
22444
|
decimalPoint: ".",
|
|
22047
22445
|
dotOperatorPrefixes: ["*", "/", "\\", "^"]
|
|
22048
22446
|
},
|
|
@@ -22347,6 +22745,9 @@ function tokenizeDetailed(input) {
|
|
|
22347
22745
|
if (numCfg.stripUnderscores) {
|
|
22348
22746
|
lexeme = lexeme.replace(/_/g, "");
|
|
22349
22747
|
}
|
|
22748
|
+
if (isFloat) {
|
|
22749
|
+
lexeme = lexeme.replace(/[dD]/g, "e");
|
|
22750
|
+
}
|
|
22350
22751
|
const tok = isFloat ? Token[numCfg.floatToken] : Token[numCfg.integerToken];
|
|
22351
22752
|
lineStart = false;
|
|
22352
22753
|
out.push({ token: tok, lexeme, start, end: pos });
|
|
@@ -27507,224 +27908,88 @@ defineBuiltin({
|
|
|
27507
27908
|
}
|
|
27508
27909
|
});
|
|
27509
27910
|
|
|
27510
|
-
// src/numbl-core/
|
|
27511
|
-
|
|
27512
|
-
|
|
27513
|
-
|
|
27514
|
-
|
|
27515
|
-
|
|
27516
|
-
|
|
27517
|
-
|
|
27518
|
-
|
|
27519
|
-
if (
|
|
27520
|
-
|
|
27521
|
-
|
|
27522
|
-
|
|
27523
|
-
const expPart0 = s.slice(ePos);
|
|
27524
|
-
if (mantissa.includes(".")) mantissa = mantissa.replace(/\.?0+$/, "");
|
|
27525
|
-
const expPart = expPart0.replace(/([eE][+-])(\d)$/, "$10$2");
|
|
27526
|
-
s = mantissa + expPart;
|
|
27527
|
-
} else {
|
|
27528
|
-
if (Number.isInteger(n)) return String(n);
|
|
27529
|
-
s = n.toPrecision(prec);
|
|
27530
|
-
if (s.includes(".")) s = s.replace(/\.?0+$/, "");
|
|
27911
|
+
// src/numbl-core/interpreter/builtins/logical.ts
|
|
27912
|
+
var LOGICAL_KINDS = /* @__PURE__ */ new Set([
|
|
27913
|
+
"number",
|
|
27914
|
+
"boolean",
|
|
27915
|
+
"tensor",
|
|
27916
|
+
"sparse_matrix"
|
|
27917
|
+
]);
|
|
27918
|
+
function binaryLogicalMatch(argTypes) {
|
|
27919
|
+
if (argTypes.length !== 2) return null;
|
|
27920
|
+
if (!LOGICAL_KINDS.has(argTypes[0].kind)) return null;
|
|
27921
|
+
if (!LOGICAL_KINDS.has(argTypes[1].kind)) return null;
|
|
27922
|
+
if (argTypes[0].kind === "tensor" || argTypes[1].kind === "tensor") {
|
|
27923
|
+
return [{ kind: "tensor", isComplex: false, isLogical: true }];
|
|
27531
27924
|
}
|
|
27532
|
-
|
|
27533
|
-
}
|
|
27534
|
-
function applyWidth(spec, str) {
|
|
27535
|
-
const m = spec.match(/^%([-+ #]*)0?(\d+)?/);
|
|
27536
|
-
if (!m) return str;
|
|
27537
|
-
const explicitFlags = m[1] || "";
|
|
27538
|
-
const leftAlign = explicitFlags.includes("-");
|
|
27539
|
-
const afterPercent = spec.slice(1);
|
|
27540
|
-
const flagAndWidth = afterPercent.match(/^([-+ #]*)(0?)(\d+)?/);
|
|
27541
|
-
const zeroFlag = flagAndWidth ? flagAndWidth[2] === "0" : false;
|
|
27542
|
-
const width = flagAndWidth && flagAndWidth[3] ? parseInt(flagAndWidth[3]) : 0;
|
|
27543
|
-
if (width <= str.length) return str;
|
|
27544
|
-
const zeroPad = !leftAlign && zeroFlag;
|
|
27545
|
-
const padLen = width - str.length;
|
|
27546
|
-
if (leftAlign) return str + " ".repeat(padLen);
|
|
27547
|
-
if (zeroPad) {
|
|
27548
|
-
if (str[0] === "-" || str[0] === "+") {
|
|
27549
|
-
return str[0] + "0".repeat(padLen) + str.slice(1);
|
|
27550
|
-
}
|
|
27551
|
-
return "0".repeat(padLen) + str;
|
|
27925
|
+
if (argTypes[0].kind === "sparse_matrix" || argTypes[1].kind === "sparse_matrix") {
|
|
27926
|
+
return [{ kind: "tensor", isComplex: false, isLogical: true }];
|
|
27552
27927
|
}
|
|
27553
|
-
return
|
|
27928
|
+
return [{ kind: "boolean" }];
|
|
27554
27929
|
}
|
|
27555
|
-
function
|
|
27556
|
-
|
|
27557
|
-
|
|
27558
|
-
|
|
27559
|
-
|
|
27560
|
-
|
|
27561
|
-
|
|
27562
|
-
|
|
27563
|
-
flatArgs.push(arg);
|
|
27564
|
-
}
|
|
27930
|
+
function isTensorLike(v) {
|
|
27931
|
+
return isRuntimeTensor(v) || isRuntimeSparseMatrix(v);
|
|
27932
|
+
}
|
|
27933
|
+
function applyBinaryLogical(args, op, scalarFn) {
|
|
27934
|
+
const a = args[0];
|
|
27935
|
+
const b = args[1];
|
|
27936
|
+
if (isTensorLike(a) || isTensorLike(b)) {
|
|
27937
|
+
return elementWiseLogicalOp(a, b, op);
|
|
27565
27938
|
}
|
|
27566
|
-
|
|
27567
|
-
|
|
27568
|
-
|
|
27569
|
-
|
|
27570
|
-
|
|
27571
|
-
|
|
27572
|
-
|
|
27573
|
-
|
|
27574
|
-
|
|
27575
|
-
|
|
27576
|
-
|
|
27577
|
-
|
|
27578
|
-
|
|
27579
|
-
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
|
|
27584
|
-
|
|
27585
|
-
|
|
27586
|
-
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
|
|
27590
|
-
|
|
27591
|
-
|
|
27592
|
-
|
|
27593
|
-
|
|
27594
|
-
|
|
27595
|
-
|
|
27596
|
-
|
|
27597
|
-
|
|
27598
|
-
|
|
27599
|
-
|
|
27600
|
-
|
|
27601
|
-
|
|
27602
|
-
|
|
27603
|
-
|
|
27604
|
-
|
|
27605
|
-
|
|
27606
|
-
|
|
27607
|
-
|
|
27608
|
-
|
|
27609
|
-
|
|
27610
|
-
|
|
27611
|
-
|
|
27612
|
-
|
|
27613
|
-
}
|
|
27614
|
-
} else if (ch === "f") {
|
|
27615
|
-
const n = toNumber(flatArgs[argIdx++]);
|
|
27616
|
-
if (!isFinite(n) || isNaN(n)) {
|
|
27617
|
-
result += applyWidth(spec, numStr(n));
|
|
27618
|
-
} else {
|
|
27619
|
-
const fFlags = spec.slice(1);
|
|
27620
|
-
const fHasPlus = fFlags.includes("+");
|
|
27621
|
-
const precMatch = spec.match(/\.(\d+)/);
|
|
27622
|
-
const prec = precMatch ? parseInt(precMatch[1]) : 6;
|
|
27623
|
-
const formatted = n.toFixed(prec);
|
|
27624
|
-
const fSign = n < 0 ? "" : fHasPlus ? "+" : "";
|
|
27625
|
-
result += applyWidth(spec, fSign + formatted);
|
|
27626
|
-
}
|
|
27627
|
-
} else if (ch === "e" || ch === "E") {
|
|
27628
|
-
const n = toNumber(flatArgs[argIdx++]);
|
|
27629
|
-
if (!isFinite(n) || isNaN(n)) {
|
|
27630
|
-
result += applyWidth(spec, numStr(n));
|
|
27631
|
-
} else {
|
|
27632
|
-
const precMatch = spec.match(/\.(\d+)/);
|
|
27633
|
-
const prec = precMatch ? parseInt(precMatch[1]) : 6;
|
|
27634
|
-
let eStr = n.toExponential(prec);
|
|
27635
|
-
eStr = eStr.replace(/e([+-])(\d)$/, "e$10$2");
|
|
27636
|
-
if (ch === "E") eStr = eStr.toUpperCase();
|
|
27637
|
-
result += applyWidth(spec, eStr);
|
|
27638
|
-
}
|
|
27639
|
-
} else if (ch === "x" || ch === "X") {
|
|
27640
|
-
const n = Math.round(toNumber(flatArgs[argIdx++]));
|
|
27641
|
-
let s = Math.abs(n).toString(16);
|
|
27642
|
-
if (ch === "X") s = s.toUpperCase();
|
|
27643
|
-
result += applyWidth(spec, s);
|
|
27644
|
-
} else if (ch === "o") {
|
|
27645
|
-
const n = Math.round(toNumber(flatArgs[argIdx++]));
|
|
27646
|
-
result += applyWidth(spec, Math.abs(n).toString(8));
|
|
27647
|
-
} else if (ch === "g" || ch === "G") {
|
|
27648
|
-
const gVal = toNumber(flatArgs[argIdx++]);
|
|
27649
|
-
if (!isFinite(gVal) || isNaN(gVal)) {
|
|
27650
|
-
result += applyWidth(spec, numStr(gVal));
|
|
27651
|
-
} else {
|
|
27652
|
-
const precMatch = spec.match(/\.(\d+)/);
|
|
27653
|
-
const gPrec = precMatch ? parseInt(precMatch[1]) : 6;
|
|
27654
|
-
let gStr;
|
|
27655
|
-
if (gVal === 0) {
|
|
27656
|
-
gStr = "0";
|
|
27657
|
-
} else {
|
|
27658
|
-
const exp = Math.floor(Math.log10(Math.abs(gVal)));
|
|
27659
|
-
if (exp < -4 || exp >= gPrec) {
|
|
27660
|
-
gStr = gVal.toExponential(gPrec - 1);
|
|
27661
|
-
const ePos = gStr.indexOf("e");
|
|
27662
|
-
let mantissa = gStr.slice(0, ePos);
|
|
27663
|
-
let expPart = gStr.slice(ePos);
|
|
27664
|
-
if (mantissa.includes(".")) {
|
|
27665
|
-
mantissa = mantissa.replace(/\.?0+$/, "");
|
|
27666
|
-
}
|
|
27667
|
-
expPart = expPart.replace(/e([+-])(\d)$/, "e$10$2");
|
|
27668
|
-
gStr = mantissa + expPart;
|
|
27669
|
-
} else {
|
|
27670
|
-
gStr = gVal.toPrecision(gPrec);
|
|
27671
|
-
if (gStr.includes(".")) {
|
|
27672
|
-
gStr = gStr.replace(/\.?0+$/, "");
|
|
27673
|
-
}
|
|
27674
|
-
if (gStr.includes("e")) {
|
|
27675
|
-
gStr = String(parseFloat(gStr));
|
|
27676
|
-
}
|
|
27677
|
-
}
|
|
27678
|
-
}
|
|
27679
|
-
if (ch === "G") gStr = gStr.toUpperCase();
|
|
27680
|
-
result += applyWidth(spec, gStr);
|
|
27681
|
-
}
|
|
27682
|
-
} else if (ch === "s") {
|
|
27683
|
-
const sVal = toString(flatArgs[argIdx++]);
|
|
27684
|
-
const sFlags = spec.slice(1);
|
|
27685
|
-
const sLeftAlign = sFlags.includes("-");
|
|
27686
|
-
const sWidthMatch = spec.match(/^%[^0-9]*(\d+)/);
|
|
27687
|
-
const sWidth = sWidthMatch ? parseInt(sWidthMatch[1]) : 0;
|
|
27688
|
-
if (sWidth > sVal.length) {
|
|
27689
|
-
const sPad = " ".repeat(sWidth - sVal.length);
|
|
27690
|
-
result += sLeftAlign ? sVal + sPad : sPad + sVal;
|
|
27691
|
-
} else {
|
|
27692
|
-
result += sVal;
|
|
27693
|
-
}
|
|
27694
|
-
} else if (ch === "c") {
|
|
27695
|
-
result += String.fromCharCode(
|
|
27696
|
-
Math.round(toNumber(flatArgs[argIdx++]))
|
|
27697
|
-
);
|
|
27698
|
-
} else {
|
|
27699
|
-
result += spec + ch;
|
|
27700
|
-
argIdx++;
|
|
27701
|
-
}
|
|
27702
|
-
}
|
|
27703
|
-
} else if (fmt[i] === "\\" && i + 1 < fmt.length) {
|
|
27704
|
-
i++;
|
|
27705
|
-
switch (fmt[i]) {
|
|
27706
|
-
case "n":
|
|
27707
|
-
result += "\n";
|
|
27708
|
-
break;
|
|
27709
|
-
case "t":
|
|
27710
|
-
result += " ";
|
|
27711
|
-
break;
|
|
27712
|
-
case "\\":
|
|
27713
|
-
result += "\\";
|
|
27714
|
-
break;
|
|
27715
|
-
default:
|
|
27716
|
-
result += "\\" + fmt[i];
|
|
27939
|
+
return RTV.logical(scalarFn(toBool(a), toBool(b)));
|
|
27940
|
+
}
|
|
27941
|
+
var orCase = {
|
|
27942
|
+
match: binaryLogicalMatch,
|
|
27943
|
+
apply: (args) => applyBinaryLogical(
|
|
27944
|
+
args,
|
|
27945
|
+
(x, y) => x !== 0 || y !== 0 ? 1 : 0,
|
|
27946
|
+
(a, b) => a || b
|
|
27947
|
+
)
|
|
27948
|
+
};
|
|
27949
|
+
defineBuiltin({
|
|
27950
|
+
name: "or",
|
|
27951
|
+
help: {
|
|
27952
|
+
signatures: ["TF = or(A, B)"],
|
|
27953
|
+
description: "Logical OR. Functional form of A | B; returns a logical scalar or tensor."
|
|
27954
|
+
},
|
|
27955
|
+
cases: [orCase]
|
|
27956
|
+
});
|
|
27957
|
+
var andCase = {
|
|
27958
|
+
match: binaryLogicalMatch,
|
|
27959
|
+
apply: (args) => applyBinaryLogical(
|
|
27960
|
+
args,
|
|
27961
|
+
(x, y) => x !== 0 && y !== 0 ? 1 : 0,
|
|
27962
|
+
(a, b) => a && b
|
|
27963
|
+
)
|
|
27964
|
+
};
|
|
27965
|
+
defineBuiltin({
|
|
27966
|
+
name: "and",
|
|
27967
|
+
help: {
|
|
27968
|
+
signatures: ["TF = and(A, B)"],
|
|
27969
|
+
description: "Logical AND. Functional form of A & B; returns a logical scalar or tensor."
|
|
27970
|
+
},
|
|
27971
|
+
cases: [andCase]
|
|
27972
|
+
});
|
|
27973
|
+
defineBuiltin({
|
|
27974
|
+
name: "not",
|
|
27975
|
+
help: {
|
|
27976
|
+
signatures: ["TF = not(A)"],
|
|
27977
|
+
description: "Logical negation. Functional form of ~A; returns a logical scalar or tensor."
|
|
27978
|
+
},
|
|
27979
|
+
cases: [
|
|
27980
|
+
{
|
|
27981
|
+
match: (argTypes) => {
|
|
27982
|
+
if (argTypes.length !== 1) return null;
|
|
27983
|
+
if (!LOGICAL_KINDS.has(argTypes[0].kind)) return null;
|
|
27984
|
+
if (argTypes[0].kind === "tensor" || argTypes[0].kind === "sparse_matrix") {
|
|
27985
|
+
return [{ kind: "tensor", isComplex: false, isLogical: true }];
|
|
27717
27986
|
}
|
|
27718
|
-
|
|
27719
|
-
}
|
|
27720
|
-
|
|
27721
|
-
i++;
|
|
27722
|
-
}
|
|
27987
|
+
return [{ kind: "boolean" }];
|
|
27988
|
+
},
|
|
27989
|
+
apply: (args) => not(args[0])
|
|
27723
27990
|
}
|
|
27724
|
-
|
|
27725
|
-
|
|
27726
|
-
return result;
|
|
27727
|
-
}
|
|
27991
|
+
]
|
|
27992
|
+
});
|
|
27728
27993
|
|
|
27729
27994
|
// src/numbl-core/interpreter/builtins/utility.ts
|
|
27730
27995
|
function sparseToDense2(S) {
|
|
@@ -27834,7 +28099,7 @@ defineBuiltin({
|
|
|
27834
28099
|
{
|
|
27835
28100
|
match: (argTypes) => {
|
|
27836
28101
|
if (argTypes.length < 1) return null;
|
|
27837
|
-
return [
|
|
28102
|
+
return [];
|
|
27838
28103
|
},
|
|
27839
28104
|
apply: (args) => {
|
|
27840
28105
|
const v = args[0];
|
|
@@ -27855,7 +28120,7 @@ defineBuiltin({
|
|
|
27855
28120
|
const msg = args.length > 1 ? textValue(args[1]) ?? String(args[1]) : "Assertion failed";
|
|
27856
28121
|
throw new Error(msg);
|
|
27857
28122
|
}
|
|
27858
|
-
return 0;
|
|
28123
|
+
return void 0;
|
|
27859
28124
|
}
|
|
27860
28125
|
}
|
|
27861
28126
|
]
|
|
@@ -27866,7 +28131,7 @@ defineBuiltin({
|
|
|
27866
28131
|
{
|
|
27867
28132
|
match: (argTypes) => {
|
|
27868
28133
|
if (argTypes.length === 0) return null;
|
|
27869
|
-
return [
|
|
28134
|
+
return [];
|
|
27870
28135
|
},
|
|
27871
28136
|
apply: (args) => {
|
|
27872
28137
|
const first = textValue(args[0]) ?? String(args[0]);
|
|
@@ -28538,6 +28803,19 @@ defineBuiltin({
|
|
|
28538
28803
|
name: "NaN",
|
|
28539
28804
|
cases: arrayConstructorCases(nanFill, NaN)
|
|
28540
28805
|
});
|
|
28806
|
+
function infFill(shape) {
|
|
28807
|
+
const data = new FloatXArray(numel(shape));
|
|
28808
|
+
data.fill(Infinity);
|
|
28809
|
+
return makeTensor(data, void 0, shape);
|
|
28810
|
+
}
|
|
28811
|
+
defineBuiltin({
|
|
28812
|
+
name: "inf",
|
|
28813
|
+
cases: arrayConstructorCases(infFill, Infinity)
|
|
28814
|
+
});
|
|
28815
|
+
defineBuiltin({
|
|
28816
|
+
name: "Inf",
|
|
28817
|
+
cases: arrayConstructorCases(infFill, Infinity)
|
|
28818
|
+
});
|
|
28541
28819
|
defineBuiltin({
|
|
28542
28820
|
name: "eye",
|
|
28543
28821
|
cases: arrayConstructorCases(
|
|
@@ -29375,19 +29653,33 @@ function preserveTextType(t) {
|
|
|
29375
29653
|
if (t.kind === "string") return { kind: "string" };
|
|
29376
29654
|
return null;
|
|
29377
29655
|
}
|
|
29656
|
+
function applyTextFn(v, fn) {
|
|
29657
|
+
if (isRuntimeCell(v)) {
|
|
29658
|
+
const out = new Array(v.data.length);
|
|
29659
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
29660
|
+
out[i] = applyTextFn(v.data[i], fn);
|
|
29661
|
+
}
|
|
29662
|
+
return RTV.cell(out, [...v.shape]);
|
|
29663
|
+
}
|
|
29664
|
+
if (isRuntimeChar(v)) return RTV.char(fn(v.value));
|
|
29665
|
+
if (isRuntimeString(v)) return RTV.string(fn(toString(v)));
|
|
29666
|
+
return v;
|
|
29667
|
+
}
|
|
29378
29668
|
function textPreserveResolve(fn) {
|
|
29379
29669
|
return (argTypes) => {
|
|
29380
29670
|
if (argTypes.length !== 1) return null;
|
|
29381
|
-
const
|
|
29671
|
+
const t = argTypes[0];
|
|
29672
|
+
if (t.kind === "cell") {
|
|
29673
|
+
return {
|
|
29674
|
+
outputTypes: [{ kind: "cell" }],
|
|
29675
|
+
apply: (args) => applyTextFn(args[0], fn)
|
|
29676
|
+
};
|
|
29677
|
+
}
|
|
29678
|
+
const out = preserveTextType(t);
|
|
29382
29679
|
if (!out) return null;
|
|
29383
29680
|
return {
|
|
29384
29681
|
outputTypes: [out],
|
|
29385
|
-
apply: (args) =>
|
|
29386
|
-
const v = args[0];
|
|
29387
|
-
const s = toString(v);
|
|
29388
|
-
const result = fn(s);
|
|
29389
|
-
return isRuntimeChar(v) ? RTV.char(result) : RTV.string(result);
|
|
29390
|
-
}
|
|
29682
|
+
apply: (args) => applyTextFn(args[0], fn)
|
|
29391
29683
|
};
|
|
29392
29684
|
};
|
|
29393
29685
|
}
|
|
@@ -29765,6 +30057,150 @@ registerIBuiltin({
|
|
|
29765
30057
|
};
|
|
29766
30058
|
}
|
|
29767
30059
|
});
|
|
30060
|
+
var RE_ALPHA = /\p{L}/u;
|
|
30061
|
+
var RE_ALPHANUM = /[\p{L}\p{N}]/u;
|
|
30062
|
+
var RE_CNTRL = /\p{Cc}/u;
|
|
30063
|
+
var RE_GRAPHIC = /[\p{L}\p{N}\p{P}\p{S}\p{M}]/u;
|
|
30064
|
+
var RE_LOWER = /\p{Ll}/u;
|
|
30065
|
+
var RE_PUNCT = /\p{P}/u;
|
|
30066
|
+
var RE_UPPER = /\p{Lu}/u;
|
|
30067
|
+
var RE_WSPACE = /\s/u;
|
|
30068
|
+
function isstrpropPredicate(category) {
|
|
30069
|
+
switch (category) {
|
|
30070
|
+
case "alpha":
|
|
30071
|
+
return (cp) => RE_ALPHA.test(String.fromCodePoint(cp));
|
|
30072
|
+
case "alphanum":
|
|
30073
|
+
return (cp) => RE_ALPHANUM.test(String.fromCodePoint(cp));
|
|
30074
|
+
case "cntrl":
|
|
30075
|
+
return (cp) => RE_CNTRL.test(String.fromCodePoint(cp));
|
|
30076
|
+
case "digit":
|
|
30077
|
+
return (cp) => cp >= 48 && cp <= 57;
|
|
30078
|
+
case "graphic":
|
|
30079
|
+
return (cp) => RE_GRAPHIC.test(String.fromCodePoint(cp));
|
|
30080
|
+
case "lower":
|
|
30081
|
+
return (cp) => RE_LOWER.test(String.fromCodePoint(cp));
|
|
30082
|
+
case "print":
|
|
30083
|
+
return (cp) => cp === 32 || RE_GRAPHIC.test(String.fromCodePoint(cp));
|
|
30084
|
+
case "punct":
|
|
30085
|
+
return (cp) => RE_PUNCT.test(String.fromCodePoint(cp));
|
|
30086
|
+
case "wspace":
|
|
30087
|
+
return (cp) => RE_WSPACE.test(String.fromCodePoint(cp));
|
|
30088
|
+
case "upper":
|
|
30089
|
+
return (cp) => RE_UPPER.test(String.fromCodePoint(cp));
|
|
30090
|
+
case "xdigit":
|
|
30091
|
+
return (cp) => cp >= 48 && cp <= 57 || cp >= 65 && cp <= 70 || cp >= 97 && cp <= 102;
|
|
30092
|
+
default:
|
|
30093
|
+
return null;
|
|
30094
|
+
}
|
|
30095
|
+
}
|
|
30096
|
+
function stringCodePoints(s) {
|
|
30097
|
+
const out = [];
|
|
30098
|
+
for (const ch of s) out.push(ch.codePointAt(0));
|
|
30099
|
+
return out;
|
|
30100
|
+
}
|
|
30101
|
+
function logicalRowFromString(s, pred, shape) {
|
|
30102
|
+
const cps = stringCodePoints(s);
|
|
30103
|
+
const data = new FloatXArray(cps.length);
|
|
30104
|
+
for (let i = 0; i < cps.length; i++) data[i] = pred(cps[i]) ? 1 : 0;
|
|
30105
|
+
return {
|
|
30106
|
+
kind: "tensor",
|
|
30107
|
+
data,
|
|
30108
|
+
shape: shape ?? [1, cps.length],
|
|
30109
|
+
_isLogical: true,
|
|
30110
|
+
_rc: 1
|
|
30111
|
+
};
|
|
30112
|
+
}
|
|
30113
|
+
function logicalFromNumericTensor(data, shape, pred) {
|
|
30114
|
+
const out = new FloatXArray(data.length);
|
|
30115
|
+
for (let i = 0; i < data.length; i++) {
|
|
30116
|
+
out[i] = pred(Math.round(data[i])) ? 1 : 0;
|
|
30117
|
+
}
|
|
30118
|
+
return {
|
|
30119
|
+
kind: "tensor",
|
|
30120
|
+
data: out,
|
|
30121
|
+
shape: [...shape],
|
|
30122
|
+
_isLogical: true,
|
|
30123
|
+
_rc: 1
|
|
30124
|
+
};
|
|
30125
|
+
}
|
|
30126
|
+
function isstrpropApply(args) {
|
|
30127
|
+
const v = args[0];
|
|
30128
|
+
const category = toString(args[1]);
|
|
30129
|
+
const pred = isstrpropPredicate(category);
|
|
30130
|
+
if (!pred) {
|
|
30131
|
+
throw new RuntimeError(`isstrprop: unknown category '${category}'`);
|
|
30132
|
+
}
|
|
30133
|
+
let forceCell = false;
|
|
30134
|
+
if (args.length >= 3) {
|
|
30135
|
+
const flagName = toString(args[2]).toLowerCase();
|
|
30136
|
+
if (flagName !== "forcecelloutput") {
|
|
30137
|
+
throw new RuntimeError(`isstrprop: unknown name '${toString(args[2])}'`);
|
|
30138
|
+
}
|
|
30139
|
+
if (args.length < 4) {
|
|
30140
|
+
throw new RuntimeError("isstrprop: 'ForceCellOutput' requires a value");
|
|
30141
|
+
}
|
|
30142
|
+
forceCell = toNumber(args[3]) !== 0;
|
|
30143
|
+
}
|
|
30144
|
+
if (isRuntimeCell(v)) {
|
|
30145
|
+
const out = new Array(v.data.length);
|
|
30146
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
30147
|
+
const elem = v.data[i];
|
|
30148
|
+
const s = isText(elem) ? toString(elem) : "";
|
|
30149
|
+
out[i] = logicalRowFromString(s, pred);
|
|
30150
|
+
}
|
|
30151
|
+
return RTV.cell(out, [...v.shape]);
|
|
30152
|
+
}
|
|
30153
|
+
let result;
|
|
30154
|
+
if (isRuntimeString(v)) {
|
|
30155
|
+
result = logicalRowFromString(toString(v), pred);
|
|
30156
|
+
} else if (isRuntimeChar(v)) {
|
|
30157
|
+
const c = v;
|
|
30158
|
+
result = logicalRowFromString(
|
|
30159
|
+
c.value,
|
|
30160
|
+
pred,
|
|
30161
|
+
c.shape ? [...c.shape] : void 0
|
|
30162
|
+
);
|
|
30163
|
+
} else if (isRuntimeTensor(v)) {
|
|
30164
|
+
result = logicalFromNumericTensor(v.data, v.shape, pred);
|
|
30165
|
+
} else if (isRuntimeNumber(v) || isRuntimeLogical(v)) {
|
|
30166
|
+
const cp = Math.round(toNumber(v));
|
|
30167
|
+
const data = new FloatXArray(1);
|
|
30168
|
+
data[0] = pred(cp) ? 1 : 0;
|
|
30169
|
+
result = { kind: "tensor", data, shape: [1, 1], _isLogical: true, _rc: 1 };
|
|
30170
|
+
} else {
|
|
30171
|
+
throw new RuntimeError("isstrprop: unsupported input type");
|
|
30172
|
+
}
|
|
30173
|
+
if (forceCell) return RTV.cell([result], [1, 1]);
|
|
30174
|
+
return result;
|
|
30175
|
+
}
|
|
30176
|
+
registerIBuiltin({
|
|
30177
|
+
name: "isstrprop",
|
|
30178
|
+
help: {
|
|
30179
|
+
signatures: [
|
|
30180
|
+
"TF = isstrprop(str, category)",
|
|
30181
|
+
"TF = isstrprop(str, category, 'ForceCellOutput', tf)"
|
|
30182
|
+
],
|
|
30183
|
+
description: "Test which characters in str belong to a category (alpha, alphanum, cntrl, digit, graphic, lower, print, punct, upper, wspace, xdigit). Returns a logical array, or a cell of logical vectors when str is a cell array or ForceCellOutput is true. Numeric input is treated as Unicode code points."
|
|
30184
|
+
},
|
|
30185
|
+
resolve: (argTypes) => {
|
|
30186
|
+
if (argTypes.length < 2 || argTypes.length > 4) return null;
|
|
30187
|
+
if (!isTextType(argTypes[1])) return null;
|
|
30188
|
+
if (argTypes.length >= 3 && !isTextType(argTypes[2])) return null;
|
|
30189
|
+
if (argTypes.length === 4) {
|
|
30190
|
+
const k = argTypes[3].kind;
|
|
30191
|
+
if (k !== "number" && k !== "boolean") return null;
|
|
30192
|
+
}
|
|
30193
|
+
const t0 = argTypes[0];
|
|
30194
|
+
if (t0.kind !== "char" && t0.kind !== "string" && t0.kind !== "number" && t0.kind !== "boolean" && t0.kind !== "tensor" && t0.kind !== "cell") {
|
|
30195
|
+
return null;
|
|
30196
|
+
}
|
|
30197
|
+
const isCell = t0.kind === "cell";
|
|
30198
|
+
return {
|
|
30199
|
+
outputTypes: isCell ? [{ kind: "cell" }] : [{ kind: "tensor", isComplex: false, isLogical: true }],
|
|
30200
|
+
apply: (args) => isstrpropApply(args)
|
|
30201
|
+
};
|
|
30202
|
+
}
|
|
30203
|
+
});
|
|
29768
30204
|
registerIBuiltin({
|
|
29769
30205
|
name: "contains",
|
|
29770
30206
|
resolve: (argTypes) => {
|
|
@@ -33150,11 +33586,15 @@ defineBuiltin({
|
|
|
33150
33586
|
apply: (args) => {
|
|
33151
33587
|
if (args.length !== 2)
|
|
33152
33588
|
throw new RuntimeError("kron requires 2 arguments");
|
|
33153
|
-
const
|
|
33154
|
-
|
|
33155
|
-
|
|
33156
|
-
|
|
33589
|
+
const coerce = (v) => {
|
|
33590
|
+
if (isRuntimeNumber(v))
|
|
33591
|
+
return RTV.tensor(new FloatXArray([v]), [1, 1]);
|
|
33592
|
+
if (isRuntimeSparseMatrix(v)) return sparseToDense(v);
|
|
33593
|
+
if (isRuntimeTensor(v)) return v;
|
|
33157
33594
|
throw new RuntimeError("kron: arguments must be numeric");
|
|
33595
|
+
};
|
|
33596
|
+
const A = coerce(args[0]);
|
|
33597
|
+
const B = coerce(args[1]);
|
|
33158
33598
|
const [m, n] = tensorSize2D(A);
|
|
33159
33599
|
const [p2, q] = tensorSize2D(B);
|
|
33160
33600
|
const rows = m * p2, cols = n * q;
|
|
@@ -35472,6 +35912,65 @@ defineBuiltin({
|
|
|
35472
35912
|
}
|
|
35473
35913
|
]
|
|
35474
35914
|
});
|
|
35915
|
+
defineBuiltin({
|
|
35916
|
+
name: "bitget",
|
|
35917
|
+
cases: [
|
|
35918
|
+
{
|
|
35919
|
+
match: (argTypes) => {
|
|
35920
|
+
if (argTypes.length !== 2) return null;
|
|
35921
|
+
return [{ kind: "unknown" }];
|
|
35922
|
+
},
|
|
35923
|
+
// bitget(A, bit) returns bit number `bit` (1-based, 1 = LSB) of each
|
|
35924
|
+
// element of A. MATLAB supports vector `bit` with broadcasting; we
|
|
35925
|
+
// match the scalar-or-same-shape rules used by the other bitwise ops.
|
|
35926
|
+
apply: (args) => bitwiseOp(
|
|
35927
|
+
args[0],
|
|
35928
|
+
args[1],
|
|
35929
|
+
(a, bit) => {
|
|
35930
|
+
const b = Math.round(bit);
|
|
35931
|
+
if (b < 1) return 0;
|
|
35932
|
+
if (b <= 31) return a >>> b - 1 & 1;
|
|
35933
|
+
const bi = BigInt(a);
|
|
35934
|
+
return Number(bi >> BigInt(b - 1) & 1n);
|
|
35935
|
+
},
|
|
35936
|
+
"bitget"
|
|
35937
|
+
)
|
|
35938
|
+
}
|
|
35939
|
+
]
|
|
35940
|
+
});
|
|
35941
|
+
defineBuiltin({
|
|
35942
|
+
name: "bitset",
|
|
35943
|
+
cases: [
|
|
35944
|
+
{
|
|
35945
|
+
match: (argTypes) => {
|
|
35946
|
+
if (argTypes.length < 2 || argTypes.length > 3) return null;
|
|
35947
|
+
return [{ kind: "unknown" }];
|
|
35948
|
+
},
|
|
35949
|
+
// bitset(A, bit) → set bit to 1
|
|
35950
|
+
// bitset(A, bit, v) → set bit to v (0 or 1)
|
|
35951
|
+
apply: (args) => {
|
|
35952
|
+
const v = args.length >= 3 ? Math.round(toNumber(args[2])) : 1;
|
|
35953
|
+
return bitwiseOp(
|
|
35954
|
+
args[0],
|
|
35955
|
+
args[1],
|
|
35956
|
+
(a, bit) => {
|
|
35957
|
+
const b = Math.round(bit);
|
|
35958
|
+
if (b < 1) return a;
|
|
35959
|
+
if (b <= 31) {
|
|
35960
|
+
const mask2 = 1 << b - 1;
|
|
35961
|
+
return v ? a | mask2 : a & ~mask2;
|
|
35962
|
+
}
|
|
35963
|
+
const bi = BigInt(a);
|
|
35964
|
+
const mask = 1n << BigInt(b - 1);
|
|
35965
|
+
const out = v ? bi | mask : bi & ~mask;
|
|
35966
|
+
return Number(out);
|
|
35967
|
+
},
|
|
35968
|
+
"bitset"
|
|
35969
|
+
);
|
|
35970
|
+
}
|
|
35971
|
+
}
|
|
35972
|
+
]
|
|
35973
|
+
});
|
|
35475
35974
|
function coordTransform(name, nArgs, nOut, fn) {
|
|
35476
35975
|
defineBuiltin({
|
|
35477
35976
|
name,
|
|
@@ -36601,6 +37100,131 @@ defineBuiltin({
|
|
|
36601
37100
|
}
|
|
36602
37101
|
]
|
|
36603
37102
|
});
|
|
37103
|
+
var INT_RANGES = [
|
|
37104
|
+
{ name: "int8", min: -128, max: 127 },
|
|
37105
|
+
{ name: "int16", min: -32768, max: 32767 },
|
|
37106
|
+
{ name: "int32", min: -2147483648, max: 2147483647 },
|
|
37107
|
+
// int64/uint64 can't represent their full native range as doubles;
|
|
37108
|
+
// clamp at Number.MAX_SAFE_INTEGER to avoid silent precision loss.
|
|
37109
|
+
{
|
|
37110
|
+
name: "int64",
|
|
37111
|
+
min: -Number.MAX_SAFE_INTEGER,
|
|
37112
|
+
max: Number.MAX_SAFE_INTEGER
|
|
37113
|
+
},
|
|
37114
|
+
{ name: "uint8", min: 0, max: 255 },
|
|
37115
|
+
{ name: "uint16", min: 0, max: 65535 },
|
|
37116
|
+
{ name: "uint32", min: 0, max: 4294967295 },
|
|
37117
|
+
{ name: "uint64", min: 0, max: Number.MAX_SAFE_INTEGER }
|
|
37118
|
+
];
|
|
37119
|
+
function saturateRoundToward(x, min, max) {
|
|
37120
|
+
if (isNaN(x)) return 0;
|
|
37121
|
+
const r = x >= 0 ? Math.floor(x + 0.5) : -Math.floor(-x + 0.5);
|
|
37122
|
+
if (r < min) return min;
|
|
37123
|
+
if (r > max) return max;
|
|
37124
|
+
return r;
|
|
37125
|
+
}
|
|
37126
|
+
for (const { name, min, max } of INT_RANGES) {
|
|
37127
|
+
defineBuiltin({
|
|
37128
|
+
name,
|
|
37129
|
+
cases: [
|
|
37130
|
+
{
|
|
37131
|
+
match: (argTypes) => {
|
|
37132
|
+
if (argTypes.length !== 1) return null;
|
|
37133
|
+
const a = argTypes[0];
|
|
37134
|
+
if (a.kind === "number" || a.kind === "boolean" || a.kind === "char" || a.kind === "complex_or_number")
|
|
37135
|
+
return [{ kind: "number" }];
|
|
37136
|
+
if (a.kind === "tensor")
|
|
37137
|
+
return [
|
|
37138
|
+
{
|
|
37139
|
+
kind: "tensor",
|
|
37140
|
+
isComplex: false,
|
|
37141
|
+
shape: a.shape,
|
|
37142
|
+
ndim: a.ndim
|
|
37143
|
+
}
|
|
37144
|
+
];
|
|
37145
|
+
return null;
|
|
37146
|
+
},
|
|
37147
|
+
apply: (args) => {
|
|
37148
|
+
const v = args[0];
|
|
37149
|
+
if (isRuntimeNumber(v))
|
|
37150
|
+
return RTV.num(saturateRoundToward(v, min, max));
|
|
37151
|
+
if (isRuntimeLogical(v)) return RTV.num(v ? 1 : 0);
|
|
37152
|
+
if (isRuntimeComplexNumber(v))
|
|
37153
|
+
return RTV.num(saturateRoundToward(v.re, min, max));
|
|
37154
|
+
if (isRuntimeChar(v)) {
|
|
37155
|
+
if (v.value.length === 0)
|
|
37156
|
+
return RTV.tensor(new FloatXArray(0), [0, 0]);
|
|
37157
|
+
if (v.value.length === 1)
|
|
37158
|
+
return RTV.num(
|
|
37159
|
+
saturateRoundToward(v.value.charCodeAt(0), min, max)
|
|
37160
|
+
);
|
|
37161
|
+
const out = new FloatXArray(v.value.length);
|
|
37162
|
+
for (let i = 0; i < v.value.length; i++) {
|
|
37163
|
+
out[i] = saturateRoundToward(v.value.charCodeAt(i), min, max);
|
|
37164
|
+
}
|
|
37165
|
+
return RTV.row(Array.from(out));
|
|
37166
|
+
}
|
|
37167
|
+
if (isRuntimeTensor(v)) {
|
|
37168
|
+
const data = new FloatXArray(v.data.length);
|
|
37169
|
+
for (let i = 0; i < v.data.length; i++) {
|
|
37170
|
+
data[i] = saturateRoundToward(v.data[i], min, max);
|
|
37171
|
+
}
|
|
37172
|
+
return RTV.tensor(data, [...v.shape]);
|
|
37173
|
+
}
|
|
37174
|
+
return RTV.num(saturateRoundToward(toNumber(v), min, max));
|
|
37175
|
+
}
|
|
37176
|
+
}
|
|
37177
|
+
]
|
|
37178
|
+
});
|
|
37179
|
+
}
|
|
37180
|
+
defineBuiltin({
|
|
37181
|
+
name: "idivide",
|
|
37182
|
+
cases: [
|
|
37183
|
+
{
|
|
37184
|
+
match: (argTypes) => {
|
|
37185
|
+
if (argTypes.length < 2 || argTypes.length > 3) return null;
|
|
37186
|
+
return [{ kind: "unknown" }];
|
|
37187
|
+
},
|
|
37188
|
+
apply: (args) => {
|
|
37189
|
+
const divFix = (a2, b2) => {
|
|
37190
|
+
if (b2 === 0) {
|
|
37191
|
+
return 0;
|
|
37192
|
+
}
|
|
37193
|
+
const q = a2 / b2;
|
|
37194
|
+
return q >= 0 ? Math.floor(q) : -Math.floor(-q);
|
|
37195
|
+
};
|
|
37196
|
+
const a = args[0];
|
|
37197
|
+
const b = args[1];
|
|
37198
|
+
if (isRuntimeNumber(a) && isRuntimeNumber(b)) {
|
|
37199
|
+
return RTV.num(divFix(a, b));
|
|
37200
|
+
}
|
|
37201
|
+
if (isRuntimeTensor(a) && isRuntimeNumber(b)) {
|
|
37202
|
+
const bv = b;
|
|
37203
|
+
const data = new FloatXArray(a.data.length);
|
|
37204
|
+
for (let i = 0; i < a.data.length; i++)
|
|
37205
|
+
data[i] = divFix(a.data[i], bv);
|
|
37206
|
+
return RTV.tensor(data, [...a.shape]);
|
|
37207
|
+
}
|
|
37208
|
+
if (isRuntimeNumber(a) && isRuntimeTensor(b)) {
|
|
37209
|
+
const av = a;
|
|
37210
|
+
const data = new FloatXArray(b.data.length);
|
|
37211
|
+
for (let i = 0; i < b.data.length; i++)
|
|
37212
|
+
data[i] = divFix(av, b.data[i]);
|
|
37213
|
+
return RTV.tensor(data, [...b.shape]);
|
|
37214
|
+
}
|
|
37215
|
+
if (isRuntimeTensor(a) && isRuntimeTensor(b)) {
|
|
37216
|
+
if (a.data.length !== b.data.length)
|
|
37217
|
+
throw new RuntimeError("idivide: arrays must be the same size");
|
|
37218
|
+
const data = new FloatXArray(a.data.length);
|
|
37219
|
+
for (let i = 0; i < a.data.length; i++)
|
|
37220
|
+
data[i] = divFix(a.data[i], b.data[i]);
|
|
37221
|
+
return RTV.tensor(data, [...a.shape]);
|
|
37222
|
+
}
|
|
37223
|
+
throw new RuntimeError("idivide: arguments must be numeric");
|
|
37224
|
+
}
|
|
37225
|
+
}
|
|
37226
|
+
]
|
|
37227
|
+
});
|
|
36604
37228
|
defineBuiltin({
|
|
36605
37229
|
name: "logical",
|
|
36606
37230
|
cases: [
|
|
@@ -37983,6 +38607,24 @@ registerIBuiltin({
|
|
|
37983
38607
|
}
|
|
37984
38608
|
})
|
|
37985
38609
|
});
|
|
38610
|
+
function getMexExt() {
|
|
38611
|
+
if (typeof process === "undefined") return "";
|
|
38612
|
+
const platform = process.platform;
|
|
38613
|
+
const cpuArch = process.arch;
|
|
38614
|
+
if (platform === "win32") return "mexw64";
|
|
38615
|
+
if (platform === "darwin")
|
|
38616
|
+
return cpuArch === "arm64" ? "mexmaca64" : "mexmaci64";
|
|
38617
|
+
return "mexa64";
|
|
38618
|
+
}
|
|
38619
|
+
defineBuiltin({
|
|
38620
|
+
name: "mexext",
|
|
38621
|
+
cases: [
|
|
38622
|
+
{
|
|
38623
|
+
match: (argTypes) => argTypes.length === 0 ? [{ kind: "char" }] : null,
|
|
38624
|
+
apply: () => RTV.char(getMexExt())
|
|
38625
|
+
}
|
|
38626
|
+
]
|
|
38627
|
+
});
|
|
37986
38628
|
var _platform = typeof process !== "undefined" ? process.platform : "linux";
|
|
37987
38629
|
for (const [name, val] of [
|
|
37988
38630
|
["ismac", _platform === "darwin"],
|
|
@@ -39028,7 +39670,7 @@ for (const name of ["clear", "clc", "clf"]) {
|
|
|
39028
39670
|
name,
|
|
39029
39671
|
resolve: () => ({
|
|
39030
39672
|
outputTypes: [],
|
|
39031
|
-
apply: () => 0
|
|
39673
|
+
apply: () => void 0
|
|
39032
39674
|
})
|
|
39033
39675
|
});
|
|
39034
39676
|
}
|
|
@@ -39162,7 +39804,7 @@ registerIBuiltin({
|
|
|
39162
39804
|
name: "set",
|
|
39163
39805
|
resolve: () => ({
|
|
39164
39806
|
outputTypes: [],
|
|
39165
|
-
apply: () => 0
|
|
39807
|
+
apply: () => void 0
|
|
39166
39808
|
})
|
|
39167
39809
|
});
|
|
39168
39810
|
for (const name of [
|
|
@@ -39184,7 +39826,7 @@ for (const name of [
|
|
|
39184
39826
|
name,
|
|
39185
39827
|
resolve: () => ({
|
|
39186
39828
|
outputTypes: [],
|
|
39187
|
-
apply: () => 0
|
|
39829
|
+
apply: () => void 0
|
|
39188
39830
|
})
|
|
39189
39831
|
});
|
|
39190
39832
|
}
|
|
@@ -40992,6 +41634,15 @@ var H = {
|
|
|
40992
41634
|
signatures: ["TF = isequal(A, B, ...)"],
|
|
40993
41635
|
description: "True if all inputs are equal (NaN ~= NaN)."
|
|
40994
41636
|
},
|
|
41637
|
+
// ── Dynamic evaluation ────────────────────────────────────────────────
|
|
41638
|
+
evalin: {
|
|
41639
|
+
signatures: ["V = evalin(WS, EXPR)", "V = evalin(WS, EXPR, DEFAULT)"],
|
|
41640
|
+
description: "Evaluate EXPR in workspace WS ('caller' or 'base'/'workspace').\n\nnumbl-specific note: variables read by evalin must be declared in the\nfunction that owns them with a `% external-access:` comment, e.g.\n function out = f()\n % external-access: x y\n x = 1; y = 2;\n ...\n end\nVariables not listed in `% external-access` are stored in a separate\ndynamic map and are only reachable through evalin/assignin. The\ndirective is a comment, so MATLAB ignores it."
|
|
41641
|
+
},
|
|
41642
|
+
assignin: {
|
|
41643
|
+
signatures: ["assignin(WS, NAME, VALUE)"],
|
|
41644
|
+
description: "Assign VALUE to variable NAME in workspace WS ('caller' or 'base'/'workspace').\n\nnumbl-specific note: variables written by assignin must be declared in\nthe function that owns them with a `% external-access:` comment, e.g.\n function out = f()\n % external-access: x y\n x = 1; y = 2;\n ...\n end\nVariables not listed in `% external-access` are stored in a separate\ndynamic map and are only reachable through evalin/assignin. The\ndirective is a comment, so MATLAB ignores it."
|
|
41645
|
+
},
|
|
40995
41646
|
// ── Misc ──────────────────────────────────────────────────────────────
|
|
40996
41647
|
disp: {
|
|
40997
41648
|
signatures: ["disp(X)"],
|
|
@@ -43904,6 +44555,114 @@ function bisectEvent(eventIdx, step, events) {
|
|
|
43904
44555
|
return [tOld + xFinal * h, denseOutputEval(yOld, Q, h, xFinal)];
|
|
43905
44556
|
}
|
|
43906
44557
|
|
|
44558
|
+
// src/numbl-core/helpers/quadgk.ts
|
|
44559
|
+
var XK = [
|
|
44560
|
+
-0.9914553711208126,
|
|
44561
|
+
-0.9491079123427585,
|
|
44562
|
+
-0.8648644233597691,
|
|
44563
|
+
-0.7415311855993945,
|
|
44564
|
+
-0.586087235467691,
|
|
44565
|
+
-0.4058451513773972,
|
|
44566
|
+
-0.2077849550078985,
|
|
44567
|
+
0,
|
|
44568
|
+
0.2077849550078985,
|
|
44569
|
+
0.4058451513773972,
|
|
44570
|
+
0.586087235467691,
|
|
44571
|
+
0.7415311855993945,
|
|
44572
|
+
0.8648644233597691,
|
|
44573
|
+
0.9491079123427585,
|
|
44574
|
+
0.9914553711208126
|
|
44575
|
+
];
|
|
44576
|
+
var WK = [
|
|
44577
|
+
0.0229353220105292,
|
|
44578
|
+
0.0630920926299786,
|
|
44579
|
+
0.1047900103222502,
|
|
44580
|
+
0.1406532597155259,
|
|
44581
|
+
0.1690047266392679,
|
|
44582
|
+
0.1903505780647854,
|
|
44583
|
+
0.2044329400752989,
|
|
44584
|
+
0.2094821410847278,
|
|
44585
|
+
0.2044329400752989,
|
|
44586
|
+
0.1903505780647854,
|
|
44587
|
+
0.1690047266392679,
|
|
44588
|
+
0.1406532597155259,
|
|
44589
|
+
0.1047900103222502,
|
|
44590
|
+
0.0630920926299786,
|
|
44591
|
+
0.0229353220105292
|
|
44592
|
+
];
|
|
44593
|
+
var WG = [
|
|
44594
|
+
0.1294849661688697,
|
|
44595
|
+
0.2797053914892767,
|
|
44596
|
+
0.3818300505051189,
|
|
44597
|
+
0.4179591836734694,
|
|
44598
|
+
0.3818300505051189,
|
|
44599
|
+
0.2797053914892767,
|
|
44600
|
+
0.1294849661688697
|
|
44601
|
+
];
|
|
44602
|
+
function kronrodNodes(lo, hi) {
|
|
44603
|
+
const m = (lo + hi) / 2;
|
|
44604
|
+
const h = (hi - lo) / 2;
|
|
44605
|
+
const out = new Array(15);
|
|
44606
|
+
for (let i = 0; i < 15; i++) out[i] = m + h * XK[i];
|
|
44607
|
+
return out;
|
|
44608
|
+
}
|
|
44609
|
+
function segmentEstimate(lo, hi, fv) {
|
|
44610
|
+
const h = (hi - lo) / 2;
|
|
44611
|
+
let K = 0;
|
|
44612
|
+
let G = 0;
|
|
44613
|
+
for (let i = 0; i < 15; i++) K += WK[i] * fv[i];
|
|
44614
|
+
for (let i = 0; i < 7; i++) G += WG[i] * fv[2 * i + 1];
|
|
44615
|
+
K *= h;
|
|
44616
|
+
G *= h;
|
|
44617
|
+
return { K, err: Math.abs(K - G) };
|
|
44618
|
+
}
|
|
44619
|
+
function quadgkAdaptive(integrand, a, b, opts = {}) {
|
|
44620
|
+
const relTol = opts.relTol ?? 1e-6;
|
|
44621
|
+
const absTol = opts.absTol ?? 1e-10;
|
|
44622
|
+
const maxIntervals = opts.maxIntervalCount ?? 650;
|
|
44623
|
+
if (a === b) return { value: 0, errbnd: 0, intervalsUsed: 0 };
|
|
44624
|
+
const sign = a < b ? 1 : -1;
|
|
44625
|
+
const lo0 = Math.min(a, b);
|
|
44626
|
+
const hi0 = Math.max(a, b);
|
|
44627
|
+
const segmentOn = (lo, hi) => {
|
|
44628
|
+
const pts = kronrodNodes(lo, hi);
|
|
44629
|
+
const fv = integrand(pts);
|
|
44630
|
+
if (fv.length !== 15) {
|
|
44631
|
+
throw new Error(
|
|
44632
|
+
`quadgk: integrand must return 15 values for 15 nodes, got ${fv.length}`
|
|
44633
|
+
);
|
|
44634
|
+
}
|
|
44635
|
+
return segmentEstimate(lo, hi, fv);
|
|
44636
|
+
};
|
|
44637
|
+
const initial = segmentOn(lo0, hi0);
|
|
44638
|
+
let totalK = initial.K;
|
|
44639
|
+
let totalErr = initial.err;
|
|
44640
|
+
const worklist = [{ lo: lo0, hi: hi0, ...initial }];
|
|
44641
|
+
const converged = () => totalErr <= Math.max(absTol, relTol * Math.abs(totalK));
|
|
44642
|
+
let iters = 0;
|
|
44643
|
+
while (!converged() && worklist.length < maxIntervals && iters < 1e4) {
|
|
44644
|
+
iters++;
|
|
44645
|
+
let worstIdx = 0;
|
|
44646
|
+
for (let i = 1; i < worklist.length; i++) {
|
|
44647
|
+
if (worklist[i].err > worklist[worstIdx].err) worstIdx = i;
|
|
44648
|
+
}
|
|
44649
|
+
const worst = worklist[worstIdx];
|
|
44650
|
+
if (worst.hi - worst.lo <= 1e-15 * (hi0 - lo0)) break;
|
|
44651
|
+
const mid = (worst.lo + worst.hi) / 2;
|
|
44652
|
+
const s1 = segmentOn(worst.lo, mid);
|
|
44653
|
+
const s2 = segmentOn(mid, worst.hi);
|
|
44654
|
+
totalK += s1.K + s2.K - worst.K;
|
|
44655
|
+
totalErr += s1.err + s2.err - worst.err;
|
|
44656
|
+
worklist[worstIdx] = { lo: worst.lo, hi: mid, ...s1 };
|
|
44657
|
+
worklist.push({ lo: mid, hi: worst.hi, ...s2 });
|
|
44658
|
+
}
|
|
44659
|
+
return {
|
|
44660
|
+
value: sign * totalK,
|
|
44661
|
+
errbnd: totalErr,
|
|
44662
|
+
intervalsUsed: worklist.length
|
|
44663
|
+
};
|
|
44664
|
+
}
|
|
44665
|
+
|
|
43907
44666
|
// src/numbl-core/runtime/specialBuiltinNames.ts
|
|
43908
44667
|
var SPECIAL_BUILTIN_NAMES = [
|
|
43909
44668
|
"help",
|
|
@@ -43992,6 +44751,7 @@ var SPECIAL_BUILTIN_NAMES = [
|
|
|
43992
44751
|
"webread",
|
|
43993
44752
|
"delete",
|
|
43994
44753
|
"rmdir",
|
|
44754
|
+
"movefile",
|
|
43995
44755
|
"unzip",
|
|
43996
44756
|
"dir",
|
|
43997
44757
|
"warning",
|
|
@@ -44005,7 +44765,8 @@ var SPECIAL_BUILTIN_NAMES = [
|
|
|
44005
44765
|
"ode45",
|
|
44006
44766
|
"ode23",
|
|
44007
44767
|
"deval",
|
|
44008
|
-
"toc"
|
|
44768
|
+
"toc",
|
|
44769
|
+
"quadgk"
|
|
44009
44770
|
];
|
|
44010
44771
|
|
|
44011
44772
|
// src/numbl-core/runtime/specialBuiltins.ts
|
|
@@ -44019,42 +44780,58 @@ function registerSpecial(name, fn) {
|
|
|
44019
44780
|
})
|
|
44020
44781
|
});
|
|
44021
44782
|
}
|
|
44783
|
+
function registerSpecialVoid(name, fn) {
|
|
44784
|
+
registerDynamicIBuiltin({
|
|
44785
|
+
name,
|
|
44786
|
+
resolve: () => ({
|
|
44787
|
+
outputTypes: [],
|
|
44788
|
+
apply: (args) => {
|
|
44789
|
+
fn(args);
|
|
44790
|
+
return void 0;
|
|
44791
|
+
}
|
|
44792
|
+
})
|
|
44793
|
+
});
|
|
44794
|
+
}
|
|
44022
44795
|
function registerSpecialBuiltins(rt) {
|
|
44023
|
-
registerSpecial("help", (
|
|
44796
|
+
registerSpecial("help", (nargout, args) => {
|
|
44797
|
+
let text = "";
|
|
44798
|
+
const emit = (s) => {
|
|
44799
|
+
text += s;
|
|
44800
|
+
if (nargout === 0) rt.output(s);
|
|
44801
|
+
};
|
|
44024
44802
|
if (args.length === 0) {
|
|
44025
44803
|
const names = getAllBuiltinNames().sort();
|
|
44026
|
-
|
|
44027
|
-
|
|
44028
|
-
|
|
44029
|
-
|
|
44030
|
-
|
|
44031
|
-
|
|
44032
|
-
|
|
44033
|
-
|
|
44034
|
-
|
|
44035
|
-
|
|
44036
|
-
rt.output(`No help available for '${name}'.
|
|
44804
|
+
emit("Available builtins:\n");
|
|
44805
|
+
emit(" " + names.join(", ") + "\n");
|
|
44806
|
+
emit("\nType 'help <name>' for help on a specific builtin.\n");
|
|
44807
|
+
} else {
|
|
44808
|
+
const name = toString(args[0]);
|
|
44809
|
+
const h = getIBuiltinHelp(name);
|
|
44810
|
+
if (!h) {
|
|
44811
|
+
const allNames = getAllBuiltinNames();
|
|
44812
|
+
if (allNames.includes(name)) {
|
|
44813
|
+
emit(`No help available for '${name}'.
|
|
44037
44814
|
`);
|
|
44038
|
-
|
|
44039
|
-
|
|
44815
|
+
} else {
|
|
44816
|
+
emit(`Unknown function '${name}'.
|
|
44040
44817
|
`);
|
|
44041
|
-
|
|
44042
|
-
|
|
44043
|
-
|
|
44044
|
-
rt.output(` ${h.signatures.join("\n ")}
|
|
44818
|
+
}
|
|
44819
|
+
} else {
|
|
44820
|
+
emit(` ${h.signatures.join("\n ")}
|
|
44045
44821
|
|
|
44046
44822
|
`);
|
|
44047
|
-
|
|
44823
|
+
emit(`${h.description}
|
|
44048
44824
|
`);
|
|
44049
|
-
|
|
44825
|
+
}
|
|
44826
|
+
}
|
|
44827
|
+
return nargout >= 1 ? RTV.char(text) : void 0;
|
|
44050
44828
|
});
|
|
44051
|
-
|
|
44829
|
+
registerSpecialVoid("disp", (args) => {
|
|
44052
44830
|
if (args.length >= 1) {
|
|
44053
44831
|
const mv = ensureRuntimeValue(args[0]);
|
|
44054
|
-
if (isRuntimeTensor(mv) && mv.data.length === 0) return
|
|
44832
|
+
if (isRuntimeTensor(mv) && mv.data.length === 0) return;
|
|
44055
44833
|
rt.output(displayValue(mv) + "\n");
|
|
44056
44834
|
}
|
|
44057
|
-
return 0;
|
|
44058
44835
|
});
|
|
44059
44836
|
registerSpecial("toc", (nargout) => {
|
|
44060
44837
|
const elapsed = (performance.now() - getTicTime()) / 1e3;
|
|
@@ -44064,12 +44841,13 @@ function registerSpecialBuiltins(rt) {
|
|
|
44064
44841
|
}
|
|
44065
44842
|
return RTV.num(elapsed);
|
|
44066
44843
|
});
|
|
44067
|
-
registerSpecial("warning", (
|
|
44068
|
-
if (args.length === 0) return RTV.num(0);
|
|
44844
|
+
registerSpecial("warning", (nargout, args) => {
|
|
44845
|
+
if (args.length === 0) return nargout >= 1 ? RTV.num(0) : void 0;
|
|
44069
44846
|
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
44070
44847
|
if (margs.length === 2 && isRuntimeChar(margs[0]) && isRuntimeChar(margs[1])) {
|
|
44071
44848
|
const state = toString(margs[0]);
|
|
44072
44849
|
if (state === "on" || state === "off") {
|
|
44850
|
+
if (nargout === 0) return void 0;
|
|
44073
44851
|
return RTV.struct(
|
|
44074
44852
|
/* @__PURE__ */ new Map([
|
|
44075
44853
|
["state", RTV.char("on")],
|
|
@@ -44098,9 +44876,9 @@ function registerSpecialBuiltins(rt) {
|
|
|
44098
44876
|
} else {
|
|
44099
44877
|
rt.output("Warning: " + sprintfFormat(fmt, fmtArgs) + "\n");
|
|
44100
44878
|
}
|
|
44101
|
-
return RTV.num(0);
|
|
44879
|
+
return nargout >= 1 ? RTV.num(0) : void 0;
|
|
44102
44880
|
});
|
|
44103
|
-
registerSpecial("fprintf", (
|
|
44881
|
+
registerSpecial("fprintf", (nargout, args) => {
|
|
44104
44882
|
let output = "";
|
|
44105
44883
|
if (args.length >= 1) {
|
|
44106
44884
|
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
@@ -44111,27 +44889,7 @@ function registerSpecialBuiltins(rt) {
|
|
|
44111
44889
|
fmtIdx = 1;
|
|
44112
44890
|
}
|
|
44113
44891
|
const fmt = toString(margs[fmtIdx]);
|
|
44114
|
-
|
|
44115
|
-
for (let i = fmtIdx + 1; i < margs.length; i++) {
|
|
44116
|
-
const a = margs[i];
|
|
44117
|
-
if (isRuntimeTensor(a)) {
|
|
44118
|
-
for (let j = 0; j < a.data.length; j++)
|
|
44119
|
-
scalarArgs.push(RTV.num(a.data[j]));
|
|
44120
|
-
} else {
|
|
44121
|
-
scalarArgs.push(a);
|
|
44122
|
-
}
|
|
44123
|
-
}
|
|
44124
|
-
const specCount = (fmt.match(/%[^%]/g) || []).length;
|
|
44125
|
-
if (specCount === 0 || scalarArgs.length === 0) {
|
|
44126
|
-
output = sprintfFormat(fmt, scalarArgs);
|
|
44127
|
-
} else {
|
|
44128
|
-
let idx = 0;
|
|
44129
|
-
while (idx < scalarArgs.length) {
|
|
44130
|
-
const batch = scalarArgs.slice(idx, idx + specCount);
|
|
44131
|
-
output += sprintfFormat(fmt, batch);
|
|
44132
|
-
idx += specCount;
|
|
44133
|
-
}
|
|
44134
|
-
}
|
|
44892
|
+
output = sprintfFormat(fmt, margs.slice(fmtIdx + 1));
|
|
44135
44893
|
if (fid === 1 || fid === 2) {
|
|
44136
44894
|
rt.output(output);
|
|
44137
44895
|
} else {
|
|
@@ -44142,7 +44900,7 @@ function registerSpecialBuiltins(rt) {
|
|
|
44142
44900
|
rt.fileIO.fwrite(fid, output);
|
|
44143
44901
|
}
|
|
44144
44902
|
}
|
|
44145
|
-
return output.length;
|
|
44903
|
+
return nargout >= 1 ? output.length : void 0;
|
|
44146
44904
|
});
|
|
44147
44905
|
registerSpecial("arrayfun", (nargout, args) => {
|
|
44148
44906
|
return arrayfunImpl(rt, nargout, args);
|
|
@@ -44174,6 +44932,55 @@ function registerSpecialBuiltins(rt) {
|
|
|
44174
44932
|
registerSpecial("bsxfun", (nargout, args) => {
|
|
44175
44933
|
return bsxfunImpl(rt, nargout, args);
|
|
44176
44934
|
});
|
|
44935
|
+
registerSpecial("quadgk", (nargout, args) => {
|
|
44936
|
+
if (args.length < 3)
|
|
44937
|
+
throw new RuntimeError(
|
|
44938
|
+
"quadgk: requires at least 3 arguments (fun, a, b)"
|
|
44939
|
+
);
|
|
44940
|
+
const fnArg = ensureRuntimeValue(args[0]);
|
|
44941
|
+
if (!isRuntimeFunction(fnArg))
|
|
44942
|
+
throw new RuntimeError("quadgk: first argument must be a function");
|
|
44943
|
+
const a = toNumber(ensureRuntimeValue(args[1]));
|
|
44944
|
+
const b = toNumber(ensureRuntimeValue(args[2]));
|
|
44945
|
+
let relTol;
|
|
44946
|
+
let absTol;
|
|
44947
|
+
let maxIntervalCount;
|
|
44948
|
+
for (let i = 3; i + 1 < args.length; i += 2) {
|
|
44949
|
+
const keyRv = ensureRuntimeValue(args[i]);
|
|
44950
|
+
const key = isRuntimeChar(keyRv) ? keyRv.value : isRuntimeString(keyRv) ? keyRv : "";
|
|
44951
|
+
const lowerKey = key.toLowerCase();
|
|
44952
|
+
const valRv = ensureRuntimeValue(args[i + 1]);
|
|
44953
|
+
if (lowerKey === "reltol") relTol = toNumber(valRv);
|
|
44954
|
+
else if (lowerKey === "abstol") absTol = toNumber(valRv);
|
|
44955
|
+
else if (lowerKey === "maxintervalcount")
|
|
44956
|
+
maxIntervalCount = toNumber(valRv);
|
|
44957
|
+
}
|
|
44958
|
+
const integrand = (pts) => {
|
|
44959
|
+
const vecData = new FloatXArray(pts);
|
|
44960
|
+
const vec = RTV.tensor(vecData, [1, pts.length]);
|
|
44961
|
+
const resultRaw = rt.index(fnArg, [vec], 1);
|
|
44962
|
+
const rv = ensureRuntimeValue(resultRaw);
|
|
44963
|
+
if (isRuntimeNumber(rv)) {
|
|
44964
|
+
return new Array(pts.length).fill(rv);
|
|
44965
|
+
}
|
|
44966
|
+
if (isRuntimeTensor(rv)) {
|
|
44967
|
+
if (rv.data.length !== pts.length) {
|
|
44968
|
+
throw new RuntimeError(
|
|
44969
|
+
`quadgk: integrand returned ${rv.data.length} values for ${pts.length} nodes`
|
|
44970
|
+
);
|
|
44971
|
+
}
|
|
44972
|
+
return Array.from(rv.data);
|
|
44973
|
+
}
|
|
44974
|
+
throw new RuntimeError("quadgk: integrand must return a numeric vector");
|
|
44975
|
+
};
|
|
44976
|
+
const result = quadgkAdaptive(integrand, a, b, {
|
|
44977
|
+
relTol,
|
|
44978
|
+
absTol,
|
|
44979
|
+
maxIntervalCount
|
|
44980
|
+
});
|
|
44981
|
+
if (nargout >= 2) return [result.value, result.errbnd];
|
|
44982
|
+
return result.value;
|
|
44983
|
+
});
|
|
44177
44984
|
registerSpecial("subsref", (nargout, args) => {
|
|
44178
44985
|
return subsrefBuiltin(rt, nargout, args);
|
|
44179
44986
|
});
|
|
@@ -44796,7 +45603,7 @@ function registerSpecialBuiltins(rt) {
|
|
|
44796
45603
|
return RTV.char(text);
|
|
44797
45604
|
}
|
|
44798
45605
|
});
|
|
44799
|
-
|
|
45606
|
+
registerSpecialVoid("delete", (args) => {
|
|
44800
45607
|
const io = requireFileIO();
|
|
44801
45608
|
if (!io.deleteFile)
|
|
44802
45609
|
throw new RuntimeError("delete is not available in this environment");
|
|
@@ -44806,7 +45613,6 @@ function registerSpecialBuiltins(rt) {
|
|
|
44806
45613
|
for (const arg of margs) {
|
|
44807
45614
|
io.deleteFile(toString(arg));
|
|
44808
45615
|
}
|
|
44809
|
-
return 0;
|
|
44810
45616
|
});
|
|
44811
45617
|
registerSpecial("rmdir", (nargout, args) => {
|
|
44812
45618
|
const io = requireFileIO();
|
|
@@ -44829,6 +45635,34 @@ function registerSpecialBuiltins(rt) {
|
|
|
44829
45635
|
RTV.char("")
|
|
44830
45636
|
];
|
|
44831
45637
|
});
|
|
45638
|
+
registerSpecial("movefile", (nargout, args) => {
|
|
45639
|
+
const io = requireFileIO();
|
|
45640
|
+
if (!io.movefile)
|
|
45641
|
+
throw new RuntimeError("movefile is not available in this environment");
|
|
45642
|
+
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
45643
|
+
if (margs.length < 1)
|
|
45644
|
+
throw new RuntimeError("movefile requires at least 1 argument");
|
|
45645
|
+
const source = toString(margs[0]);
|
|
45646
|
+
const destination = margs.length >= 2 ? toString(margs[1]) : rt.system?.cwd() ?? ".";
|
|
45647
|
+
let force = false;
|
|
45648
|
+
if (margs.length >= 3) {
|
|
45649
|
+
const third = toString(margs[2]);
|
|
45650
|
+
if (third.toLowerCase() === "f") force = true;
|
|
45651
|
+
}
|
|
45652
|
+
const ok = io.movefile(source, destination, force);
|
|
45653
|
+
if (nargout === 0) {
|
|
45654
|
+
if (!ok)
|
|
45655
|
+
throw new RuntimeError(
|
|
45656
|
+
`movefile: cannot move '${source}' to '${destination}'`
|
|
45657
|
+
);
|
|
45658
|
+
return void 0;
|
|
45659
|
+
}
|
|
45660
|
+
return nargout <= 1 ? RTV.num(ok ? 1 : 0) : [
|
|
45661
|
+
RTV.num(ok ? 1 : 0),
|
|
45662
|
+
RTV.char(ok ? "" : `Cannot move '${source}' to '${destination}'`),
|
|
45663
|
+
RTV.char("")
|
|
45664
|
+
];
|
|
45665
|
+
});
|
|
44832
45666
|
registerSpecial("unzip", (nargout, args) => {
|
|
44833
45667
|
const io = requireFileIO();
|
|
44834
45668
|
if (!io.unzip)
|
|
@@ -44880,7 +45714,7 @@ function registerSpecialBuiltins(rt) {
|
|
|
44880
45714
|
const cellData = extracted.map((f) => RTV.char(f));
|
|
44881
45715
|
return RTV.cell(cellData, [1, cellData.length]);
|
|
44882
45716
|
}
|
|
44883
|
-
return 0;
|
|
45717
|
+
return void 0;
|
|
44884
45718
|
});
|
|
44885
45719
|
registerSpecial("dir", (nargout, args) => {
|
|
44886
45720
|
const io = requireFileIO();
|
|
@@ -44977,7 +45811,7 @@ function registerSpecialBuiltins(rt) {
|
|
|
44977
45811
|
const parts = margs.map((a) => toString(a));
|
|
44978
45812
|
return RTV.char(parts.join("/"));
|
|
44979
45813
|
});
|
|
44980
|
-
|
|
45814
|
+
registerSpecialVoid("assignin", (args) => {
|
|
44981
45815
|
if (args.length < 3)
|
|
44982
45816
|
throw new RuntimeError("assignin requires 3 arguments");
|
|
44983
45817
|
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
@@ -44992,7 +45826,6 @@ function registerSpecialBuiltins(rt) {
|
|
|
44992
45826
|
} else {
|
|
44993
45827
|
rt.setWorkspaceVariable(varName, args[2]);
|
|
44994
45828
|
}
|
|
44995
|
-
return 0;
|
|
44996
45829
|
});
|
|
44997
45830
|
registerSpecial("evalin", (_nargout, args) => {
|
|
44998
45831
|
if (args.length < 2)
|
|
@@ -45013,13 +45846,12 @@ function registerSpecialBuiltins(rt) {
|
|
|
45013
45846
|
}
|
|
45014
45847
|
return val;
|
|
45015
45848
|
});
|
|
45016
|
-
|
|
45849
|
+
registerSpecialVoid("drawnow", () => {
|
|
45017
45850
|
rt.drawnow();
|
|
45018
|
-
return 0;
|
|
45019
45851
|
});
|
|
45020
|
-
registerSpecial("pause", (
|
|
45852
|
+
registerSpecial("pause", (nargout, args) => {
|
|
45021
45853
|
rt.pause(args[0] ?? 0);
|
|
45022
|
-
return 0;
|
|
45854
|
+
return nargout >= 1 ? RTV.char("on") : void 0;
|
|
45023
45855
|
});
|
|
45024
45856
|
registerSpecial("mfilename", (_nargout, args) => {
|
|
45025
45857
|
const file = rt.$file ?? "";
|
|
@@ -45063,7 +45895,7 @@ function registerSpecialBuiltins(rt) {
|
|
|
45063
45895
|
}
|
|
45064
45896
|
}
|
|
45065
45897
|
if (nargout >= 1) return RTV.char(rt.searchPaths.join(";"));
|
|
45066
|
-
return 0;
|
|
45898
|
+
return void 0;
|
|
45067
45899
|
});
|
|
45068
45900
|
registerSpecial("rmpath", (nargout, args) => {
|
|
45069
45901
|
if (!rt.onPathChange) {
|
|
@@ -45083,11 +45915,11 @@ function registerSpecialBuiltins(rt) {
|
|
|
45083
45915
|
}
|
|
45084
45916
|
}
|
|
45085
45917
|
if (nargout >= 1) return RTV.char(rt.searchPaths.join(";"));
|
|
45086
|
-
return 0;
|
|
45918
|
+
return void 0;
|
|
45087
45919
|
});
|
|
45088
|
-
registerSpecial("savepath", () => {
|
|
45920
|
+
registerSpecial("savepath", (nargout) => {
|
|
45089
45921
|
rt.output("Warning: savepath is a no-op in numbl\n");
|
|
45090
|
-
return 0;
|
|
45922
|
+
return nargout >= 1 ? RTV.num(0) : void 0;
|
|
45091
45923
|
});
|
|
45092
45924
|
registerSpecial("input", (_nargout, args) => {
|
|
45093
45925
|
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
@@ -45150,11 +45982,11 @@ function registerSpecialBuiltins(rt) {
|
|
|
45150
45982
|
}
|
|
45151
45983
|
return RTV.char(sys?.getEnv(toString(args[0])) ?? "");
|
|
45152
45984
|
});
|
|
45153
|
-
|
|
45985
|
+
registerSpecialVoid("setenv", (args) => {
|
|
45154
45986
|
const sys = rt.system;
|
|
45155
45987
|
if (args.length === 2) {
|
|
45156
45988
|
sys?.setEnv(toString(args[0]), toString(args[1]));
|
|
45157
|
-
return
|
|
45989
|
+
return;
|
|
45158
45990
|
}
|
|
45159
45991
|
if (args.length === 1) {
|
|
45160
45992
|
const d = args[0];
|
|
@@ -45162,20 +45994,26 @@ function registerSpecialBuiltins(rt) {
|
|
|
45162
45994
|
for (const { key, value } of d.entries.values()) {
|
|
45163
45995
|
sys?.setEnv(toString(key), toString(value));
|
|
45164
45996
|
}
|
|
45165
|
-
return
|
|
45997
|
+
return;
|
|
45166
45998
|
}
|
|
45167
45999
|
sys?.setEnv(toString(d), "");
|
|
45168
|
-
return
|
|
46000
|
+
return;
|
|
45169
46001
|
}
|
|
45170
46002
|
throw new RuntimeError("setenv: invalid arguments");
|
|
45171
46003
|
});
|
|
45172
46004
|
registerSpecial("pwd", () => {
|
|
45173
46005
|
return RTV.char(rt.system?.cwd() ?? "/");
|
|
45174
46006
|
});
|
|
45175
|
-
registerSpecial("cd", (
|
|
46007
|
+
registerSpecial("cd", (nargout, args) => {
|
|
45176
46008
|
const sys = rt.system;
|
|
45177
46009
|
const curDir = sys?.cwd() ?? "/";
|
|
45178
|
-
if (args.length === 0)
|
|
46010
|
+
if (args.length === 0) {
|
|
46011
|
+
if (nargout === 0) {
|
|
46012
|
+
rt.output(curDir + "\n");
|
|
46013
|
+
return void 0;
|
|
46014
|
+
}
|
|
46015
|
+
return RTV.char(curDir);
|
|
46016
|
+
}
|
|
45179
46017
|
const target = toString(args[0]);
|
|
45180
46018
|
if (sys) {
|
|
45181
46019
|
try {
|
|
@@ -45183,15 +46021,18 @@ function registerSpecialBuiltins(rt) {
|
|
|
45183
46021
|
} catch {
|
|
45184
46022
|
throw new RuntimeError(`Cannot change directory to '${target}'`);
|
|
45185
46023
|
}
|
|
46024
|
+
if (rt.onCwdChange) {
|
|
46025
|
+
rt.onCwdChange(sys.cwd());
|
|
46026
|
+
}
|
|
45186
46027
|
}
|
|
45187
|
-
return RTV.char(curDir);
|
|
46028
|
+
return nargout >= 1 ? RTV.char(curDir) : void 0;
|
|
45188
46029
|
});
|
|
45189
|
-
registerSpecial("figure", (
|
|
46030
|
+
registerSpecial("figure", (nargout, args) => {
|
|
45190
46031
|
const handle = args.length > 0 ? args[0] : 1;
|
|
45191
46032
|
plotInstr(rt.plotInstructions, { type: "set_figure_handle", handle });
|
|
45192
|
-
return 0;
|
|
46033
|
+
return nargout >= 1 ? RTV.num(toNumber(ensureRuntimeValue(handle))) : void 0;
|
|
45193
46034
|
});
|
|
45194
|
-
registerSpecial("subplot", (
|
|
46035
|
+
registerSpecial("subplot", (nargout, args) => {
|
|
45195
46036
|
if (args.length >= 3) {
|
|
45196
46037
|
plotInstr(rt.plotInstructions, {
|
|
45197
46038
|
type: "set_subplot",
|
|
@@ -45200,43 +46041,41 @@ function registerSpecialBuiltins(rt) {
|
|
|
45200
46041
|
index: args[2]
|
|
45201
46042
|
});
|
|
45202
46043
|
}
|
|
45203
|
-
return 0;
|
|
46044
|
+
return nargout >= 1 ? RTV.num(0) : void 0;
|
|
45204
46045
|
});
|
|
45205
|
-
registerSpecial("title", (
|
|
46046
|
+
registerSpecial("title", (nargout, args) => {
|
|
45206
46047
|
if (args.length > 0) {
|
|
45207
46048
|
plotInstr(rt.plotInstructions, { type: "set_title", text: args[0] });
|
|
45208
46049
|
}
|
|
45209
|
-
return 0;
|
|
46050
|
+
return nargout >= 1 ? RTV.num(0) : void 0;
|
|
45210
46051
|
});
|
|
45211
|
-
registerSpecial("xlabel", (
|
|
46052
|
+
registerSpecial("xlabel", (nargout, args) => {
|
|
45212
46053
|
if (args.length > 0) {
|
|
45213
46054
|
plotInstr(rt.plotInstructions, { type: "set_xlabel", text: args[0] });
|
|
45214
46055
|
}
|
|
45215
|
-
return 0;
|
|
46056
|
+
return nargout >= 1 ? RTV.num(0) : void 0;
|
|
45216
46057
|
});
|
|
45217
|
-
registerSpecial("ylabel", (
|
|
46058
|
+
registerSpecial("ylabel", (nargout, args) => {
|
|
45218
46059
|
if (args.length > 0) {
|
|
45219
46060
|
plotInstr(rt.plotInstructions, { type: "set_ylabel", text: args[0] });
|
|
45220
46061
|
}
|
|
45221
|
-
return 0;
|
|
46062
|
+
return nargout >= 1 ? RTV.num(0) : void 0;
|
|
45222
46063
|
});
|
|
45223
|
-
|
|
46064
|
+
registerSpecialVoid("hold", (args) => {
|
|
45224
46065
|
if (args.length > 0) {
|
|
45225
46066
|
plotInstr(rt.plotInstructions, { type: "set_hold", value: args[0] });
|
|
45226
46067
|
}
|
|
45227
|
-
return 0;
|
|
45228
46068
|
});
|
|
45229
|
-
|
|
46069
|
+
registerSpecialVoid("grid", (args) => {
|
|
45230
46070
|
if (args.length > 0) {
|
|
45231
46071
|
plotInstr(rt.plotInstructions, { type: "set_grid", value: args[0] });
|
|
45232
46072
|
}
|
|
45233
|
-
return 0;
|
|
45234
46073
|
});
|
|
45235
|
-
registerSpecial("legend", (
|
|
46074
|
+
registerSpecial("legend", (nargout, args) => {
|
|
45236
46075
|
legendCall(rt.plotInstructions, args);
|
|
45237
|
-
return 0;
|
|
46076
|
+
return nargout >= 1 ? RTV.num(0) : void 0;
|
|
45238
46077
|
});
|
|
45239
|
-
registerSpecial("close", (
|
|
46078
|
+
registerSpecial("close", (nargout, args) => {
|
|
45240
46079
|
if (args.length > 0) {
|
|
45241
46080
|
const val = toString(args[0]);
|
|
45242
46081
|
if (val === "all") {
|
|
@@ -45247,26 +46086,25 @@ function registerSpecialBuiltins(rt) {
|
|
|
45247
46086
|
} else {
|
|
45248
46087
|
plotInstr(rt.plotInstructions, { type: "close" });
|
|
45249
46088
|
}
|
|
45250
|
-
return 0;
|
|
46089
|
+
return nargout >= 1 ? RTV.num(1) : void 0;
|
|
45251
46090
|
});
|
|
45252
|
-
registerSpecial("sgtitle", (
|
|
46091
|
+
registerSpecial("sgtitle", (nargout, args) => {
|
|
45253
46092
|
if (args.length > 0) {
|
|
45254
46093
|
plotInstr(rt.plotInstructions, { type: "set_sgtitle", text: args[0] });
|
|
45255
46094
|
}
|
|
45256
|
-
return 0;
|
|
46095
|
+
return nargout >= 1 ? RTV.num(0) : void 0;
|
|
45257
46096
|
});
|
|
45258
|
-
|
|
46097
|
+
registerSpecialVoid("shading", (args) => {
|
|
45259
46098
|
if (args.length > 0) {
|
|
45260
46099
|
plotInstr(rt.plotInstructions, {
|
|
45261
46100
|
type: "set_shading",
|
|
45262
46101
|
shading: args[0]
|
|
45263
46102
|
});
|
|
45264
46103
|
}
|
|
45265
|
-
return 0;
|
|
45266
46104
|
});
|
|
45267
|
-
registerSpecial("clf", () => {
|
|
46105
|
+
registerSpecial("clf", (nargout) => {
|
|
45268
46106
|
plotInstr(rt.plotInstructions, { type: "clf" });
|
|
45269
|
-
return 0;
|
|
46107
|
+
return nargout >= 1 ? RTV.num(1) : void 0;
|
|
45270
46108
|
});
|
|
45271
46109
|
registerSpecial("ode45", (nargout, args) => {
|
|
45272
46110
|
return _ode45Impl(rt, nargout, args, dormandPrince45);
|
|
@@ -45811,6 +46649,29 @@ function methodDispatch(rt, name, nargout, args) {
|
|
|
45811
46649
|
}
|
|
45812
46650
|
return fieldVal;
|
|
45813
46651
|
}
|
|
46652
|
+
{
|
|
46653
|
+
const accessorKey = `${firstRV.className}.get.${name}`;
|
|
46654
|
+
if (!rt.activeAccessors.has(accessorKey)) {
|
|
46655
|
+
const getter = rt.cachedResolveClassMethod(
|
|
46656
|
+
firstRV.className,
|
|
46657
|
+
`get.${name}`
|
|
46658
|
+
);
|
|
46659
|
+
if (getter) {
|
|
46660
|
+
rt.activeAccessors.add(accessorKey);
|
|
46661
|
+
let gotVal;
|
|
46662
|
+
try {
|
|
46663
|
+
gotVal = getter(1, first);
|
|
46664
|
+
} finally {
|
|
46665
|
+
rt.activeAccessors.delete(accessorKey);
|
|
46666
|
+
}
|
|
46667
|
+
const remaining = args.slice(1);
|
|
46668
|
+
if (remaining.length > 0) {
|
|
46669
|
+
return rt.index(gotVal, remaining, nargout);
|
|
46670
|
+
}
|
|
46671
|
+
return gotVal;
|
|
46672
|
+
}
|
|
46673
|
+
}
|
|
46674
|
+
}
|
|
45814
46675
|
try {
|
|
45815
46676
|
return callClassMethod(rt, firstRV.className, name, nargout, args);
|
|
45816
46677
|
} catch (e) {
|
|
@@ -46379,6 +47240,7 @@ function index(rt, base, indices, nargout = 1, skipSubsref = false) {
|
|
|
46379
47240
|
const im2 = t.imag[i];
|
|
46380
47241
|
return im2 === 0 ? t.data[i] : RTV.complex(t.data[i], im2);
|
|
46381
47242
|
}
|
|
47243
|
+
if (t._isLogical === true) return t.data[i] !== 0;
|
|
46382
47244
|
return t.data[i];
|
|
46383
47245
|
}
|
|
46384
47246
|
} else if (nIdx === 2) {
|
|
@@ -46387,7 +47249,14 @@ function index(rt, base, indices, nargout = 1, skipSubsref = false) {
|
|
|
46387
47249
|
if (typeof ri === "number" && typeof ci === "number") {
|
|
46388
47250
|
const s = t.shape;
|
|
46389
47251
|
const rows = s.length === 0 ? 1 : s.length === 1 ? 1 : s[0];
|
|
46390
|
-
|
|
47252
|
+
let cols;
|
|
47253
|
+
if (s.length === 0) cols = 1;
|
|
47254
|
+
else if (s.length === 1) cols = s[0];
|
|
47255
|
+
else if (s.length === 2) cols = s[1];
|
|
47256
|
+
else {
|
|
47257
|
+
cols = 1;
|
|
47258
|
+
for (let k = 1; k < s.length; k++) cols *= s[k];
|
|
47259
|
+
}
|
|
46391
47260
|
const r = Math.round(ri) - 1;
|
|
46392
47261
|
const c = Math.round(ci) - 1;
|
|
46393
47262
|
if (r < 0 || r >= rows || c < 0 || c >= cols)
|
|
@@ -46397,6 +47266,7 @@ function index(rt, base, indices, nargout = 1, skipSubsref = false) {
|
|
|
46397
47266
|
const im2 = t.imag[lin];
|
|
46398
47267
|
return im2 === 0 ? t.data[lin] : RTV.complex(t.data[lin], im2);
|
|
46399
47268
|
}
|
|
47269
|
+
if (t._isLogical === true) return t.data[lin] !== 0;
|
|
46400
47270
|
return t.data[lin];
|
|
46401
47271
|
}
|
|
46402
47272
|
} else if (nIdx >= 3) {
|
|
@@ -46787,14 +47657,20 @@ function multiOutputCellAssign(base, indices, results) {
|
|
|
46787
47657
|
if (base === void 0 || base === null) base = RTV.cell([], [0, 0]);
|
|
46788
47658
|
let mv = ensureRuntimeValue(base);
|
|
46789
47659
|
if (!isRuntimeCell(mv)) mv = RTV.cell([], [0, 0]);
|
|
46790
|
-
const idxMv = ensureRuntimeValue(indices);
|
|
46791
47660
|
let idxArray;
|
|
46792
|
-
if (
|
|
46793
|
-
|
|
46794
|
-
|
|
46795
|
-
|
|
47661
|
+
if (indices === COLON_SENTINEL) {
|
|
47662
|
+
const n = mv.data.length;
|
|
47663
|
+
idxArray = [];
|
|
47664
|
+
for (let i = 1; i <= n; i++) idxArray.push(i);
|
|
46796
47665
|
} else {
|
|
46797
|
-
|
|
47666
|
+
const idxMv = ensureRuntimeValue(indices);
|
|
47667
|
+
if (isRuntimeTensor(idxMv)) {
|
|
47668
|
+
idxArray = Array.from(idxMv.data);
|
|
47669
|
+
} else if (isRuntimeNumber(idxMv)) {
|
|
47670
|
+
idxArray = [idxMv];
|
|
47671
|
+
} else {
|
|
47672
|
+
idxArray = [1];
|
|
47673
|
+
}
|
|
46798
47674
|
}
|
|
46799
47675
|
for (let i = 0; i < idxArray.length && i < results.length; i++) {
|
|
46800
47676
|
const idx = idxArray[i];
|
|
@@ -47021,6 +47897,8 @@ var Runtime = class _Runtime {
|
|
|
47021
47897
|
classMethodCache = /* @__PURE__ */ new Map();
|
|
47022
47898
|
/** Callback for addpath/rmpath — mutates search paths and rebuilds function index. */
|
|
47023
47899
|
onPathChange = null;
|
|
47900
|
+
/** Callback invoked after cd() to update the implicit cwd search path. */
|
|
47901
|
+
onCwdChange = null;
|
|
47024
47902
|
/** Reference to the active search paths (set by executeCode). */
|
|
47025
47903
|
searchPaths = [];
|
|
47026
47904
|
// Workspace accessors: varName → { get, set } closures over script-level vars
|
|
@@ -47300,23 +48178,26 @@ var Runtime = class _Runtime {
|
|
|
47300
48178
|
if (e instanceof RuntimeError) {
|
|
47301
48179
|
return RTV.struct(
|
|
47302
48180
|
/* @__PURE__ */ new Map([
|
|
47303
|
-
["message", RTV.
|
|
47304
|
-
["identifier", RTV.
|
|
48181
|
+
["message", RTV.char(e.message)],
|
|
48182
|
+
["identifier", RTV.char(e.identifier)],
|
|
48183
|
+
["stack", buildStackField(e)]
|
|
47305
48184
|
])
|
|
47306
48185
|
);
|
|
47307
48186
|
}
|
|
47308
48187
|
if (e instanceof Error) {
|
|
47309
48188
|
return RTV.struct(
|
|
47310
48189
|
/* @__PURE__ */ new Map([
|
|
47311
|
-
["message", RTV.
|
|
47312
|
-
["identifier", RTV.
|
|
48190
|
+
["message", RTV.char(e.message)],
|
|
48191
|
+
["identifier", RTV.char("")],
|
|
48192
|
+
["stack", emptyStackField()]
|
|
47313
48193
|
])
|
|
47314
48194
|
);
|
|
47315
48195
|
}
|
|
47316
48196
|
return RTV.struct(
|
|
47317
48197
|
/* @__PURE__ */ new Map([
|
|
47318
|
-
["message", RTV.
|
|
47319
|
-
["identifier", RTV.
|
|
48198
|
+
["message", RTV.char(String(e))],
|
|
48199
|
+
["identifier", RTV.char("")],
|
|
48200
|
+
["stack", emptyStackField()]
|
|
47320
48201
|
])
|
|
47321
48202
|
);
|
|
47322
48203
|
}
|
|
@@ -48148,6 +49029,63 @@ var rstr = (s) => {
|
|
|
48148
49029
|
if (isRuntimeChar(s)) return s.value;
|
|
48149
49030
|
throw new RuntimeError(`Expected string or char, got ${kstr(s)}`);
|
|
48150
49031
|
};
|
|
49032
|
+
function emptyStackField() {
|
|
49033
|
+
return RTV.structArray(["file", "name", "line"], []);
|
|
49034
|
+
}
|
|
49035
|
+
function buildStackField(e) {
|
|
49036
|
+
const fieldNames = ["file", "name", "line"];
|
|
49037
|
+
const frames = e.callStack;
|
|
49038
|
+
if (!frames || frames.length === 0) {
|
|
49039
|
+
if (e.file || e.line !== null) {
|
|
49040
|
+
return RTV.structArray(fieldNames, [
|
|
49041
|
+
RTV.struct(
|
|
49042
|
+
/* @__PURE__ */ new Map([
|
|
49043
|
+
["file", RTV.char(e.file ?? "")],
|
|
49044
|
+
["name", RTV.char("")],
|
|
49045
|
+
["line", e.line ?? 0]
|
|
49046
|
+
])
|
|
49047
|
+
)
|
|
49048
|
+
]);
|
|
49049
|
+
}
|
|
49050
|
+
return emptyStackField();
|
|
49051
|
+
}
|
|
49052
|
+
const elements = [];
|
|
49053
|
+
const N = frames.length;
|
|
49054
|
+
for (let i = N - 1; i >= 0; i--) {
|
|
49055
|
+
let frameFile;
|
|
49056
|
+
let frameLine;
|
|
49057
|
+
if (i === N - 1) {
|
|
49058
|
+
frameFile = e.file;
|
|
49059
|
+
frameLine = e.line ?? 0;
|
|
49060
|
+
} else {
|
|
49061
|
+
const callerFrame = frames[i + 1];
|
|
49062
|
+
frameFile = callerFrame.callerFile;
|
|
49063
|
+
frameLine = callerFrame.callerLine;
|
|
49064
|
+
}
|
|
49065
|
+
elements.push(
|
|
49066
|
+
RTV.struct(
|
|
49067
|
+
/* @__PURE__ */ new Map([
|
|
49068
|
+
["file", RTV.char(frameFile ?? "")],
|
|
49069
|
+
["name", RTV.char(frames[i].name)],
|
|
49070
|
+
["line", frameLine]
|
|
49071
|
+
])
|
|
49072
|
+
)
|
|
49073
|
+
);
|
|
49074
|
+
}
|
|
49075
|
+
const outermost = frames[0];
|
|
49076
|
+
if (outermost.callerFile && outermost.callerLine > 0) {
|
|
49077
|
+
elements.push(
|
|
49078
|
+
RTV.struct(
|
|
49079
|
+
/* @__PURE__ */ new Map([
|
|
49080
|
+
["file", RTV.char(outermost.callerFile)],
|
|
49081
|
+
["name", RTV.char("")],
|
|
49082
|
+
["line", outermost.callerLine]
|
|
49083
|
+
])
|
|
49084
|
+
)
|
|
49085
|
+
);
|
|
49086
|
+
}
|
|
49087
|
+
return RTV.structArray(fieldNames, elements);
|
|
49088
|
+
}
|
|
48151
49089
|
|
|
48152
49090
|
// src/numbl-core/jsUserFunctions.ts
|
|
48153
49091
|
function funcNameFromFile(fileName) {
|
|
@@ -50541,6 +51479,9 @@ function execStmt(stmt) {
|
|
|
50541
51479
|
case "ExprStmt": {
|
|
50542
51480
|
const val = this.evalExprNargout(stmt.expr, 0);
|
|
50543
51481
|
const singleVal = Array.isArray(val) ? val[0] : val;
|
|
51482
|
+
if (singleVal === void 0) {
|
|
51483
|
+
return null;
|
|
51484
|
+
}
|
|
50544
51485
|
const rv = ensureRuntimeValue(singleVal);
|
|
50545
51486
|
this.ans = rv;
|
|
50546
51487
|
this.env.set("ans", rv);
|
|
@@ -50564,19 +51505,25 @@ function execStmt(stmt) {
|
|
|
50564
51505
|
if (stmt.lvalues.length === 1 && stmt.lvalues[0].type === "IndexCell") {
|
|
50565
51506
|
const lv = stmt.lvalues[0];
|
|
50566
51507
|
const cellBase = lv.base.type === "Ident" ? this.env.get(lv.base.name) ?? RTV.cell([], [0, 0]) : this.evalExpr(lv.base);
|
|
50567
|
-
const indices =
|
|
50568
|
-
const idxVal = ensureRuntimeValue(indices[0]);
|
|
51508
|
+
const indices = this.evalIndicesWithEnd(cellBase, lv.indices);
|
|
50569
51509
|
let expandedCount = 1;
|
|
50570
|
-
|
|
50571
|
-
|
|
50572
|
-
|
|
50573
|
-
expandedCount =
|
|
51510
|
+
const idx0 = indices[0];
|
|
51511
|
+
if (idx0 === COLON_SENTINEL) {
|
|
51512
|
+
const baseRv = ensureRuntimeValue(cellBase);
|
|
51513
|
+
expandedCount = isRuntimeCell(baseRv) ? baseRv.data.length : 0;
|
|
51514
|
+
} else {
|
|
51515
|
+
const idxVal = ensureRuntimeValue(idx0);
|
|
51516
|
+
if (isRuntimeTensor(idxVal)) {
|
|
51517
|
+
expandedCount = idxVal.data.length;
|
|
51518
|
+
} else if (typeof idxVal === "number") {
|
|
51519
|
+
expandedCount = 1;
|
|
51520
|
+
}
|
|
50574
51521
|
}
|
|
50575
51522
|
const val2 = this.evalExprNargout(stmt.expr, expandedCount);
|
|
50576
51523
|
const values2 = Array.isArray(val2) ? val2 : [val2];
|
|
50577
51524
|
const result = this.rt.multiOutputCellAssign(
|
|
50578
51525
|
cellBase,
|
|
50579
|
-
|
|
51526
|
+
idx0,
|
|
50580
51527
|
values2.map((v) => ensureRuntimeValue(v))
|
|
50581
51528
|
);
|
|
50582
51529
|
if (lv.base.type === "Ident") {
|
|
@@ -51138,7 +52085,11 @@ function evalAnonFunc(expr) {
|
|
|
51138
52085
|
capturedMethodName,
|
|
51139
52086
|
() => {
|
|
51140
52087
|
try {
|
|
51141
|
-
|
|
52088
|
+
const result = this.evalExprNargout(bodyExpr, narg);
|
|
52089
|
+
if (narg > 1 && !(Array.isArray(result) && result.length >= narg)) {
|
|
52090
|
+
throw new RuntimeError("Too many output arguments.");
|
|
52091
|
+
}
|
|
52092
|
+
return result;
|
|
51142
52093
|
} finally {
|
|
51143
52094
|
this.env = savedEnv;
|
|
51144
52095
|
}
|
|
@@ -51618,6 +52569,17 @@ register("exist", (ctx, args) => {
|
|
|
51618
52569
|
}
|
|
51619
52570
|
return FALL_THROUGH;
|
|
51620
52571
|
});
|
|
52572
|
+
register("which", (ctx, args) => {
|
|
52573
|
+
if (args.length < 1) return FALL_THROUGH;
|
|
52574
|
+
const nameArg = toString(ensureRuntimeValue(args[0]));
|
|
52575
|
+
if (ctx.env.has(nameArg)) return RTV.char("variable");
|
|
52576
|
+
const filePath = ctx.lookupWorkspaceFile(nameArg);
|
|
52577
|
+
if (filePath) return RTV.char(filePath);
|
|
52578
|
+
if (ctx.rt.builtins[nameArg] || getIBuiltin(nameArg)) {
|
|
52579
|
+
return RTV.char("built-in");
|
|
52580
|
+
}
|
|
52581
|
+
return RTV.char("");
|
|
52582
|
+
});
|
|
51621
52583
|
register("isfolder", (ctx, args) => {
|
|
51622
52584
|
if (args.length < 1) return FALL_THROUGH;
|
|
51623
52585
|
const fio = ctx.rt.fileIO;
|
|
@@ -51720,6 +52682,9 @@ register("run", (ctx, args) => {
|
|
|
51720
52682
|
} catch {
|
|
51721
52683
|
throw new RuntimeError(`Cannot change directory to '${scriptDir}'`);
|
|
51722
52684
|
}
|
|
52685
|
+
if (ctx.rt.onCwdChange) {
|
|
52686
|
+
ctx.rt.onCwdChange(sys.cwd());
|
|
52687
|
+
}
|
|
51723
52688
|
}
|
|
51724
52689
|
const cwdAfterCd = sys?.cwd() ?? "/";
|
|
51725
52690
|
try {
|
|
@@ -51731,6 +52696,9 @@ register("run", (ctx, args) => {
|
|
|
51731
52696
|
sys.chdir(oldCwd);
|
|
51732
52697
|
} catch {
|
|
51733
52698
|
}
|
|
52699
|
+
if (ctx.rt.onCwdChange) {
|
|
52700
|
+
ctx.rt.onCwdChange(sys.cwd());
|
|
52701
|
+
}
|
|
51734
52702
|
}
|
|
51735
52703
|
}
|
|
51736
52704
|
return void 0;
|
|
@@ -51750,7 +52718,14 @@ function callFunction(name, args, nargout) {
|
|
|
51750
52718
|
workspaceEnv: this.workspaceEnv,
|
|
51751
52719
|
evalInLocalScope: (codeArg, fileName) => this.evalInLocalScope(codeArg, fileName),
|
|
51752
52720
|
callFunction: (n, a, no) => this.callFunction(n, a, no),
|
|
51753
|
-
rt: this.rt
|
|
52721
|
+
rt: this.rt,
|
|
52722
|
+
lookupWorkspaceFile: (n) => {
|
|
52723
|
+
const entry = this.ctx.registry.filesByFuncName.get(n);
|
|
52724
|
+
if (entry) return entry.fileName;
|
|
52725
|
+
const classInfo = this.ctx.getClassInfo(n);
|
|
52726
|
+
if (classInfo) return classInfo.fileName;
|
|
52727
|
+
return void 0;
|
|
52728
|
+
}
|
|
51754
52729
|
};
|
|
51755
52730
|
const result = specialHandler(ctx, args, nargout);
|
|
51756
52731
|
if (result !== FALL_THROUGH) return result;
|
|
@@ -51784,13 +52759,18 @@ function interpretTarget(target, args, nargout) {
|
|
|
51784
52759
|
const argTypes = margs.map(inferJitType);
|
|
51785
52760
|
const resolution = ib.resolve(argTypes, nargout);
|
|
51786
52761
|
if (resolution) {
|
|
52762
|
+
const isVoid = resolution.outputTypes.length === 0;
|
|
52763
|
+
if (isVoid && nargout > 0) {
|
|
52764
|
+
throw new RuntimeError("Too many output arguments.");
|
|
52765
|
+
}
|
|
51787
52766
|
if (this.rt.profilingEnabled) {
|
|
51788
52767
|
this.rt.profileEnter("builtin:interp:" + target.name);
|
|
51789
|
-
const
|
|
52768
|
+
const result2 = resolution.apply(margs, nargout);
|
|
51790
52769
|
this.rt.profileLeave();
|
|
51791
|
-
return
|
|
52770
|
+
return isVoid ? void 0 : result2;
|
|
51792
52771
|
}
|
|
51793
|
-
|
|
52772
|
+
const result = resolution.apply(margs, nargout);
|
|
52773
|
+
return isVoid ? void 0 : result;
|
|
51794
52774
|
}
|
|
51795
52775
|
}
|
|
51796
52776
|
const builtin = this.rt.builtins[target.name];
|
|
@@ -51882,7 +52862,19 @@ function interpretLocalFunction(target, args, nargout) {
|
|
|
51882
52862
|
function interpretWorkspaceFunction(target, args, nargout) {
|
|
51883
52863
|
const dotIdx = target.name.lastIndexOf(".");
|
|
51884
52864
|
const primaryName = dotIdx >= 0 ? target.name.slice(dotIdx + 1) : target.name;
|
|
51885
|
-
|
|
52865
|
+
let fn = this.findFunctionInWorkspaceFile(target.name, primaryName);
|
|
52866
|
+
if (!fn) {
|
|
52867
|
+
const entry = this.ctx.registry.filesByFuncName.get(target.name);
|
|
52868
|
+
if (entry) {
|
|
52869
|
+
const ast = this.ctx.getCachedAST(entry.fileName);
|
|
52870
|
+
for (const stmt of ast.body) {
|
|
52871
|
+
if (stmt.type === "Function") {
|
|
52872
|
+
fn = funcDefFromStmt(stmt);
|
|
52873
|
+
break;
|
|
52874
|
+
}
|
|
52875
|
+
}
|
|
52876
|
+
}
|
|
52877
|
+
}
|
|
51886
52878
|
if (!fn) {
|
|
51887
52879
|
const entry = this.ctx.registry.filesByFuncName.get(target.name);
|
|
51888
52880
|
if (entry) {
|
|
@@ -52026,6 +53018,11 @@ function interpretConstructor(classInfo, args, nargout) {
|
|
|
52026
53018
|
return args[0];
|
|
52027
53019
|
}
|
|
52028
53020
|
function callUserFunction(fn, args, nargout, narginOverride) {
|
|
53021
|
+
const hasVarargoutDecl = fn.outputs.length > 0 && fn.outputs[fn.outputs.length - 1] === "varargout";
|
|
53022
|
+
const declaredRegularOutputs = hasVarargoutDecl ? fn.outputs.length - 1 : fn.outputs.length;
|
|
53023
|
+
if (!hasVarargoutDecl && nargout > declaredRegularOutputs) {
|
|
53024
|
+
throw new RuntimeError("Too many output arguments.");
|
|
53025
|
+
}
|
|
52029
53026
|
if (this.optimization >= 1 && narginOverride === void 0) {
|
|
52030
53027
|
const jitResult = tryJitCall(this, fn, args, nargout);
|
|
52031
53028
|
if (jitResult !== JIT_SKIP) return jitResult;
|
|
@@ -52075,7 +53072,7 @@ function callUserFunction(fn, args, nargout, narginOverride) {
|
|
|
52075
53072
|
}
|
|
52076
53073
|
}
|
|
52077
53074
|
}
|
|
52078
|
-
const hasVarargout =
|
|
53075
|
+
const hasVarargout = hasVarargoutDecl;
|
|
52079
53076
|
const regularOutputs = hasVarargout ? fn.outputs.slice(0, -1) : fn.outputs;
|
|
52080
53077
|
const collectCount = nargout === 0 && regularOutputs.length > 0 ? 1 : Math.min(regularOutputs.length, nargout);
|
|
52081
53078
|
const outputs = [];
|
|
@@ -53680,6 +54677,31 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
|
|
|
53680
54677
|
}
|
|
53681
54678
|
}
|
|
53682
54679
|
}
|
|
54680
|
+
let implicitCwdPath = null;
|
|
54681
|
+
if (options.implicitCwdPath !== null && options.system && options.fileIO?.scanDirectory) {
|
|
54682
|
+
try {
|
|
54683
|
+
const cwd = options.implicitCwdPath ?? options.system.cwd();
|
|
54684
|
+
const absCwd = options.fileIO.resolvePath?.(cwd) ?? cwd;
|
|
54685
|
+
const explicitPaths = searchPaths ?? [];
|
|
54686
|
+
if (!explicitPaths.includes(absCwd)) {
|
|
54687
|
+
implicitCwdPath = absCwd;
|
|
54688
|
+
const prefix = absCwd.endsWith("/") ? absCwd : absCwd + "/";
|
|
54689
|
+
const alreadyHave = mWorkspaceFiles.some(
|
|
54690
|
+
(f) => f.name === absCwd || f.name.startsWith(prefix)
|
|
54691
|
+
);
|
|
54692
|
+
if (!alreadyHave) {
|
|
54693
|
+
const cwdFiles = options.fileIO.scanDirectory(absCwd);
|
|
54694
|
+
for (const f of cwdFiles) {
|
|
54695
|
+
if (f.name.endsWith(".m")) {
|
|
54696
|
+
mWorkspaceFiles.push(f);
|
|
54697
|
+
}
|
|
54698
|
+
}
|
|
54699
|
+
}
|
|
54700
|
+
}
|
|
54701
|
+
} catch {
|
|
54702
|
+
implicitCwdPath = null;
|
|
54703
|
+
}
|
|
54704
|
+
}
|
|
53683
54705
|
const jsUserFunctions = loadJsUserFunctions(
|
|
53684
54706
|
jsWorkspaceFiles,
|
|
53685
54707
|
wasmWorkspaceFiles,
|
|
@@ -53697,6 +54719,9 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
|
|
|
53697
54719
|
stdlibShimNames.add(shimName);
|
|
53698
54720
|
}
|
|
53699
54721
|
ctx.registry.searchPaths = [...searchPaths ?? [], SHIM_SEARCH_PATH];
|
|
54722
|
+
if (implicitCwdPath !== null) {
|
|
54723
|
+
ctx.registry.searchPaths.unshift(implicitCwdPath);
|
|
54724
|
+
}
|
|
53700
54725
|
ctx.fileASTCache.set(mainFileName, ast);
|
|
53701
54726
|
const skippedFiles = /* @__PURE__ */ new Set();
|
|
53702
54727
|
for (const f of mWorkspaceFiles) {
|
|
@@ -53730,6 +54755,11 @@ function executeCode(source, options = {}, workspaceFiles, mainFileName = "scrip
|
|
|
53730
54755
|
ctx.registerWorkspaceFiles(mWorkspaceFiles);
|
|
53731
54756
|
}
|
|
53732
54757
|
const functionIndex = ctx.buildFunctionIndex(jsUserFunctionNames);
|
|
54758
|
+
const savedSpecialBuiltins = /* @__PURE__ */ new Map();
|
|
54759
|
+
for (const name of SPECIAL_BUILTIN_NAMES) {
|
|
54760
|
+
const existing = getIBuiltin(name);
|
|
54761
|
+
if (existing) savedSpecialBuiltins.set(name, existing);
|
|
54762
|
+
}
|
|
53733
54763
|
const rt = new Runtime(options, options.initialVariableValues);
|
|
53734
54764
|
const savedIBuiltins = /* @__PURE__ */ new Map();
|
|
53735
54765
|
for (const ib of jsUserFunctions) {
|
|
@@ -53771,13 +54801,39 @@ ${jsCode}`
|
|
|
53771
54801
|
interpreter.installRuntimeCallbacks();
|
|
53772
54802
|
rt.searchPaths = ctx.registry.searchPaths;
|
|
53773
54803
|
let pathsModified = false;
|
|
54804
|
+
const rebuildWorkspace = () => {
|
|
54805
|
+
const paths = ctx.registry.searchPaths;
|
|
54806
|
+
const priorityOf = (name) => {
|
|
54807
|
+
let bestIdx = paths.length;
|
|
54808
|
+
let bestLen = -1;
|
|
54809
|
+
for (let i = 0; i < paths.length; i++) {
|
|
54810
|
+
const p2 = paths[i];
|
|
54811
|
+
const withSep = p2.endsWith("/") ? p2 : p2 + "/";
|
|
54812
|
+
if (name === p2 || name.startsWith(withSep)) {
|
|
54813
|
+
if (p2.length > bestLen) {
|
|
54814
|
+
bestLen = p2.length;
|
|
54815
|
+
bestIdx = i;
|
|
54816
|
+
}
|
|
54817
|
+
}
|
|
54818
|
+
}
|
|
54819
|
+
return bestIdx;
|
|
54820
|
+
};
|
|
54821
|
+
mWorkspaceFiles.sort((a, b) => priorityOf(a.name) - priorityOf(b.name));
|
|
54822
|
+
ctx.clearWorkspaceRegistrations();
|
|
54823
|
+
ctx.registerWorkspaceFiles(mWorkspaceFiles);
|
|
54824
|
+
const newIndex = ctx.buildFunctionIndex(jsUserFunctionNames);
|
|
54825
|
+
interpreter.functionIndex = newIndex;
|
|
54826
|
+
interpreter.clearAllCaches();
|
|
54827
|
+
pathsModified = true;
|
|
54828
|
+
};
|
|
53774
54829
|
rt.onPathChange = (action, dir, position) => {
|
|
53775
54830
|
const fileIO = options.fileIO;
|
|
53776
54831
|
const absDir = fileIO?.resolvePath?.(dir) ?? dir;
|
|
53777
54832
|
if (action === "add") {
|
|
53778
54833
|
if (ctx.registry.searchPaths.includes(absDir)) return;
|
|
53779
54834
|
if (position === "begin") {
|
|
53780
|
-
ctx.registry.searchPaths
|
|
54835
|
+
const cwdIsFirst = implicitCwdPath !== null && ctx.registry.searchPaths[0] === implicitCwdPath;
|
|
54836
|
+
ctx.registry.searchPaths.splice(cwdIsFirst ? 1 : 0, 0, absDir);
|
|
53781
54837
|
} else {
|
|
53782
54838
|
const shimIdx = ctx.registry.searchPaths.indexOf(SHIM_SEARCH_PATH);
|
|
53783
54839
|
if (shimIdx >= 0) {
|
|
@@ -53795,10 +54851,14 @@ ${jsCode}`
|
|
|
53795
54851
|
try {
|
|
53796
54852
|
ctx.fileASTCache.set(f.name, parseMFile(f.source, f.name));
|
|
53797
54853
|
} catch (e) {
|
|
53798
|
-
if (e instanceof SyntaxError
|
|
53799
|
-
|
|
54854
|
+
if (e instanceof SyntaxError) {
|
|
54855
|
+
console.warn(
|
|
54856
|
+
`Warning: skipping ${f.name} (syntax error at line ${e.line ?? "?"})`
|
|
54857
|
+
);
|
|
54858
|
+
} else {
|
|
54859
|
+
console.warn(`Warning: skipping ${f.name} (parse error)`);
|
|
53800
54860
|
}
|
|
53801
|
-
|
|
54861
|
+
continue;
|
|
53802
54862
|
}
|
|
53803
54863
|
interpreter.fileSources.set(f.name, f.source);
|
|
53804
54864
|
mWorkspaceFiles.push(f);
|
|
@@ -53838,26 +54898,76 @@ ${jsCode}`
|
|
|
53838
54898
|
}
|
|
53839
54899
|
}
|
|
53840
54900
|
}
|
|
53841
|
-
|
|
53842
|
-
|
|
53843
|
-
|
|
53844
|
-
|
|
53845
|
-
|
|
53846
|
-
|
|
53847
|
-
|
|
54901
|
+
rebuildWorkspace();
|
|
54902
|
+
};
|
|
54903
|
+
rt.onCwdChange = (newCwd) => {
|
|
54904
|
+
const fileIO = options.fileIO;
|
|
54905
|
+
const absNewCwd = fileIO?.resolvePath?.(newCwd) ?? newCwd;
|
|
54906
|
+
if (implicitCwdPath === absNewCwd) return;
|
|
54907
|
+
if (implicitCwdPath !== null) {
|
|
54908
|
+
const oldPrefix = implicitCwdPath.endsWith("/") ? implicitCwdPath : implicitCwdPath + "/";
|
|
54909
|
+
const deeperPaths = ctx.registry.searchPaths.filter(
|
|
54910
|
+
(p2) => p2 !== implicitCwdPath && p2 !== SHIM_SEARCH_PATH && (p2 === implicitCwdPath || p2.startsWith(oldPrefix))
|
|
53848
54911
|
);
|
|
53849
|
-
const
|
|
53850
|
-
|
|
53851
|
-
|
|
53852
|
-
|
|
53853
|
-
|
|
53854
|
-
|
|
53855
|
-
|
|
53856
|
-
|
|
53857
|
-
|
|
53858
|
-
|
|
54912
|
+
const fileBelongsToDeeperPath = (fname) => {
|
|
54913
|
+
for (const p2 of deeperPaths) {
|
|
54914
|
+
const withSep = p2.endsWith("/") ? p2 : p2 + "/";
|
|
54915
|
+
if (fname === p2 || fname.startsWith(withSep)) return true;
|
|
54916
|
+
}
|
|
54917
|
+
return false;
|
|
54918
|
+
};
|
|
54919
|
+
for (let i = mWorkspaceFiles.length - 1; i >= 0; i--) {
|
|
54920
|
+
const fname = mWorkspaceFiles[i].name;
|
|
54921
|
+
if ((fname === implicitCwdPath || fname.startsWith(oldPrefix)) && !fileBelongsToDeeperPath(fname)) {
|
|
54922
|
+
ctx.fileASTCache.delete(fname);
|
|
54923
|
+
interpreter.fileSources.delete(fname);
|
|
54924
|
+
mWorkspaceFiles.splice(i, 1);
|
|
54925
|
+
}
|
|
54926
|
+
}
|
|
54927
|
+
const oldIdx = ctx.registry.searchPaths.indexOf(implicitCwdPath);
|
|
54928
|
+
if (oldIdx >= 0) ctx.registry.searchPaths.splice(oldIdx, 1);
|
|
54929
|
+
implicitCwdPath = null;
|
|
54930
|
+
}
|
|
54931
|
+
if (ctx.registry.searchPaths.includes(absNewCwd)) {
|
|
54932
|
+
rebuildWorkspace();
|
|
54933
|
+
return;
|
|
54934
|
+
}
|
|
54935
|
+
ctx.registry.searchPaths.unshift(absNewCwd);
|
|
54936
|
+
implicitCwdPath = absNewCwd;
|
|
54937
|
+
if (fileIO?.scanDirectory) {
|
|
54938
|
+
let newFiles = [];
|
|
54939
|
+
try {
|
|
54940
|
+
newFiles = fileIO.scanDirectory(absNewCwd);
|
|
54941
|
+
} catch {
|
|
54942
|
+
}
|
|
54943
|
+
for (const f of newFiles) {
|
|
54944
|
+
if (f.name.endsWith(".m") && !ctx.fileASTCache.has(f.name)) {
|
|
54945
|
+
try {
|
|
54946
|
+
ctx.fileASTCache.set(f.name, parseMFile(f.source, f.name));
|
|
54947
|
+
} catch (e) {
|
|
54948
|
+
if (e instanceof SyntaxError) {
|
|
54949
|
+
console.warn(
|
|
54950
|
+
`Warning: skipping ${f.name} (syntax error at line ${e.line ?? "?"})`
|
|
54951
|
+
);
|
|
54952
|
+
} else {
|
|
54953
|
+
console.warn(`Warning: skipping ${f.name} (parse error)`);
|
|
54954
|
+
}
|
|
54955
|
+
continue;
|
|
54956
|
+
}
|
|
54957
|
+
interpreter.fileSources.set(f.name, f.source);
|
|
54958
|
+
mWorkspaceFiles.push(f);
|
|
54959
|
+
}
|
|
54960
|
+
}
|
|
54961
|
+
}
|
|
54962
|
+
rebuildWorkspace();
|
|
53859
54963
|
};
|
|
53860
54964
|
rt.evalLocalCallback = (code, initialVars, onOutput, fileName) => {
|
|
54965
|
+
const nestedSearchPaths = ctx.registry.searchPaths.filter(
|
|
54966
|
+
(p2) => p2 !== SHIM_SEARCH_PATH && p2 !== implicitCwdPath
|
|
54967
|
+
);
|
|
54968
|
+
const nestedWorkspaceFiles = mWorkspaceFiles.filter(
|
|
54969
|
+
(f) => !stdlibShimNames.has(f.name)
|
|
54970
|
+
);
|
|
53861
54971
|
const evalResult = executeCode(
|
|
53862
54972
|
code,
|
|
53863
54973
|
{
|
|
@@ -53865,11 +54975,18 @@ ${jsCode}`
|
|
|
53865
54975
|
displayResults: false,
|
|
53866
54976
|
initialVariableValues: initialVars,
|
|
53867
54977
|
fileIO: options.fileIO,
|
|
53868
|
-
|
|
54978
|
+
system: options.system,
|
|
54979
|
+
onInput: options.onInput,
|
|
54980
|
+
implicitCwdPath
|
|
53869
54981
|
},
|
|
53870
|
-
|
|
53871
|
-
fileName
|
|
54982
|
+
nestedWorkspaceFiles,
|
|
54983
|
+
fileName,
|
|
54984
|
+
nestedSearchPaths,
|
|
54985
|
+
nativeBridge
|
|
53872
54986
|
);
|
|
54987
|
+
if (evalResult.implicitCwdPath !== void 0) {
|
|
54988
|
+
implicitCwdPath = evalResult.implicitCwdPath;
|
|
54989
|
+
}
|
|
53873
54990
|
return {
|
|
53874
54991
|
returnValue: evalResult.returnValue,
|
|
53875
54992
|
variableValues: evalResult.variableValues,
|
|
@@ -53901,12 +55018,13 @@ ${jitSections.join("\n\n")}` : "// No JS generated",
|
|
|
53901
55018
|
}
|
|
53902
55019
|
if (pathsModified) {
|
|
53903
55020
|
result.searchPaths = ctx.registry.searchPaths.filter(
|
|
53904
|
-
(p2) => p2 !== SHIM_SEARCH_PATH
|
|
55021
|
+
(p2) => p2 !== SHIM_SEARCH_PATH && p2 !== implicitCwdPath
|
|
53905
55022
|
);
|
|
53906
55023
|
result.workspaceFiles = mWorkspaceFiles.filter(
|
|
53907
55024
|
(f) => !stdlibShimNames.has(f.name)
|
|
53908
55025
|
);
|
|
53909
55026
|
}
|
|
55027
|
+
result.implicitCwdPath = implicitCwdPath;
|
|
53910
55028
|
return result;
|
|
53911
55029
|
} catch (e) {
|
|
53912
55030
|
const generatedJS = jitSections.length > 0 ? `// Interpreter mode \u2014 JIT compiled sections:
|
|
@@ -53942,6 +55060,9 @@ ${jitSections.join("\n\n")}` : "// No JS generated";
|
|
|
53942
55060
|
unregisterIBuiltin(ib.name);
|
|
53943
55061
|
}
|
|
53944
55062
|
}
|
|
55063
|
+
for (const [, ib] of savedSpecialBuiltins) {
|
|
55064
|
+
registerDynamicIBuiltin(ib);
|
|
55065
|
+
}
|
|
53945
55066
|
}
|
|
53946
55067
|
}
|
|
53947
55068
|
export {
|