numbl 0.1.4 → 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 CHANGED
@@ -38178,6 +38178,150 @@ registerIBuiltin({
38178
38178
  };
38179
38179
  }
38180
38180
  });
38181
+ var RE_ALPHA = /\p{L}/u;
38182
+ var RE_ALPHANUM = /[\p{L}\p{N}]/u;
38183
+ var RE_CNTRL = /\p{Cc}/u;
38184
+ var RE_GRAPHIC = /[\p{L}\p{N}\p{P}\p{S}\p{M}]/u;
38185
+ var RE_LOWER = /\p{Ll}/u;
38186
+ var RE_PUNCT = /\p{P}/u;
38187
+ var RE_UPPER = /\p{Lu}/u;
38188
+ var RE_WSPACE = /\s/u;
38189
+ function isstrpropPredicate(category) {
38190
+ switch (category) {
38191
+ case "alpha":
38192
+ return (cp) => RE_ALPHA.test(String.fromCodePoint(cp));
38193
+ case "alphanum":
38194
+ return (cp) => RE_ALPHANUM.test(String.fromCodePoint(cp));
38195
+ case "cntrl":
38196
+ return (cp) => RE_CNTRL.test(String.fromCodePoint(cp));
38197
+ case "digit":
38198
+ return (cp) => cp >= 48 && cp <= 57;
38199
+ case "graphic":
38200
+ return (cp) => RE_GRAPHIC.test(String.fromCodePoint(cp));
38201
+ case "lower":
38202
+ return (cp) => RE_LOWER.test(String.fromCodePoint(cp));
38203
+ case "print":
38204
+ return (cp) => cp === 32 || RE_GRAPHIC.test(String.fromCodePoint(cp));
38205
+ case "punct":
38206
+ return (cp) => RE_PUNCT.test(String.fromCodePoint(cp));
38207
+ case "wspace":
38208
+ return (cp) => RE_WSPACE.test(String.fromCodePoint(cp));
38209
+ case "upper":
38210
+ return (cp) => RE_UPPER.test(String.fromCodePoint(cp));
38211
+ case "xdigit":
38212
+ return (cp) => cp >= 48 && cp <= 57 || cp >= 65 && cp <= 70 || cp >= 97 && cp <= 102;
38213
+ default:
38214
+ return null;
38215
+ }
38216
+ }
38217
+ function stringCodePoints(s) {
38218
+ const out = [];
38219
+ for (const ch of s) out.push(ch.codePointAt(0));
38220
+ return out;
38221
+ }
38222
+ function logicalRowFromString(s, pred, shape) {
38223
+ const cps = stringCodePoints(s);
38224
+ const data = new FloatXArray(cps.length);
38225
+ for (let i = 0; i < cps.length; i++) data[i] = pred(cps[i]) ? 1 : 0;
38226
+ return {
38227
+ kind: "tensor",
38228
+ data,
38229
+ shape: shape ?? [1, cps.length],
38230
+ _isLogical: true,
38231
+ _rc: 1
38232
+ };
38233
+ }
38234
+ function logicalFromNumericTensor(data, shape, pred) {
38235
+ const out = new FloatXArray(data.length);
38236
+ for (let i = 0; i < data.length; i++) {
38237
+ out[i] = pred(Math.round(data[i])) ? 1 : 0;
38238
+ }
38239
+ return {
38240
+ kind: "tensor",
38241
+ data: out,
38242
+ shape: [...shape],
38243
+ _isLogical: true,
38244
+ _rc: 1
38245
+ };
38246
+ }
38247
+ function isstrpropApply(args) {
38248
+ const v = args[0];
38249
+ const category = toString(args[1]);
38250
+ const pred = isstrpropPredicate(category);
38251
+ if (!pred) {
38252
+ throw new RuntimeError(`isstrprop: unknown category '${category}'`);
38253
+ }
38254
+ let forceCell = false;
38255
+ if (args.length >= 3) {
38256
+ const flagName = toString(args[2]).toLowerCase();
38257
+ if (flagName !== "forcecelloutput") {
38258
+ throw new RuntimeError(`isstrprop: unknown name '${toString(args[2])}'`);
38259
+ }
38260
+ if (args.length < 4) {
38261
+ throw new RuntimeError("isstrprop: 'ForceCellOutput' requires a value");
38262
+ }
38263
+ forceCell = toNumber(args[3]) !== 0;
38264
+ }
38265
+ if (isRuntimeCell(v)) {
38266
+ const out = new Array(v.data.length);
38267
+ for (let i = 0; i < v.data.length; i++) {
38268
+ const elem = v.data[i];
38269
+ const s = isText(elem) ? toString(elem) : "";
38270
+ out[i] = logicalRowFromString(s, pred);
38271
+ }
38272
+ return RTV.cell(out, [...v.shape]);
38273
+ }
38274
+ let result;
38275
+ if (isRuntimeString(v)) {
38276
+ result = logicalRowFromString(toString(v), pred);
38277
+ } else if (isRuntimeChar(v)) {
38278
+ const c = v;
38279
+ result = logicalRowFromString(
38280
+ c.value,
38281
+ pred,
38282
+ c.shape ? [...c.shape] : void 0
38283
+ );
38284
+ } else if (isRuntimeTensor(v)) {
38285
+ result = logicalFromNumericTensor(v.data, v.shape, pred);
38286
+ } else if (isRuntimeNumber(v) || isRuntimeLogical(v)) {
38287
+ const cp = Math.round(toNumber(v));
38288
+ const data = new FloatXArray(1);
38289
+ data[0] = pred(cp) ? 1 : 0;
38290
+ result = { kind: "tensor", data, shape: [1, 1], _isLogical: true, _rc: 1 };
38291
+ } else {
38292
+ throw new RuntimeError("isstrprop: unsupported input type");
38293
+ }
38294
+ if (forceCell) return RTV.cell([result], [1, 1]);
38295
+ return result;
38296
+ }
38297
+ registerIBuiltin({
38298
+ name: "isstrprop",
38299
+ help: {
38300
+ signatures: [
38301
+ "TF = isstrprop(str, category)",
38302
+ "TF = isstrprop(str, category, 'ForceCellOutput', tf)"
38303
+ ],
38304
+ 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."
38305
+ },
38306
+ resolve: (argTypes) => {
38307
+ if (argTypes.length < 2 || argTypes.length > 4) return null;
38308
+ if (!isTextType(argTypes[1])) return null;
38309
+ if (argTypes.length >= 3 && !isTextType(argTypes[2])) return null;
38310
+ if (argTypes.length === 4) {
38311
+ const k = argTypes[3].kind;
38312
+ if (k !== "number" && k !== "boolean") return null;
38313
+ }
38314
+ const t0 = argTypes[0];
38315
+ if (t0.kind !== "char" && t0.kind !== "string" && t0.kind !== "number" && t0.kind !== "boolean" && t0.kind !== "tensor" && t0.kind !== "cell") {
38316
+ return null;
38317
+ }
38318
+ const isCell = t0.kind === "cell";
38319
+ return {
38320
+ outputTypes: isCell ? [{ kind: "cell" }] : [{ kind: "tensor", isComplex: false, isLogical: true }],
38321
+ apply: (args) => isstrpropApply(args)
38322
+ };
38323
+ }
38324
+ });
38181
38325
  registerIBuiltin({
38182
38326
  name: "contains",
38183
38327
  resolve: (argTypes) => {
@@ -48439,6 +48583,15 @@ var H = {
48439
48583
  signatures: ["TF = isequal(A, B, ...)"],
48440
48584
  description: "True if all inputs are equal (NaN ~= NaN)."
48441
48585
  },
48586
+ // ── Dynamic evaluation ────────────────────────────────────────────────
48587
+ evalin: {
48588
+ signatures: ["V = evalin(WS, EXPR)", "V = evalin(WS, EXPR, DEFAULT)"],
48589
+ 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."
48590
+ },
48591
+ assignin: {
48592
+ signatures: ["assignin(WS, NAME, VALUE)"],
48593
+ 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."
48594
+ },
48442
48595
  // ── Misc ──────────────────────────────────────────────────────────────
48443
48596
  disp: {
48444
48597
  signatures: ["disp(X)"],
@@ -49336,7 +49489,7 @@ function getSourceLine(getSource, file, line) {
49336
49489
  }
49337
49490
 
49338
49491
  // src/numbl-core/version.ts
49339
- var NUMBL_VERSION = "0.1.4";
49492
+ var NUMBL_VERSION = "0.1.5";
49340
49493
 
49341
49494
  // src/cli-repl.ts
49342
49495
  import { createInterface } from "readline";
package/dist-lib/lib.js CHANGED
@@ -30057,6 +30057,150 @@ registerIBuiltin({
30057
30057
  };
30058
30058
  }
30059
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
+ });
30060
30204
  registerIBuiltin({
30061
30205
  name: "contains",
30062
30206
  resolve: (argTypes) => {
@@ -41490,6 +41634,15 @@ var H = {
41490
41634
  signatures: ["TF = isequal(A, B, ...)"],
41491
41635
  description: "True if all inputs are equal (NaN ~= NaN)."
41492
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
+ },
41493
41646
  // ── Misc ──────────────────────────────────────────────────────────────
41494
41647
  disp: {
41495
41648
  signatures: ["disp(X)"],
@@ -1,2 +1,2 @@
1
1
  /** Numbl version, used for JIT disk cache invalidation. */
2
- export declare const NUMBL_VERSION = "0.1.4";
2
+ export declare const NUMBL_VERSION = "0.1.5";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numbl",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Run .m source files in the browser and on the command line by compiling to JavaScript",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",