numbl 0.4.10 → 0.4.11
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-browser/browser/session.d.ts +1 -1
- package/dist-browser/browser.js +2 -2
- package/dist-browser/numbl-core/interpreter/interpreter.d.ts +2 -0
- package/dist-browser/numbl-core/interpreter/interpreterFunctions.d.ts +8 -0
- package/dist-browser/numbl-core/lowering/classInfo.d.ts +6 -0
- package/dist-browser/numbl-core/parser/ClassParser.d.ts +5 -0
- package/dist-browser/numbl-core/parser/types.d.ts +7 -1
- package/dist-browser/numbl-core/runtime/runtimeEnum.d.ts +33 -0
- package/dist-browser/numbl-core/runtime/types.d.ts +5 -1
- package/dist-browser/numbl-core/version.d.ts +1 -1
- package/dist-cli/cli.js +295 -10
- package/dist-lib/lib.js +294 -9
- package/dist-lib/numbl-core/interpreter/interpreter.d.ts +2 -0
- package/dist-lib/numbl-core/interpreter/interpreterFunctions.d.ts +8 -0
- package/dist-lib/numbl-core/lowering/classInfo.d.ts +6 -0
- package/dist-lib/numbl-core/parser/ClassParser.d.ts +5 -0
- package/dist-lib/numbl-core/parser/types.d.ts +7 -1
- package/dist-lib/numbl-core/runtime/runtimeEnum.d.ts +33 -0
- package/dist-lib/numbl-core/runtime/types.d.ts +5 -1
- package/dist-lib/numbl-core/version.d.ts +1 -1
- package/dist-site-viewer/assets/{index-CT9HA1Pn.js → index-fhKbvuOM.js} +286 -286
- package/dist-site-viewer/assets/{numbl-worker-CYPflGmm.js → numbl-worker-BFP9xj5e.js} +98 -98
- package/dist-site-viewer/index.html +1 -1
- package/package.json +1 -1
package/dist-lib/lib.js
CHANGED
|
@@ -280,12 +280,17 @@ var RuntimeClassInstance = class extends Refcounted {
|
|
|
280
280
|
/** For classes that inherit from built-in types (e.g. classdef Foo < double),
|
|
281
281
|
* stores the underlying built-in data. */
|
|
282
282
|
_builtinData;
|
|
283
|
-
|
|
283
|
+
/** For enumeration-class members: the member name (e.g. "tri"). When set,
|
|
284
|
+
* this instance is an enumeration member and `_builtinData` holds its
|
|
285
|
+
* underlying (superclass) value. Drives ==/~=, switch, and char coercion. */
|
|
286
|
+
_enumMember;
|
|
287
|
+
constructor(className, fields, isHandleClass2, _builtinData, _enumMember) {
|
|
284
288
|
super();
|
|
285
289
|
this.className = className;
|
|
286
290
|
this.fields = fields;
|
|
287
291
|
this.isHandleClass = isHandleClass2;
|
|
288
292
|
this._builtinData = _builtinData;
|
|
293
|
+
this._enumMember = _enumMember;
|
|
289
294
|
for (const v of fields.values()) incref(v);
|
|
290
295
|
if (_builtinData !== void 0) incref(_builtinData);
|
|
291
296
|
}
|
|
@@ -788,6 +793,10 @@ var valuesAreEqual = (a, b) => {
|
|
|
788
793
|
return a === b;
|
|
789
794
|
}
|
|
790
795
|
case "class_instance": {
|
|
796
|
+
const bi = b;
|
|
797
|
+
if (a._enumMember !== void 0 || bi._enumMember !== void 0) {
|
|
798
|
+
return a._enumMember === bi._enumMember && a.className === bi.className;
|
|
799
|
+
}
|
|
791
800
|
return a === b;
|
|
792
801
|
}
|
|
793
802
|
case "complex_number": {
|
|
@@ -21556,6 +21565,15 @@ function inferJitType(value) {
|
|
|
21556
21565
|
fields
|
|
21557
21566
|
};
|
|
21558
21567
|
}
|
|
21568
|
+
if (isRuntimeClassInstanceArray(value)) {
|
|
21569
|
+
const arr = value;
|
|
21570
|
+
return {
|
|
21571
|
+
kind: "class_instance",
|
|
21572
|
+
className: arr.className,
|
|
21573
|
+
isHandleClass: false,
|
|
21574
|
+
fields: {}
|
|
21575
|
+
};
|
|
21576
|
+
}
|
|
21559
21577
|
if (typeof value === "object" && value !== null && value.kind === "function") {
|
|
21560
21578
|
return { kind: "function_handle" };
|
|
21561
21579
|
}
|
|
@@ -24044,6 +24062,19 @@ function assignSlice(base, rowIndices, colIndices, rhs, curRows) {
|
|
|
24044
24062
|
if (isRuntimeTensor(rhs)) {
|
|
24045
24063
|
const nR = rowIndices.length;
|
|
24046
24064
|
const nC = colIndices.length;
|
|
24065
|
+
if (rhs.data.length === 1) {
|
|
24066
|
+
const re = rhs.data[0];
|
|
24067
|
+
const im = rhs.imag ? rhs.imag[0] : 0;
|
|
24068
|
+
if (im !== 0 || base.imag) ensureImag(base);
|
|
24069
|
+
for (const r of rowIndices) {
|
|
24070
|
+
for (const c of colIndices) {
|
|
24071
|
+
const li = colMajorIndex(r, c, curRows);
|
|
24072
|
+
base.data[li] = re;
|
|
24073
|
+
if (base.imag) base.imag[li] = im;
|
|
24074
|
+
}
|
|
24075
|
+
}
|
|
24076
|
+
return;
|
|
24077
|
+
}
|
|
24047
24078
|
const [rhsRows, rhsCols] = tensorSize2D(rhs);
|
|
24048
24079
|
const shapeMatches = rhsRows === nR && rhsCols === nC;
|
|
24049
24080
|
const sliceIsVector = nR === 1 || nC === 1;
|
|
@@ -31246,11 +31277,15 @@ var ClassParser = class extends FunctionParser {
|
|
|
31246
31277
|
} else if (tok === 20 /* Enumeration */) {
|
|
31247
31278
|
this.pos++;
|
|
31248
31279
|
const attrs = this.parseOptionalAttrList();
|
|
31249
|
-
const
|
|
31280
|
+
const enumMembers = this.parseEnumerationBlock();
|
|
31250
31281
|
if (!this.consume(15 /* End */)) {
|
|
31251
31282
|
throw this.error("expected 'end' after enumeration");
|
|
31252
31283
|
}
|
|
31253
|
-
members.push({
|
|
31284
|
+
members.push({
|
|
31285
|
+
type: "Enumeration",
|
|
31286
|
+
attributes: attrs,
|
|
31287
|
+
members: enumMembers
|
|
31288
|
+
});
|
|
31254
31289
|
} else if (tok === 21 /* Arguments */) {
|
|
31255
31290
|
this.pos++;
|
|
31256
31291
|
const attrs = this.parseOptionalAttrList();
|
|
@@ -31291,6 +31326,38 @@ var ClassParser = class extends FunctionParser {
|
|
|
31291
31326
|
}
|
|
31292
31327
|
return names;
|
|
31293
31328
|
}
|
|
31329
|
+
/** Parse an `enumeration ... end` member list. Each member is a bare
|
|
31330
|
+
* identifier optionally followed by a parenthesized argument list
|
|
31331
|
+
* (`quad (0)`, `Error (1, 0, 0)`). Members are separated by `;`/`,`/
|
|
31332
|
+
* newline. The args are evaluated later (at member construction). */
|
|
31333
|
+
parseEnumerationBlock() {
|
|
31334
|
+
const members = [];
|
|
31335
|
+
while (this.peekToken() !== void 0) {
|
|
31336
|
+
if (this.peekToken() === 15 /* End */) break;
|
|
31337
|
+
if (this.consume(49 /* Semicolon */) || this.consume(47 /* Comma */) || this.consume(68 /* Newline */)) {
|
|
31338
|
+
continue;
|
|
31339
|
+
}
|
|
31340
|
+
if (this.peekToken() !== 4 /* Ident */) break;
|
|
31341
|
+
const name = this.expectIdent();
|
|
31342
|
+
const args = [];
|
|
31343
|
+
if (this.consume(50 /* LParen */)) {
|
|
31344
|
+
if (this.peekToken() !== 51 /* RParen */) {
|
|
31345
|
+
args.push(this.parseExpr());
|
|
31346
|
+
while (this.consume(47 /* Comma */)) {
|
|
31347
|
+
args.push(this.parseExpr());
|
|
31348
|
+
}
|
|
31349
|
+
}
|
|
31350
|
+
if (!this.consume(51 /* RParen */)) {
|
|
31351
|
+
throw this.errorWithExpected(
|
|
31352
|
+
"expected ')' after enumeration member arguments",
|
|
31353
|
+
")"
|
|
31354
|
+
);
|
|
31355
|
+
}
|
|
31356
|
+
}
|
|
31357
|
+
members.push({ name, args });
|
|
31358
|
+
}
|
|
31359
|
+
return members;
|
|
31360
|
+
}
|
|
31294
31361
|
parsePropertiesNamesBlock() {
|
|
31295
31362
|
const props = [];
|
|
31296
31363
|
while (this.peekToken() !== void 0) {
|
|
@@ -32132,6 +32199,96 @@ function getConstant(name) {
|
|
|
32132
32199
|
var COLON_SENTINEL = /* @__PURE__ */ Symbol("COLON");
|
|
32133
32200
|
var END_SENTINEL = /* @__PURE__ */ Symbol("END");
|
|
32134
32201
|
|
|
32202
|
+
// src/numbl-core/runtime/runtimeEnum.ts
|
|
32203
|
+
function isEnumInstance(v) {
|
|
32204
|
+
return isRuntimeClassInstance(v) && v._enumMember !== void 0;
|
|
32205
|
+
}
|
|
32206
|
+
function isEnumValue(v) {
|
|
32207
|
+
if (isEnumInstance(v)) return true;
|
|
32208
|
+
if (isRuntimeClassInstanceArray(v))
|
|
32209
|
+
return v.elements.some((e) => e._enumMember !== void 0);
|
|
32210
|
+
return false;
|
|
32211
|
+
}
|
|
32212
|
+
function asText(v) {
|
|
32213
|
+
if (isRuntimeChar(v)) return v.value;
|
|
32214
|
+
if (isRuntimeString(v)) return v;
|
|
32215
|
+
return null;
|
|
32216
|
+
}
|
|
32217
|
+
function enumScalarEquals(e, other) {
|
|
32218
|
+
const text = asText(other);
|
|
32219
|
+
if (text !== null) return e._enumMember === text;
|
|
32220
|
+
if (isEnumInstance(other)) {
|
|
32221
|
+
if (e._builtinData !== void 0 && other._builtinData !== void 0) {
|
|
32222
|
+
return toNumber(e._builtinData) === toNumber(other._builtinData);
|
|
32223
|
+
}
|
|
32224
|
+
return e._enumMember === other._enumMember;
|
|
32225
|
+
}
|
|
32226
|
+
if (e._builtinData !== void 0) {
|
|
32227
|
+
if (isRuntimeNumber(other)) return toNumber(e._builtinData) === other;
|
|
32228
|
+
if (isRuntimeLogical(other))
|
|
32229
|
+
return toNumber(e._builtinData) === (other ? 1 : 0);
|
|
32230
|
+
}
|
|
32231
|
+
return false;
|
|
32232
|
+
}
|
|
32233
|
+
function decompose(v) {
|
|
32234
|
+
if (isEnumInstance(v)) return { elems: [v], shape: [1, 1] };
|
|
32235
|
+
if (isRuntimeClassInstanceArray(v))
|
|
32236
|
+
return { elems: [...v.elements], shape: v.shape };
|
|
32237
|
+
if (isRuntimeChar(v)) return { elems: [v], shape: [1, 1] };
|
|
32238
|
+
if (isRuntimeString(v)) return { elems: [v], shape: [1, 1] };
|
|
32239
|
+
if (isRuntimeStringArray(v))
|
|
32240
|
+
return { elems: v.data.map((s) => s), shape: v.shape };
|
|
32241
|
+
if (isRuntimeNumber(v) || isRuntimeLogical(v))
|
|
32242
|
+
return { elems: [v], shape: [1, 1] };
|
|
32243
|
+
if (isRuntimeTensor(v)) {
|
|
32244
|
+
const shape = [v.shape[0] ?? 0, v.shape[1] ?? 1];
|
|
32245
|
+
return { elems: Array.from(v.data, (x) => x), shape };
|
|
32246
|
+
}
|
|
32247
|
+
return null;
|
|
32248
|
+
}
|
|
32249
|
+
function elementEquals(x, y) {
|
|
32250
|
+
if (isEnumInstance(x)) return enumScalarEquals(x, y);
|
|
32251
|
+
if (isEnumInstance(y)) return enumScalarEquals(y, x);
|
|
32252
|
+
return false;
|
|
32253
|
+
}
|
|
32254
|
+
function enumEqualityOp(op, a, b) {
|
|
32255
|
+
if (op !== "Equal" /* Equal */ && op !== "NotEqual" /* NotEqual */)
|
|
32256
|
+
return null;
|
|
32257
|
+
if (!isEnumValue(a) && !isEnumValue(b)) return null;
|
|
32258
|
+
const oa = decompose(a);
|
|
32259
|
+
const ob = decompose(b);
|
|
32260
|
+
if (!oa || !ob) return null;
|
|
32261
|
+
const na = oa.elems.length;
|
|
32262
|
+
const nb = ob.elems.length;
|
|
32263
|
+
let n;
|
|
32264
|
+
let shape;
|
|
32265
|
+
if (na === nb) {
|
|
32266
|
+
n = na;
|
|
32267
|
+
shape = oa.shape;
|
|
32268
|
+
} else if (na === 1) {
|
|
32269
|
+
n = nb;
|
|
32270
|
+
shape = ob.shape;
|
|
32271
|
+
} else if (nb === 1) {
|
|
32272
|
+
n = na;
|
|
32273
|
+
shape = oa.shape;
|
|
32274
|
+
} else {
|
|
32275
|
+
throw new RuntimeError("Array dimensions must match for comparison");
|
|
32276
|
+
}
|
|
32277
|
+
const negate = op === "NotEqual" /* NotEqual */;
|
|
32278
|
+
const out = new Float64Array(n);
|
|
32279
|
+
for (let i = 0; i < n; i++) {
|
|
32280
|
+
const eq2 = elementEquals(
|
|
32281
|
+
oa.elems[na === 1 ? 0 : i],
|
|
32282
|
+
ob.elems[nb === 1 ? 0 : i]
|
|
32283
|
+
);
|
|
32284
|
+
out[i] = (negate ? !eq2 : eq2) ? 1 : 0;
|
|
32285
|
+
}
|
|
32286
|
+
if (n === 1) return RTV.logical(out[0] === 1);
|
|
32287
|
+
const t = RTV.tensor(out, [shape[0], shape[1]]);
|
|
32288
|
+
t._isLogical = true;
|
|
32289
|
+
return t;
|
|
32290
|
+
}
|
|
32291
|
+
|
|
32135
32292
|
// src/numbl-core/runtime/runtimeHelpers.ts
|
|
32136
32293
|
function isDeferredRange(v) {
|
|
32137
32294
|
return typeof v === "object" && v !== null && v["_deferredRange"] === true;
|
|
@@ -32156,6 +32313,8 @@ function ensureRuntimeValue(v) {
|
|
|
32156
32313
|
return v;
|
|
32157
32314
|
}
|
|
32158
32315
|
function switchValuesMatch(a, b) {
|
|
32316
|
+
if (isEnumInstance(a)) return enumScalarEquals(a, b);
|
|
32317
|
+
if (isEnumInstance(b)) return enumScalarEquals(b, a);
|
|
32159
32318
|
if ((isRuntimeChar(a) || isRuntimeString(a)) && (isRuntimeChar(b) || isRuntimeString(b))) {
|
|
32160
32319
|
return (typeof a === "string" ? a : a.value) === (typeof b === "string" ? b : b.value);
|
|
32161
32320
|
}
|
|
@@ -34870,6 +35029,8 @@ function sparseToDense2(S) {
|
|
|
34870
35029
|
return RTV.tensor(data, [S.m, S.n], imag2);
|
|
34871
35030
|
}
|
|
34872
35031
|
function valuesEqualSimple(a, b) {
|
|
35032
|
+
if (isEnumInstance(a)) return enumScalarEquals(a, b);
|
|
35033
|
+
if (isEnumInstance(b)) return enumScalarEquals(b, a);
|
|
34873
35034
|
{
|
|
34874
35035
|
const aText = textValue(a);
|
|
34875
35036
|
const bText = textValue(b);
|
|
@@ -43412,7 +43573,8 @@ function copyClassInstance(inst) {
|
|
|
43412
43573
|
inst.className,
|
|
43413
43574
|
new Map(inst.fields),
|
|
43414
43575
|
inst.isHandleClass,
|
|
43415
|
-
inst._builtinData
|
|
43576
|
+
inst._builtinData,
|
|
43577
|
+
inst._enumMember
|
|
43416
43578
|
);
|
|
43417
43579
|
}
|
|
43418
43580
|
function repelemObjects(v, repArgs) {
|
|
@@ -46500,6 +46662,15 @@ defineBuiltin({
|
|
|
46500
46662
|
});
|
|
46501
46663
|
|
|
46502
46664
|
// src/numbl-core/interpreter/builtins/type-constructors.ts
|
|
46665
|
+
function classInstanceArrayNumeric(v) {
|
|
46666
|
+
if (!isRuntimeClassInstanceArray(v)) return null;
|
|
46667
|
+
const data = allocFloat64Array(v.elements.length);
|
|
46668
|
+
for (let i = 0; i < v.elements.length; i++) {
|
|
46669
|
+
const bd = v.elements[i]._builtinData;
|
|
46670
|
+
data[i] = bd !== void 0 ? toNumber(bd) : NaN;
|
|
46671
|
+
}
|
|
46672
|
+
return RTV.tensor(data, [v.shape[0], v.shape[1]]);
|
|
46673
|
+
}
|
|
46503
46674
|
function parseDoubleText(s) {
|
|
46504
46675
|
const t = s.trim();
|
|
46505
46676
|
if (t === "") return NaN;
|
|
@@ -46554,6 +46725,8 @@ defineBuiltin({
|
|
|
46554
46725
|
if (isRuntimeClassInstance(v) && v._builtinData !== void 0) {
|
|
46555
46726
|
return v._builtinData;
|
|
46556
46727
|
}
|
|
46728
|
+
const arr = classInstanceArrayNumeric(v);
|
|
46729
|
+
if (arr) return arr;
|
|
46557
46730
|
return RTV.num(toNumber(v));
|
|
46558
46731
|
}
|
|
46559
46732
|
}
|
|
@@ -46581,6 +46754,8 @@ function singleApply(v) {
|
|
|
46581
46754
|
}
|
|
46582
46755
|
if (isRuntimeClassInstance(v) && v._builtinData !== void 0)
|
|
46583
46756
|
return singleApply(v._builtinData);
|
|
46757
|
+
const arr = classInstanceArrayNumeric(v);
|
|
46758
|
+
if (arr) return singleApply(arr);
|
|
46584
46759
|
return RTV.num(Math.fround(toNumber(v)));
|
|
46585
46760
|
}
|
|
46586
46761
|
defineBuiltin({
|
|
@@ -46640,7 +46815,7 @@ for (const { name, min: min2, max: max2 } of INT_RANGES) {
|
|
|
46640
46815
|
match: (argTypes) => {
|
|
46641
46816
|
if (argTypes.length !== 1) return null;
|
|
46642
46817
|
const a = argTypes[0];
|
|
46643
|
-
if (a.kind === "number" || a.kind === "boolean" || a.kind === "char" || a.kind === "complex_or_number")
|
|
46818
|
+
if (a.kind === "number" || a.kind === "boolean" || a.kind === "char" || a.kind === "complex_or_number" || a.kind === "class_instance")
|
|
46644
46819
|
return [{ kind: "number" }];
|
|
46645
46820
|
if (a.kind === "tensor")
|
|
46646
46821
|
return [
|
|
@@ -46654,7 +46829,7 @@ for (const { name, min: min2, max: max2 } of INT_RANGES) {
|
|
|
46654
46829
|
return null;
|
|
46655
46830
|
},
|
|
46656
46831
|
apply: (args) => {
|
|
46657
|
-
const v = args[0];
|
|
46832
|
+
const v = isRuntimeClassInstance(args[0]) && args[0]._builtinData !== void 0 ? args[0]._builtinData : classInstanceArrayNumeric(args[0]) ?? args[0];
|
|
46658
46833
|
if (isRuntimeNumber(v))
|
|
46659
46834
|
return RTV.num(saturateRoundToward(v, min2, max2));
|
|
46660
46835
|
if (isRuntimeLogical(v)) return RTV.num(v ? 1 : 0);
|
|
@@ -46909,7 +47084,7 @@ defineBuiltin({
|
|
|
46909
47084
|
match: (argTypes) => {
|
|
46910
47085
|
if (argTypes.length !== 1) return null;
|
|
46911
47086
|
const a = argTypes[0];
|
|
46912
|
-
if (a.kind === "number" || a.kind === "boolean")
|
|
47087
|
+
if (a.kind === "number" || a.kind === "boolean" || a.kind === "class_instance")
|
|
46913
47088
|
return [{ kind: "boolean" }];
|
|
46914
47089
|
if (a.kind === "tensor")
|
|
46915
47090
|
return [
|
|
@@ -46924,7 +47099,7 @@ defineBuiltin({
|
|
|
46924
47099
|
return null;
|
|
46925
47100
|
},
|
|
46926
47101
|
apply: (args) => {
|
|
46927
|
-
const v = args[0];
|
|
47102
|
+
const v = isRuntimeClassInstance(args[0]) && args[0]._builtinData !== void 0 ? args[0]._builtinData : classInstanceArrayNumeric(args[0]) ?? args[0];
|
|
46928
47103
|
if (isRuntimeTensor(v)) {
|
|
46929
47104
|
const result = allocFloat64Array(v.data.length);
|
|
46930
47105
|
for (let i = 0; i < v.data.length; i++) {
|
|
@@ -59928,7 +60103,16 @@ function indexStore(rt, base, indices, rhs, skipSubsasgn = false) {
|
|
|
59928
60103
|
}
|
|
59929
60104
|
existing[k] = rhsInst;
|
|
59930
60105
|
if (existing.length === 1) return existing[0];
|
|
59931
|
-
|
|
60106
|
+
const origShape = isRuntimeClassInstanceArray(mv) ? mv.shape : null;
|
|
60107
|
+
let shape;
|
|
60108
|
+
if (origShape && existing.length === origShape[0] * origShape[1]) {
|
|
60109
|
+
shape = origShape;
|
|
60110
|
+
} else if (origShape && origShape[1] === 1) {
|
|
60111
|
+
shape = [existing.length, 1];
|
|
60112
|
+
} else {
|
|
60113
|
+
shape = [1, existing.length];
|
|
60114
|
+
}
|
|
60115
|
+
return RTV.classInstanceArray(className, existing, shape);
|
|
59932
60116
|
}
|
|
59933
60117
|
}
|
|
59934
60118
|
if (isRuntimeClassInstance(mv)) {
|
|
@@ -65588,6 +65772,8 @@ function evalBinary(expr) {
|
|
|
65588
65772
|
const right = this.evalExpr(expr.right);
|
|
65589
65773
|
const lv = ensureRuntimeValue(left);
|
|
65590
65774
|
const rv = ensureRuntimeValue(right);
|
|
65775
|
+
const enumResult = enumEqualityOp(expr.op, lv, rv);
|
|
65776
|
+
if (enumResult !== null) return enumResult;
|
|
65591
65777
|
if (isRuntimeClassInstance(lv) || isRuntimeClassInstance(rv)) {
|
|
65592
65778
|
return this.rt.binop(expr.op, left, right);
|
|
65593
65779
|
}
|
|
@@ -65692,6 +65878,8 @@ function evalMember(expr, nargout) {
|
|
|
65692
65878
|
if (lastDot > 0) {
|
|
65693
65879
|
const prefix = dottedName.slice(0, lastDot);
|
|
65694
65880
|
const methodName = dottedName.slice(lastDot + 1);
|
|
65881
|
+
const enumMember = this.interpretEnumMember(prefix, methodName);
|
|
65882
|
+
if (enumMember !== null) return enumMember;
|
|
65695
65883
|
if (this.functionIndex.classStaticMethods.get(prefix)?.has(methodName) || // Implicit static `ClassName.empty` (handled by interpretClassMethod)
|
|
65696
65884
|
methodName === "empty" && this.functionIndex.workspaceClasses.has(prefix)) {
|
|
65697
65885
|
const target = {
|
|
@@ -66151,6 +66339,7 @@ __export(interpreterFunctions_exports, {
|
|
|
66151
66339
|
callNestedFunction: () => callNestedFunction,
|
|
66152
66340
|
callUserFunction: () => callUserFunction,
|
|
66153
66341
|
collectClassProperties: () => collectClassProperties,
|
|
66342
|
+
convertToEnum: () => convertToEnum,
|
|
66154
66343
|
declaredNargin: () => declaredNargin,
|
|
66155
66344
|
evalInLocalScope: () => evalInLocalScope,
|
|
66156
66345
|
findExternalMethod: () => findExternalMethod,
|
|
@@ -66162,6 +66351,7 @@ __export(interpreterFunctions_exports, {
|
|
|
66162
66351
|
instantiateClass: () => instantiateClass,
|
|
66163
66352
|
interpretClassMethod: () => interpretClassMethod,
|
|
66164
66353
|
interpretConstructor: () => interpretConstructor,
|
|
66354
|
+
interpretEnumMember: () => interpretEnumMember,
|
|
66165
66355
|
interpretJsUserFunction: () => interpretJsUserFunction,
|
|
66166
66356
|
interpretLocalFunction: () => interpretLocalFunction,
|
|
66167
66357
|
interpretPrivateFunction: () => interpretPrivateFunction,
|
|
@@ -66991,11 +67181,95 @@ function interpretPrivateFunction(target, args, nargout) {
|
|
|
66991
67181
|
}
|
|
66992
67182
|
throw new RuntimeError(`Private function '${target.name}' not found`);
|
|
66993
67183
|
}
|
|
67184
|
+
var NUMERIC_ENUM_SUPERS = /* @__PURE__ */ new Set([
|
|
67185
|
+
"double",
|
|
67186
|
+
"single",
|
|
67187
|
+
"int8",
|
|
67188
|
+
"int16",
|
|
67189
|
+
"int32",
|
|
67190
|
+
"int64",
|
|
67191
|
+
"uint8",
|
|
67192
|
+
"uint16",
|
|
67193
|
+
"uint32",
|
|
67194
|
+
"uint64",
|
|
67195
|
+
"logical",
|
|
67196
|
+
"char"
|
|
67197
|
+
]);
|
|
67198
|
+
function enumUnderlyingValue(interp, classInfo, argExprs) {
|
|
67199
|
+
if (argExprs.length === 0) return void 0;
|
|
67200
|
+
const first = ensureRuntimeValue(interp.evalExpr(argExprs[0]));
|
|
67201
|
+
const sc = classInfo.superClass;
|
|
67202
|
+
if (sc && NUMERIC_ENUM_SUPERS.has(sc)) {
|
|
67203
|
+
return ensureRuntimeValue(interp.rt.callBuiltin(sc, 1, [first]));
|
|
67204
|
+
}
|
|
67205
|
+
return first;
|
|
67206
|
+
}
|
|
67207
|
+
function interpretEnumMember(className, memberName) {
|
|
67208
|
+
const classInfo = this.ctx.getClassInfo(className);
|
|
67209
|
+
if (!classInfo || !classInfo.enumMembers) return null;
|
|
67210
|
+
const memberDef = classInfo.enumMembers.find((m) => m.name === memberName);
|
|
67211
|
+
if (!memberDef) return null;
|
|
67212
|
+
const value = enumUnderlyingValue(this, classInfo, memberDef.args);
|
|
67213
|
+
return new RuntimeClassInstance(
|
|
67214
|
+
className,
|
|
67215
|
+
/* @__PURE__ */ new Map(),
|
|
67216
|
+
false,
|
|
67217
|
+
value,
|
|
67218
|
+
memberName
|
|
67219
|
+
);
|
|
67220
|
+
}
|
|
67221
|
+
function convertToEnum(className, classInfo, args) {
|
|
67222
|
+
if (args.length === 0) {
|
|
67223
|
+
throw new RuntimeError(
|
|
67224
|
+
`${className}: enumeration requires an argument to construct`
|
|
67225
|
+
);
|
|
67226
|
+
}
|
|
67227
|
+
const val = ensureRuntimeValue(args[0]);
|
|
67228
|
+
if (isRuntimeClassInstance(val) && val._enumMember !== void 0) return val;
|
|
67229
|
+
if (isRuntimeClassInstanceArray(val)) return val;
|
|
67230
|
+
const members = classInfo.enumMembers.map((m) => ({
|
|
67231
|
+
name: m.name,
|
|
67232
|
+
value: enumUnderlyingValue(this, classInfo, m.args)
|
|
67233
|
+
}));
|
|
67234
|
+
const makeMember = (name, value) => new RuntimeClassInstance(className, /* @__PURE__ */ new Map(), false, value, name);
|
|
67235
|
+
const fromName = (text) => {
|
|
67236
|
+
const m = members.find((mm) => mm.name === text);
|
|
67237
|
+
if (!m)
|
|
67238
|
+
throw new RuntimeError(
|
|
67239
|
+
`'${text}' is not a valid member of enumeration '${className}'`
|
|
67240
|
+
);
|
|
67241
|
+
return makeMember(m.name, m.value);
|
|
67242
|
+
};
|
|
67243
|
+
const fromNumber = (num) => {
|
|
67244
|
+
const m = members.find(
|
|
67245
|
+
(mm) => mm.value !== void 0 && toNumber(mm.value) === num
|
|
67246
|
+
);
|
|
67247
|
+
if (!m)
|
|
67248
|
+
throw new RuntimeError(
|
|
67249
|
+
`${num} is not a valid underlying value for enumeration '${className}'`
|
|
67250
|
+
);
|
|
67251
|
+
return makeMember(m.name, m.value);
|
|
67252
|
+
};
|
|
67253
|
+
if (isRuntimeChar(val)) return fromName(val.value);
|
|
67254
|
+
if (isRuntimeString(val)) return fromName(val);
|
|
67255
|
+
if (isRuntimeNumber(val)) return fromNumber(val);
|
|
67256
|
+
if (isRuntimeLogical(val)) return fromNumber(val ? 1 : 0);
|
|
67257
|
+
if (isRuntimeTensor(val)) {
|
|
67258
|
+
const elems = Array.from(val.data, (x) => fromNumber(x));
|
|
67259
|
+
if (elems.length === 1) return elems[0];
|
|
67260
|
+
const shape = [val.shape[0] ?? 0, val.shape[1] ?? 1];
|
|
67261
|
+
return RTV.classInstanceArray(className, elems, shape);
|
|
67262
|
+
}
|
|
67263
|
+
throw new RuntimeError(`Cannot convert value to enumeration '${className}'`);
|
|
67264
|
+
}
|
|
66994
67265
|
function instantiateClass(className, args, nargout) {
|
|
66995
67266
|
const classInfo = this.ctx.getClassInfo(className);
|
|
66996
67267
|
if (!classInfo) {
|
|
66997
67268
|
return this.rt.callClassMethod(className, className, nargout, args);
|
|
66998
67269
|
}
|
|
67270
|
+
if (classInfo.enumMembers && args.length > 0) {
|
|
67271
|
+
return this.convertToEnum(className, classInfo, args);
|
|
67272
|
+
}
|
|
66999
67273
|
if (classInfo.isOldStyle) {
|
|
67000
67274
|
const ctorName = classInfo.constructorName ?? className;
|
|
67001
67275
|
const ctorFn = this.findExternalMethod(classInfo, ctorName);
|
|
@@ -67796,6 +68070,7 @@ function extractClassInfo(classDef, qualifiedName, fileName, source) {
|
|
|
67796
68070
|
const methodNames = /* @__PURE__ */ new Set();
|
|
67797
68071
|
const staticMethodNames = /* @__PURE__ */ new Set();
|
|
67798
68072
|
let constructorName = null;
|
|
68073
|
+
let enumMembers = null;
|
|
67799
68074
|
const dotIdx = qualifiedName.lastIndexOf(".");
|
|
67800
68075
|
const baseName = dotIdx >= 0 ? qualifiedName.slice(dotIdx + 1) : qualifiedName;
|
|
67801
68076
|
for (const member of classDef.members) {
|
|
@@ -67837,6 +68112,8 @@ function extractClassInfo(classDef, qualifiedName, fileName, source) {
|
|
|
67837
68112
|
}
|
|
67838
68113
|
}
|
|
67839
68114
|
}
|
|
68115
|
+
} else if (member.type === "Enumeration") {
|
|
68116
|
+
enumMembers = member.members.map((m) => ({ name: m.name, args: m.args }));
|
|
67840
68117
|
}
|
|
67841
68118
|
}
|
|
67842
68119
|
const inferiorClasses = [];
|
|
@@ -67859,6 +68136,7 @@ function extractClassInfo(classDef, qualifiedName, fileName, source) {
|
|
|
67859
68136
|
methodNames,
|
|
67860
68137
|
staticMethodNames,
|
|
67861
68138
|
constructorName,
|
|
68139
|
+
enumMembers,
|
|
67862
68140
|
inferiorClasses,
|
|
67863
68141
|
ast: classDef,
|
|
67864
68142
|
externalMethodFiles: /* @__PURE__ */ new Map()
|
|
@@ -67889,6 +68167,7 @@ function makeOldStyleClassInfo(qualifiedName, baseName, constructorFile, methodF
|
|
|
67889
68167
|
methodNames,
|
|
67890
68168
|
staticMethodNames: /* @__PURE__ */ new Set(),
|
|
67891
68169
|
constructorName: baseName,
|
|
68170
|
+
enumMembers: null,
|
|
67892
68171
|
inferiorClasses: [],
|
|
67893
68172
|
ast: null,
|
|
67894
68173
|
isOldStyle: true,
|
|
@@ -90375,6 +90654,12 @@ function assertNoNonVoidBareExprStmts(spec) {
|
|
|
90375
90654
|
|
|
90376
90655
|
// src/numbl-core/jit/lowering/classDefs.ts
|
|
90377
90656
|
function registerClassDef(s, file, externalMethods) {
|
|
90657
|
+
if (s.members.some((m) => m.type === "Enumeration")) {
|
|
90658
|
+
throw new UnsupportedConstruct(
|
|
90659
|
+
`classdef '${s.name}' is an enumeration; enumeration classes are interpreter-only in the JIT`,
|
|
90660
|
+
s.span
|
|
90661
|
+
);
|
|
90662
|
+
}
|
|
90378
90663
|
if (s.classAttributes.length > 0) {
|
|
90379
90664
|
throw new UnsupportedConstruct(
|
|
90380
90665
|
`classdef '${s.name}' has class attributes; not supported in v1`,
|
|
@@ -180,6 +180,8 @@ export declare class Interpreter {
|
|
|
180
180
|
}>, args: unknown[], nargout: number) => unknown;
|
|
181
181
|
instantiateClass: (className: string, args: unknown[], nargout: number) => unknown;
|
|
182
182
|
interpretConstructor: (classInfo: ClassInfo, args: unknown[], nargout: number) => unknown;
|
|
183
|
+
interpretEnumMember: (className: string, memberName: string) => RuntimeValue | null;
|
|
184
|
+
convertToEnum: (className: string, classInfo: ClassInfo, args: unknown[]) => RuntimeValue;
|
|
183
185
|
callUserFunction: (fn: FunctionDef, args: unknown[], nargout: number, narginOverride?: number) => unknown;
|
|
184
186
|
callNestedFunction: (fn: FunctionDef, parentEnv: Environment, args: unknown[], nargout: number) => unknown;
|
|
185
187
|
withFileContext: <T>(file: string, className: string | undefined, methodName: string | undefined, fn: () => T) => T;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Augments the Interpreter class via prototype assignment.
|
|
4
4
|
*/
|
|
5
5
|
import type { Expr } from "../parser/types.js";
|
|
6
|
+
import type { RuntimeValue } from "../runtime/types.js";
|
|
6
7
|
import { type ResolvedTarget } from "../functionResolve.js";
|
|
7
8
|
import type { ClassInfo } from "../lowering/classInfo.js";
|
|
8
9
|
import { Environment, type FunctionDef } from "./types.js";
|
|
@@ -30,6 +31,13 @@ export declare function interpretClassMethod(this: Interpreter, target: Extract<
|
|
|
30
31
|
export declare function interpretPrivateFunction(this: Interpreter, target: Extract<ResolvedTarget, {
|
|
31
32
|
kind: "privateFunction";
|
|
32
33
|
}>, args: unknown[], nargout: number): unknown;
|
|
34
|
+
/** Resolve `ClassName.MemberName` to an enumeration-member instance. Returns
|
|
35
|
+
* null when `className` is not an enumeration or has no such member. */
|
|
36
|
+
export declare function interpretEnumMember(this: Interpreter, className: string, memberName: string): RuntimeValue | null;
|
|
37
|
+
/** Enumeration constructor-as-converter: `ClassName(x)` for an enumeration
|
|
38
|
+
* with no explicit constructor. Converts x — a member, a numeric value, a
|
|
39
|
+
* char/string member name, or an array thereof — to member(s). */
|
|
40
|
+
export declare function convertToEnum(this: Interpreter, className: string, classInfo: ClassInfo, args: unknown[]): RuntimeValue;
|
|
33
41
|
export declare function instantiateClass(this: Interpreter, className: string, args: unknown[], nargout: number): unknown;
|
|
34
42
|
export declare function interpretConstructor(this: Interpreter, classInfo: ClassInfo, args: unknown[], nargout: number): unknown;
|
|
35
43
|
export declare function callUserFunction(this: Interpreter, fn: FunctionDef, args: unknown[], nargout: number, narginOverride?: number): unknown;
|
|
@@ -18,6 +18,12 @@ export interface ClassInfo {
|
|
|
18
18
|
methodNames: Set<string>;
|
|
19
19
|
staticMethodNames: Set<string>;
|
|
20
20
|
constructorName: string | null;
|
|
21
|
+
/** Enumeration members in declaration order (name + constructor-arg
|
|
22
|
+
* exprs), or null when the class is not an enumeration. */
|
|
23
|
+
enumMembers: {
|
|
24
|
+
name: string;
|
|
25
|
+
args: Expr[];
|
|
26
|
+
}[] | null;
|
|
21
27
|
ast: (Stmt & {
|
|
22
28
|
type: "ClassDef";
|
|
23
29
|
}) | null;
|
|
@@ -7,6 +7,11 @@ export declare class ClassParser extends FunctionParser {
|
|
|
7
7
|
parseImport(): Stmt;
|
|
8
8
|
parseClassDef(): Stmt;
|
|
9
9
|
private parseNameBlock;
|
|
10
|
+
/** Parse an `enumeration ... end` member list. Each member is a bare
|
|
11
|
+
* identifier optionally followed by a parenthesized argument list
|
|
12
|
+
* (`quad (0)`, `Error (1, 0, 0)`). Members are separated by `;`/`,`/
|
|
13
|
+
* newline. The args are evaluated later (at member construction). */
|
|
14
|
+
private parseEnumerationBlock;
|
|
10
15
|
private parsePropertiesNamesBlock;
|
|
11
16
|
/** Consume a balanced `open ... close` run (handling nesting). Assumes the
|
|
12
17
|
* next token is `open`; no-op otherwise. */
|
|
@@ -194,7 +194,13 @@ export type ClassMember = {
|
|
|
194
194
|
} | {
|
|
195
195
|
type: "Enumeration";
|
|
196
196
|
attributes: Attr[];
|
|
197
|
-
|
|
197
|
+
/** Enumeration members in declaration order. Each has a name and an
|
|
198
|
+
* optional argument list (`quad (0)` → args `[0]`). Args are passed
|
|
199
|
+
* to the constructor / first superclass to build the member value. */
|
|
200
|
+
members: {
|
|
201
|
+
name: string;
|
|
202
|
+
args: Expr[];
|
|
203
|
+
}[];
|
|
198
204
|
} | {
|
|
199
205
|
type: "Arguments";
|
|
200
206
|
attributes: Attr[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enumeration-class value semantics.
|
|
3
|
+
*
|
|
4
|
+
* An enumeration member is represented as a `RuntimeClassInstance` whose
|
|
5
|
+
* `_enumMember` field holds the member name and whose `_builtinData` holds the
|
|
6
|
+
* underlying (superclass) numeric value — e.g. for `classdef patchtype < uint32`
|
|
7
|
+
* the member `tri (1)` is stored with `_enumMember = "tri"`, `_builtinData = 1`.
|
|
8
|
+
*
|
|
9
|
+
* MATLAB comparison rules (verified against R2025b):
|
|
10
|
+
* - enum == enum → compare underlying values (inherited from the numeric
|
|
11
|
+
* superclass); falls back to name equality for plain
|
|
12
|
+
* enumerations that carry no superclass value.
|
|
13
|
+
* - enum == numeric → compare underlying value to the number.
|
|
14
|
+
* - enum == char/str → compare the member NAME to the text (a non-matching
|
|
15
|
+
* name yields false, never an error), NOT an
|
|
16
|
+
* element-wise char-code comparison.
|
|
17
|
+
* Comparisons are element-wise with scalar broadcasting; arrays of members
|
|
18
|
+
* produce a logical array the size of the member array.
|
|
19
|
+
*/
|
|
20
|
+
import { type RuntimeValue, type RuntimeClassInstance } from "./types.js";
|
|
21
|
+
/** True if `v` is a single enumeration-member instance. */
|
|
22
|
+
export declare function isEnumInstance(v: RuntimeValue): v is RuntimeClassInstance;
|
|
23
|
+
/** True if `v` is an enumeration member or an array of enumeration members. */
|
|
24
|
+
export declare function isEnumValue(v: RuntimeValue): boolean;
|
|
25
|
+
/** Compare one enumeration member `e` against a scalar operand `other`
|
|
26
|
+
* (another member, a number, or char/string text). */
|
|
27
|
+
export declare function enumScalarEquals(e: RuntimeClassInstance, other: RuntimeValue): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Element-wise `==` / `~=` for enumeration operands. Returns a logical result
|
|
30
|
+
* (a boolean for scalars, a logical tensor for arrays), or null if the op is
|
|
31
|
+
* not equality/inequality or neither operand is an enumeration value.
|
|
32
|
+
*/
|
|
33
|
+
export declare function enumEqualityOp(op: string, a: RuntimeValue, b: RuntimeValue): RuntimeValue | null;
|
|
@@ -123,7 +123,11 @@ export declare class RuntimeClassInstance extends Refcounted {
|
|
|
123
123
|
/** For classes that inherit from built-in types (e.g. classdef Foo < double),
|
|
124
124
|
* stores the underlying built-in data. */
|
|
125
125
|
_builtinData: RuntimeValue | undefined;
|
|
126
|
-
|
|
126
|
+
/** For enumeration-class members: the member name (e.g. "tri"). When set,
|
|
127
|
+
* this instance is an enumeration member and `_builtinData` holds its
|
|
128
|
+
* underlying (superclass) value. Drives ==/~=, switch, and char coercion. */
|
|
129
|
+
_enumMember: string | undefined;
|
|
130
|
+
constructor(className: string, fields: Map<string, RuntimeValue>, isHandleClass: boolean, _builtinData?: RuntimeValue, _enumMember?: string);
|
|
127
131
|
/** Set/replace a field value (handle-class in-place mutation), with
|
|
128
132
|
* proper decref-old / incref-new bookkeeping. Used for handle-class
|
|
129
133
|
* field assigns; value-class field assigns construct a new instance. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Numbl version, used for JIT disk cache invalidation. */
|
|
2
|
-
export declare const NUMBL_VERSION = "0.4.
|
|
2
|
+
export declare const NUMBL_VERSION = "0.4.11";
|