numbl 0.0.13 → 0.0.15
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/README.md +5 -1
- package/dist-cli/cli.js +403 -27
- package/dist-plot-viewer/assets/index-CshiSTKK.js +4426 -0
- package/dist-plot-viewer/index.html +1 -1
- package/package.json +12 -4
- package/dist-plot-viewer/assets/index-T0rky3bg.js +0 -4426
package/README.md
CHANGED
|
@@ -8,6 +8,10 @@ Numbl is an open-source numerical computing environment that aims to be compatib
|
|
|
8
8
|
|
|
9
9
|
You can try numbl directly in the browser at <https://numbl.org> — no installation required. All execution happens locally in your browser. Note that the browser version has limited functionality and is slower than the desktop/command-line version.
|
|
10
10
|
|
|
11
|
+
## Embedding in web pages
|
|
12
|
+
|
|
13
|
+
Numbl scripts can be embedded in HTML and Markdown pages (including GitHub Pages). See the [numbl-embed-example](https://magland.github.io/numbl-embed-example/) for usage info and a [live demo](https://magland.github.io/numbl-embed-example/example1).
|
|
14
|
+
|
|
11
15
|
## Installation
|
|
12
16
|
|
|
13
17
|
```bash
|
|
@@ -50,4 +54,4 @@ Apache 2.0.
|
|
|
50
54
|
|
|
51
55
|
## Acknowledgements
|
|
52
56
|
|
|
53
|
-
See [
|
|
57
|
+
See [acknowledgements.md](docs/acknowledgements.md).
|
package/dist-cli/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
writeFileSync as writeFileSync3,
|
|
10
10
|
appendFileSync as appendFileSync2
|
|
11
11
|
} from "fs";
|
|
12
|
-
import { delimiter, dirname as dirname3, join as
|
|
12
|
+
import { delimiter, dirname as dirname3, join as join6, relative, resolve } from "path";
|
|
13
13
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
14
14
|
import { createRequire } from "module";
|
|
15
15
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -21437,7 +21437,11 @@ var ExpressionParser = class extends ParserBase {
|
|
|
21437
21437
|
const nameSpan = this.spanFrom(nameToken.position, nameToken.end);
|
|
21438
21438
|
this.pos++;
|
|
21439
21439
|
this.pos++;
|
|
21440
|
-
args.push({
|
|
21440
|
+
args.push({
|
|
21441
|
+
type: "Char",
|
|
21442
|
+
value: `'${nameToken.lexeme}'`,
|
|
21443
|
+
span: nameSpan
|
|
21444
|
+
});
|
|
21441
21445
|
args.push(this.parseExpr());
|
|
21442
21446
|
} else {
|
|
21443
21447
|
args.push(this.parseExpr());
|
|
@@ -25093,6 +25097,125 @@ function registerMathFunctions() {
|
|
|
25093
25097
|
return buildResult(snArr, cnArr, dnArr, uT.shape);
|
|
25094
25098
|
})
|
|
25095
25099
|
);
|
|
25100
|
+
register(
|
|
25101
|
+
"legendre",
|
|
25102
|
+
builtinSingle((args) => {
|
|
25103
|
+
if (args.length < 2 || args.length > 3) {
|
|
25104
|
+
throw new RuntimeError("legendre requires 2 or 3 arguments");
|
|
25105
|
+
}
|
|
25106
|
+
const n = Math.round(toNumber(args[0]));
|
|
25107
|
+
if (n < 0 || !isFinite(n)) {
|
|
25108
|
+
throw new RuntimeError("Degree n must be a non-negative integer");
|
|
25109
|
+
}
|
|
25110
|
+
let normalization = "unnorm";
|
|
25111
|
+
if (args.length === 3) {
|
|
25112
|
+
const normArg = args[2];
|
|
25113
|
+
if (isRuntimeChar(normArg)) {
|
|
25114
|
+
normalization = normArg.value;
|
|
25115
|
+
} else if (typeof normArg === "string") {
|
|
25116
|
+
normalization = normArg;
|
|
25117
|
+
} else {
|
|
25118
|
+
throw new RuntimeError(
|
|
25119
|
+
"Third argument must be a normalization string"
|
|
25120
|
+
);
|
|
25121
|
+
}
|
|
25122
|
+
if (normalization !== "unnorm" && normalization !== "sch" && normalization !== "norm") {
|
|
25123
|
+
throw new RuntimeError(
|
|
25124
|
+
"Normalization must be 'unnorm', 'sch', or 'norm'"
|
|
25125
|
+
);
|
|
25126
|
+
}
|
|
25127
|
+
}
|
|
25128
|
+
const xArg = args[1];
|
|
25129
|
+
let xValues;
|
|
25130
|
+
let xShape;
|
|
25131
|
+
if (isRuntimeNumber(xArg)) {
|
|
25132
|
+
xValues = [xArg];
|
|
25133
|
+
xShape = [1, 1];
|
|
25134
|
+
} else if (isRuntimeLogical(xArg)) {
|
|
25135
|
+
xValues = [xArg ? 1 : 0];
|
|
25136
|
+
xShape = [1, 1];
|
|
25137
|
+
} else if (isRuntimeTensor(xArg)) {
|
|
25138
|
+
const t = xArg;
|
|
25139
|
+
xValues = Array.from(t.data);
|
|
25140
|
+
xShape = t.shape;
|
|
25141
|
+
} else {
|
|
25142
|
+
throw new RuntimeError("X must be a numeric value");
|
|
25143
|
+
}
|
|
25144
|
+
const numX = xValues.length;
|
|
25145
|
+
const numOrders = n + 1;
|
|
25146
|
+
const outSize = numOrders * numX;
|
|
25147
|
+
const result = new FloatXArray(outSize);
|
|
25148
|
+
for (let xi = 0; xi < numX; xi++) {
|
|
25149
|
+
const x = xValues[xi];
|
|
25150
|
+
const pmn = legendreAllOrders(n, x);
|
|
25151
|
+
for (let m = 0; m <= n; m++) {
|
|
25152
|
+
let val = pmn[m];
|
|
25153
|
+
if (normalization === "sch") {
|
|
25154
|
+
if (m > 0) {
|
|
25155
|
+
const scale = Math.pow(-1, m) * Math.sqrt(2 * factorialVal(n - m) / factorialVal(n + m));
|
|
25156
|
+
val = scale * val;
|
|
25157
|
+
}
|
|
25158
|
+
} else if (normalization === "norm") {
|
|
25159
|
+
const scale = Math.pow(-1, m) * Math.sqrt(
|
|
25160
|
+
(n + 0.5) * factorialVal(n - m) / factorialVal(n + m)
|
|
25161
|
+
);
|
|
25162
|
+
val = scale * val;
|
|
25163
|
+
}
|
|
25164
|
+
result[xi * numOrders + m] = val;
|
|
25165
|
+
}
|
|
25166
|
+
}
|
|
25167
|
+
if (isRuntimeNumber(xArg) || isRuntimeLogical(xArg)) {
|
|
25168
|
+
return RTV.tensor(result, [numOrders, 1]);
|
|
25169
|
+
}
|
|
25170
|
+
if (xShape.length === 2 && (xShape[0] === 1 || xShape[1] === 1)) {
|
|
25171
|
+
return RTV.tensor(result, [numOrders, numX]);
|
|
25172
|
+
}
|
|
25173
|
+
return RTV.tensor(result, [numOrders, ...xShape]);
|
|
25174
|
+
})
|
|
25175
|
+
);
|
|
25176
|
+
}
|
|
25177
|
+
function factorialVal(n) {
|
|
25178
|
+
if (n <= 1) return 1;
|
|
25179
|
+
let r = 1;
|
|
25180
|
+
for (let i = 2; i <= n; i++) r *= i;
|
|
25181
|
+
return r;
|
|
25182
|
+
}
|
|
25183
|
+
function legendreAllOrders(n, x) {
|
|
25184
|
+
const result = new Array(n + 1);
|
|
25185
|
+
if (n === 0) {
|
|
25186
|
+
result[0] = 1;
|
|
25187
|
+
return result;
|
|
25188
|
+
}
|
|
25189
|
+
const sqrtFactor = Math.sqrt(1 - x * x);
|
|
25190
|
+
for (let m = 0; m <= n; m++) {
|
|
25191
|
+
let pmm = 1;
|
|
25192
|
+
if (m > 0) {
|
|
25193
|
+
let dblFact = 1;
|
|
25194
|
+
for (let i = 1; i <= m; i++) {
|
|
25195
|
+
dblFact *= 2 * i - 1;
|
|
25196
|
+
}
|
|
25197
|
+
pmm = Math.pow(-1, m) * dblFact * Math.pow(sqrtFactor, m);
|
|
25198
|
+
}
|
|
25199
|
+
if (m === n) {
|
|
25200
|
+
result[m] = pmm;
|
|
25201
|
+
continue;
|
|
25202
|
+
}
|
|
25203
|
+
const pmm1 = x * (2 * m + 1) * pmm;
|
|
25204
|
+
if (m + 1 === n) {
|
|
25205
|
+
result[m] = pmm1;
|
|
25206
|
+
continue;
|
|
25207
|
+
}
|
|
25208
|
+
let pPrev2 = pmm;
|
|
25209
|
+
let pPrev1 = pmm1;
|
|
25210
|
+
let pCurr = 0;
|
|
25211
|
+
for (let l = m + 2; l <= n; l++) {
|
|
25212
|
+
pCurr = (x * (2 * l - 1) * pPrev1 - (l + m - 1) * pPrev2) / (l - m);
|
|
25213
|
+
pPrev2 = pPrev1;
|
|
25214
|
+
pPrev1 = pCurr;
|
|
25215
|
+
}
|
|
25216
|
+
result[m] = pCurr;
|
|
25217
|
+
}
|
|
25218
|
+
return result;
|
|
25096
25219
|
}
|
|
25097
25220
|
|
|
25098
25221
|
// src/numbl-core/builtins/shape-utils.ts
|
|
@@ -34118,6 +34241,22 @@ function registerGraphicsFunctions() {
|
|
|
34118
34241
|
"close",
|
|
34119
34242
|
builtinSingle(() => RTV.num(0))
|
|
34120
34243
|
);
|
|
34244
|
+
register(
|
|
34245
|
+
"title",
|
|
34246
|
+
builtinSingle(() => RTV.num(0))
|
|
34247
|
+
);
|
|
34248
|
+
register(
|
|
34249
|
+
"xlabel",
|
|
34250
|
+
builtinSingle(() => RTV.num(0))
|
|
34251
|
+
);
|
|
34252
|
+
register(
|
|
34253
|
+
"ylabel",
|
|
34254
|
+
builtinSingle(() => RTV.num(0))
|
|
34255
|
+
);
|
|
34256
|
+
register(
|
|
34257
|
+
"shading",
|
|
34258
|
+
builtinSingle(() => RTV.num(0))
|
|
34259
|
+
);
|
|
34121
34260
|
register(
|
|
34122
34261
|
"drawnow",
|
|
34123
34262
|
builtinSingle(() => RTV.num(0))
|
|
@@ -38191,6 +38330,19 @@ function plotInstr(plotInstructions, instr) {
|
|
|
38191
38330
|
on = toString(mv) === "on";
|
|
38192
38331
|
}
|
|
38193
38332
|
plotInstructions.push({ type: "set_hold", value: on });
|
|
38333
|
+
} else if (instr.type === "set_title") {
|
|
38334
|
+
const text = typeof instr.text === "string" ? instr.text : toString(ensureRuntimeValue(instr.text));
|
|
38335
|
+
plotInstructions.push({ type: "set_title", text });
|
|
38336
|
+
} else if (instr.type === "set_xlabel") {
|
|
38337
|
+
const text = typeof instr.text === "string" ? instr.text : toString(ensureRuntimeValue(instr.text));
|
|
38338
|
+
plotInstructions.push({ type: "set_xlabel", text });
|
|
38339
|
+
} else if (instr.type === "set_ylabel") {
|
|
38340
|
+
const text = typeof instr.text === "string" ? instr.text : toString(ensureRuntimeValue(instr.text));
|
|
38341
|
+
plotInstructions.push({ type: "set_ylabel", text });
|
|
38342
|
+
} else if (instr.type === "set_shading") {
|
|
38343
|
+
const raw = typeof instr.shading === "string" ? instr.shading : toString(ensureRuntimeValue(instr.shading));
|
|
38344
|
+
const shading = raw.replace(/^'|'$/g, "");
|
|
38345
|
+
plotInstructions.push({ type: "set_shading", shading });
|
|
38194
38346
|
} else if (instr.type === "close") {
|
|
38195
38347
|
plotInstructions.push({ type: "close" });
|
|
38196
38348
|
} else if (instr.type === "close_all") {
|
|
@@ -39147,6 +39299,61 @@ function getEffectiveDir(fileName, searchPaths) {
|
|
|
39147
39299
|
}
|
|
39148
39300
|
return parts.length > 0 ? parts.join("/") + "/" : "";
|
|
39149
39301
|
}
|
|
39302
|
+
function resolveViaImports(name, argTypes, callSite, index2, wildcardOnly) {
|
|
39303
|
+
const imports = index2.fileImports.get(callSite.file);
|
|
39304
|
+
if (!imports) return null;
|
|
39305
|
+
for (const imp of imports) {
|
|
39306
|
+
if (imp.wildcard !== wildcardOnly) continue;
|
|
39307
|
+
if (imp.wildcard) {
|
|
39308
|
+
const candidateName = `${imp.namespace}.${name}`;
|
|
39309
|
+
if (index2.workspaceFunctions.has(candidateName)) {
|
|
39310
|
+
return { kind: "workspaceFunction", name: candidateName, argTypes };
|
|
39311
|
+
}
|
|
39312
|
+
if (index2.workspaceClasses.has(candidateName)) {
|
|
39313
|
+
return {
|
|
39314
|
+
kind: "workspaceClassConstructor",
|
|
39315
|
+
className: candidateName,
|
|
39316
|
+
argTypes
|
|
39317
|
+
};
|
|
39318
|
+
}
|
|
39319
|
+
if (index2.classStaticMethods.get(imp.namespace)?.has(name)) {
|
|
39320
|
+
return {
|
|
39321
|
+
kind: "classMethod",
|
|
39322
|
+
className: imp.namespace,
|
|
39323
|
+
methodName: name,
|
|
39324
|
+
compileArgTypes: argTypes,
|
|
39325
|
+
stripInstance: false
|
|
39326
|
+
};
|
|
39327
|
+
}
|
|
39328
|
+
} else {
|
|
39329
|
+
if (name !== imp.shortName) continue;
|
|
39330
|
+
if (imp.staticMethod) {
|
|
39331
|
+
return {
|
|
39332
|
+
kind: "classMethod",
|
|
39333
|
+
className: imp.staticMethod.className,
|
|
39334
|
+
methodName: imp.staticMethod.methodName,
|
|
39335
|
+
compileArgTypes: argTypes,
|
|
39336
|
+
stripInstance: false
|
|
39337
|
+
};
|
|
39338
|
+
}
|
|
39339
|
+
if (index2.workspaceFunctions.has(imp.qualifiedName)) {
|
|
39340
|
+
return {
|
|
39341
|
+
kind: "workspaceFunction",
|
|
39342
|
+
name: imp.qualifiedName,
|
|
39343
|
+
argTypes
|
|
39344
|
+
};
|
|
39345
|
+
}
|
|
39346
|
+
if (index2.workspaceClasses.has(imp.qualifiedName)) {
|
|
39347
|
+
return {
|
|
39348
|
+
kind: "workspaceClassConstructor",
|
|
39349
|
+
className: imp.qualifiedName,
|
|
39350
|
+
argTypes
|
|
39351
|
+
};
|
|
39352
|
+
}
|
|
39353
|
+
}
|
|
39354
|
+
}
|
|
39355
|
+
return null;
|
|
39356
|
+
}
|
|
39150
39357
|
function resolveFunction(name, argTypes, callSite, index2) {
|
|
39151
39358
|
if (callSite.targetClassName) {
|
|
39152
39359
|
const className = callSite.targetClassName;
|
|
@@ -39161,6 +39368,10 @@ function resolveFunction(name, argTypes, callSite, index2) {
|
|
|
39161
39368
|
stripInstance
|
|
39162
39369
|
};
|
|
39163
39370
|
}
|
|
39371
|
+
{
|
|
39372
|
+
const imported = resolveViaImports(name, argTypes, callSite, index2, false);
|
|
39373
|
+
if (imported) return imported;
|
|
39374
|
+
}
|
|
39164
39375
|
if (callSite.className) {
|
|
39165
39376
|
const className = callSite.className;
|
|
39166
39377
|
const isClassMethod = index2.classInstanceMethods.get(className)?.has(name) || index2.classConstructors.get(className) === name || index2.classStaticMethods.get(className)?.has(name);
|
|
@@ -39209,6 +39420,10 @@ function resolveFunction(name, argTypes, callSite, index2) {
|
|
|
39209
39420
|
}
|
|
39210
39421
|
}
|
|
39211
39422
|
}
|
|
39423
|
+
{
|
|
39424
|
+
const imported = resolveViaImports(name, argTypes, callSite, index2, true);
|
|
39425
|
+
if (imported) return imported;
|
|
39426
|
+
}
|
|
39212
39427
|
if (callSite.file) {
|
|
39213
39428
|
const dir = getEffectiveDir(callSite.file, index2.searchPaths);
|
|
39214
39429
|
if (index2.privateFunctions.get(dir)?.has(name)) {
|
|
@@ -39263,6 +39478,9 @@ function resolveFunction(name, argTypes, callSite, index2) {
|
|
|
39263
39478
|
argTypes
|
|
39264
39479
|
};
|
|
39265
39480
|
}
|
|
39481
|
+
if (index2.jsUserFunctions.has(name)) {
|
|
39482
|
+
return { kind: "builtin", name };
|
|
39483
|
+
}
|
|
39266
39484
|
if (index2.workspaceClasses.has(name)) {
|
|
39267
39485
|
return {
|
|
39268
39486
|
kind: "workspaceClassConstructor",
|
|
@@ -39328,12 +39546,17 @@ function resolveFuncCall(ctx, name, args, nargout, span) {
|
|
|
39328
39546
|
{ type: "userFunction", functionId: `private:${name}` }
|
|
39329
39547
|
]);
|
|
39330
39548
|
case "workspaceFunction":
|
|
39331
|
-
return makeFuncCallExpr(ctx, name, args, nargout, span, [
|
|
39332
|
-
{ type: "userFunction", functionId: name }
|
|
39549
|
+
return makeFuncCallExpr(ctx, target.name, args, nargout, span, [
|
|
39550
|
+
{ type: "userFunction", functionId: target.name }
|
|
39333
39551
|
]);
|
|
39334
39552
|
case "workspaceClassConstructor":
|
|
39335
39553
|
return {
|
|
39336
|
-
kind: {
|
|
39554
|
+
kind: {
|
|
39555
|
+
type: "ClassInstantiation",
|
|
39556
|
+
className: target.className,
|
|
39557
|
+
args,
|
|
39558
|
+
nargout
|
|
39559
|
+
},
|
|
39337
39560
|
span
|
|
39338
39561
|
};
|
|
39339
39562
|
case "builtin":
|
|
@@ -40720,8 +40943,17 @@ var LoweringContext = class _LoweringContext {
|
|
|
40720
40943
|
* Should be called once after registerWorkspaceFiles() and registerLocalFunctionAST().
|
|
40721
40944
|
* Parses all workspace files eagerly to discover subfunctions.
|
|
40722
40945
|
*/
|
|
40723
|
-
buildFunctionIndex() {
|
|
40946
|
+
buildFunctionIndex(jsUserFunctionNames) {
|
|
40724
40947
|
const builtins2 = new Set(getAllBuiltinNames());
|
|
40948
|
+
const jsUserFunctions = /* @__PURE__ */ new Set();
|
|
40949
|
+
if (jsUserFunctionNames) {
|
|
40950
|
+
for (const name of jsUserFunctionNames) {
|
|
40951
|
+
if (builtins2.has(name)) {
|
|
40952
|
+
builtins2.delete(name);
|
|
40953
|
+
jsUserFunctions.add(name);
|
|
40954
|
+
}
|
|
40955
|
+
}
|
|
40956
|
+
}
|
|
40725
40957
|
const mainLocalFunctions = new Set(this.localFunctionASTs.keys());
|
|
40726
40958
|
const workspaceFunctions = new Set(this.registry.filesByFuncName.keys());
|
|
40727
40959
|
const workspaceClasses = /* @__PURE__ */ new Set([
|
|
@@ -40832,11 +41064,55 @@ var LoweringContext = class _LoweringContext {
|
|
|
40832
41064
|
classInferiorClasses.set(className, new Set(info.inferiorClasses));
|
|
40833
41065
|
}
|
|
40834
41066
|
}
|
|
41067
|
+
const fileImports = /* @__PURE__ */ new Map();
|
|
41068
|
+
const collectImportsFromBody = (body, fileName) => {
|
|
41069
|
+
const entries = [];
|
|
41070
|
+
for (const stmt of body) {
|
|
41071
|
+
if (stmt.type !== "Import") continue;
|
|
41072
|
+
if (stmt.wildcard) {
|
|
41073
|
+
entries.push({ wildcard: true, namespace: stmt.path.join(".") });
|
|
41074
|
+
} else {
|
|
41075
|
+
const qualifiedName = stmt.path.join(".");
|
|
41076
|
+
const shortName = stmt.path[stmt.path.length - 1];
|
|
41077
|
+
const prefix = stmt.path.slice(0, -1).join(".");
|
|
41078
|
+
const isStaticMethod = prefix.length > 0 && classStaticMethods.get(prefix)?.has(shortName);
|
|
41079
|
+
entries.push({
|
|
41080
|
+
wildcard: false,
|
|
41081
|
+
qualifiedName,
|
|
41082
|
+
shortName,
|
|
41083
|
+
...isStaticMethod ? { staticMethod: { className: prefix, methodName: shortName } } : {}
|
|
41084
|
+
});
|
|
41085
|
+
}
|
|
41086
|
+
}
|
|
41087
|
+
if (entries.length > 0) {
|
|
41088
|
+
fileImports.set(fileName, entries);
|
|
41089
|
+
}
|
|
41090
|
+
};
|
|
41091
|
+
try {
|
|
41092
|
+
const mainAst = this.getCachedAST(this.mainFileName);
|
|
41093
|
+
collectImportsFromBody(mainAst.body, this.mainFileName);
|
|
41094
|
+
} catch {
|
|
41095
|
+
}
|
|
41096
|
+
for (const [, entry] of this.registry.filesByFuncName) {
|
|
41097
|
+
const ast = this.getCachedAST(entry.fileName);
|
|
41098
|
+
collectImportsFromBody(ast.body, entry.fileName);
|
|
41099
|
+
}
|
|
41100
|
+
for (const [, info] of this.registry.classesByName) {
|
|
41101
|
+
const ast = this.getCachedAST(info.fileName);
|
|
41102
|
+
collectImportsFromBody(ast.body, info.fileName);
|
|
41103
|
+
}
|
|
41104
|
+
for (const [, entries] of this.registry.privateFilesByDir) {
|
|
41105
|
+
for (const [, entry] of entries) {
|
|
41106
|
+
const ast = this.getCachedAST(entry.fileName);
|
|
41107
|
+
collectImportsFromBody(ast.body, entry.fileName);
|
|
41108
|
+
}
|
|
41109
|
+
}
|
|
40835
41110
|
const index2 = {
|
|
40836
41111
|
builtins: builtins2,
|
|
40837
41112
|
mainFileName: this.mainFileName,
|
|
40838
41113
|
mainLocalFunctions,
|
|
40839
41114
|
workspaceFunctions,
|
|
41115
|
+
jsUserFunctions,
|
|
40840
41116
|
workspaceClasses,
|
|
40841
41117
|
workspaceFileSubfunctions,
|
|
40842
41118
|
classFileSubfunctions,
|
|
@@ -40847,7 +41123,8 @@ var LoweringContext = class _LoweringContext {
|
|
|
40847
41123
|
privateFileSubfunctions,
|
|
40848
41124
|
classInferiorClasses,
|
|
40849
41125
|
searchPaths: this.registry.searchPaths,
|
|
40850
|
-
fileToFuncName: this.registry.fileToFuncName
|
|
41126
|
+
fileToFuncName: this.registry.fileToFuncName,
|
|
41127
|
+
fileImports
|
|
40851
41128
|
};
|
|
40852
41129
|
this.registry.functionIndex = index2;
|
|
40853
41130
|
return index2;
|
|
@@ -41604,6 +41881,14 @@ function genFuncCall(cg, kind) {
|
|
|
41604
41881
|
return `$rt.plot_instr({type: "set_hold", value: ${args[0]}})`;
|
|
41605
41882
|
if (kind.name === "ishold") return `$rt.ishold()`;
|
|
41606
41883
|
if (kind.name === "clf") return `$rt.plot_instr({type: "clf"})`;
|
|
41884
|
+
if (kind.name === "title")
|
|
41885
|
+
return `$rt.plot_instr({type: "set_title", text: ${args[0] ?? '""'}})`;
|
|
41886
|
+
if (kind.name === "xlabel")
|
|
41887
|
+
return `$rt.plot_instr({type: "set_xlabel", text: ${args[0] ?? '""'}})`;
|
|
41888
|
+
if (kind.name === "ylabel")
|
|
41889
|
+
return `$rt.plot_instr({type: "set_ylabel", text: ${args[0] ?? '""'}})`;
|
|
41890
|
+
if (kind.name === "shading")
|
|
41891
|
+
return `$rt.plot_instr({type: "set_shading", shading: ${args[0] ?? '"faceted"'}})`;
|
|
41607
41892
|
if (kind.name === "close") {
|
|
41608
41893
|
if (args.length > 0) {
|
|
41609
41894
|
return `$rt.plot_instr({type: "close_all"})`;
|
|
@@ -41715,13 +42000,18 @@ function genFuncCall(cg, kind) {
|
|
|
41715
42000
|
break;
|
|
41716
42001
|
}
|
|
41717
42002
|
case "builtin": {
|
|
41718
|
-
const
|
|
41719
|
-
kind.name
|
|
41720
|
-
kind.nargout,
|
|
41721
|
-
kind.args,
|
|
41722
|
-
args
|
|
42003
|
+
const isJsUserFunc = cg.loweringCtx.functionIndex.jsUserFunctions.has(
|
|
42004
|
+
kind.name
|
|
41723
42005
|
);
|
|
41724
|
-
if (
|
|
42006
|
+
if (!isJsUserFunc) {
|
|
42007
|
+
const nativeMath = tryNativeMathCodegen(
|
|
42008
|
+
kind.name,
|
|
42009
|
+
kind.nargout,
|
|
42010
|
+
kind.args,
|
|
42011
|
+
args
|
|
42012
|
+
);
|
|
42013
|
+
if (nativeMath !== null) return nativeMath;
|
|
42014
|
+
}
|
|
41725
42015
|
if (hasUnknown) {
|
|
41726
42016
|
return emitDispatchUnknown(
|
|
41727
42017
|
cg,
|
|
@@ -43327,8 +43617,61 @@ var defaultCheck = (_argTypes, nargout) => ({
|
|
|
43327
43617
|
kind: "Unknown"
|
|
43328
43618
|
})
|
|
43329
43619
|
});
|
|
43330
|
-
function
|
|
43620
|
+
function buildWasmMap(wasmFiles) {
|
|
43621
|
+
const map = /* @__PURE__ */ new Map();
|
|
43622
|
+
for (const f of wasmFiles) {
|
|
43623
|
+
if (!f.data) continue;
|
|
43624
|
+
const base = f.name.split("/").pop().replace(/\.wasm$/, "");
|
|
43625
|
+
map.set(base, f.data);
|
|
43626
|
+
}
|
|
43627
|
+
return map;
|
|
43628
|
+
}
|
|
43629
|
+
function parseWasmDirective(source) {
|
|
43630
|
+
const match = source.match(/^\s*\/\/\s*wasm:\s*(\S+)/);
|
|
43631
|
+
return match ? match[1] : null;
|
|
43632
|
+
}
|
|
43633
|
+
function instantiateWasm(wasmData) {
|
|
43634
|
+
const wasmModule = new WebAssembly.Module(wasmData);
|
|
43635
|
+
const moduleImports = WebAssembly.Module.imports(wasmModule);
|
|
43636
|
+
const importObject = {};
|
|
43637
|
+
const neededModules = new Set(moduleImports.map((i) => i.module));
|
|
43638
|
+
if (neededModules.has("wasi_snapshot_preview1")) {
|
|
43639
|
+
importObject.wasi_snapshot_preview1 = {
|
|
43640
|
+
fd_write: () => 0,
|
|
43641
|
+
fd_read: () => 0,
|
|
43642
|
+
fd_close: () => 0,
|
|
43643
|
+
fd_seek: () => 0,
|
|
43644
|
+
fd_fdstat_get: () => 0,
|
|
43645
|
+
proc_exit: () => {
|
|
43646
|
+
},
|
|
43647
|
+
environ_sizes_get: () => 0,
|
|
43648
|
+
environ_get: () => 0,
|
|
43649
|
+
clock_time_get: () => 0,
|
|
43650
|
+
args_sizes_get: () => 0,
|
|
43651
|
+
args_get: () => 0
|
|
43652
|
+
};
|
|
43653
|
+
}
|
|
43654
|
+
if (neededModules.has("env")) {
|
|
43655
|
+
importObject.env = {
|
|
43656
|
+
emscripten_notify_memory_growth: () => {
|
|
43657
|
+
}
|
|
43658
|
+
};
|
|
43659
|
+
}
|
|
43660
|
+
return new WebAssembly.Instance(wasmModule, importObject);
|
|
43661
|
+
}
|
|
43662
|
+
function loadJsUserFunctions(jsFiles, wasmFiles) {
|
|
43331
43663
|
const result = /* @__PURE__ */ new Map();
|
|
43664
|
+
const wasmMap = wasmFiles ? buildWasmMap(wasmFiles) : /* @__PURE__ */ new Map();
|
|
43665
|
+
const wasmInstanceCache = /* @__PURE__ */ new Map();
|
|
43666
|
+
function getWasmInstance(name) {
|
|
43667
|
+
const cached = wasmInstanceCache.get(name);
|
|
43668
|
+
if (cached) return cached;
|
|
43669
|
+
const data = wasmMap.get(name);
|
|
43670
|
+
if (!data) return null;
|
|
43671
|
+
const instance = instantiateWasm(data);
|
|
43672
|
+
wasmInstanceCache.set(name, instance);
|
|
43673
|
+
return instance;
|
|
43674
|
+
}
|
|
43332
43675
|
for (const file of jsFiles) {
|
|
43333
43676
|
const funcName = funcNameFromFile(file.name);
|
|
43334
43677
|
try {
|
|
@@ -43342,14 +43685,18 @@ function loadJsUserFunctions(jsFiles) {
|
|
|
43342
43685
|
apply: branch.apply
|
|
43343
43686
|
});
|
|
43344
43687
|
};
|
|
43688
|
+
const wasmName = parseWasmDirective(file.source) ?? funcName;
|
|
43689
|
+
const wasmInstance = getWasmInstance(wasmName);
|
|
43345
43690
|
const factory = new Function(
|
|
43346
43691
|
"RTV",
|
|
43347
43692
|
"RuntimeError",
|
|
43348
43693
|
"FloatXArray",
|
|
43694
|
+
"IType",
|
|
43349
43695
|
"register",
|
|
43696
|
+
"wasm",
|
|
43350
43697
|
file.source
|
|
43351
43698
|
);
|
|
43352
|
-
factory(RTV, RuntimeError, FloatXArray, registerFn);
|
|
43699
|
+
factory(RTV, RuntimeError, FloatXArray, IType, registerFn, wasmInstance);
|
|
43353
43700
|
if (branches.length === 0) {
|
|
43354
43701
|
throw new Error(
|
|
43355
43702
|
`JS user function '${funcName}' (${file.name}) must call register() at least once`
|
|
@@ -43445,10 +43792,13 @@ function generateMainScriptCode(source, mainFileName = "script.m", workspaceFile
|
|
|
43445
43792
|
const ctx = new LoweringContext(source, mainFileName);
|
|
43446
43793
|
const mWorkspaceFiles = [];
|
|
43447
43794
|
const jsWorkspaceFiles = [];
|
|
43795
|
+
const wasmWorkspaceFiles = [];
|
|
43448
43796
|
if (workspaceFiles) {
|
|
43449
43797
|
for (const f of workspaceFiles) {
|
|
43450
43798
|
if (f.name.endsWith(".js")) {
|
|
43451
43799
|
jsWorkspaceFiles.push(f);
|
|
43800
|
+
} else if (f.name.endsWith(".wasm")) {
|
|
43801
|
+
wasmWorkspaceFiles.push(f);
|
|
43452
43802
|
} else {
|
|
43453
43803
|
mWorkspaceFiles.push(f);
|
|
43454
43804
|
}
|
|
@@ -43465,7 +43815,10 @@ function generateMainScriptCode(source, mainFileName = "script.m", workspaceFile
|
|
|
43465
43815
|
}
|
|
43466
43816
|
ctx.registry.searchPaths = [...searchPaths ?? [], SHIM_SEARCH_PATH];
|
|
43467
43817
|
_t0 = performance.now();
|
|
43468
|
-
const jsUserFunctions = loadJsUserFunctions(
|
|
43818
|
+
const jsUserFunctions = loadJsUserFunctions(
|
|
43819
|
+
jsWorkspaceFiles,
|
|
43820
|
+
wasmWorkspaceFiles
|
|
43821
|
+
);
|
|
43469
43822
|
const _loadJsUserFunctionsMs = performance.now() - _t0;
|
|
43470
43823
|
_t0 = performance.now();
|
|
43471
43824
|
ctx.fileASTCache.set(mainFileName, ast);
|
|
@@ -43491,12 +43844,15 @@ function generateMainScriptCode(source, mainFileName = "script.m", workspaceFile
|
|
|
43491
43844
|
ctx.registerWorkspaceFiles(mWorkspaceFiles);
|
|
43492
43845
|
}
|
|
43493
43846
|
const jsUserFuncNames = [...jsUserFunctions.keys()];
|
|
43847
|
+
const savedBuiltins = /* @__PURE__ */ new Map();
|
|
43494
43848
|
for (const name of jsUserFuncNames) {
|
|
43849
|
+
const existing = getBuiltin(name);
|
|
43850
|
+
if (existing) savedBuiltins.set(name, existing);
|
|
43495
43851
|
register(name, jsUserFunctions.get(name));
|
|
43496
43852
|
}
|
|
43497
43853
|
const _registrationMs = performance.now() - _t0;
|
|
43498
43854
|
_t0 = performance.now();
|
|
43499
|
-
const functionIndex = ctx.buildFunctionIndex();
|
|
43855
|
+
const functionIndex = ctx.buildFunctionIndex(jsUserFuncNames);
|
|
43500
43856
|
const _buildFunctionIndexMs = performance.now() - _t0;
|
|
43501
43857
|
ctx.isTopLevel = true;
|
|
43502
43858
|
const initialVarIRVars = [];
|
|
@@ -43575,7 +43931,12 @@ function generateMainScriptCode(source, mainFileName = "script.m", workspaceFile
|
|
|
43575
43931
|
codegen.emit(`return $ret;`);
|
|
43576
43932
|
const _codegenMs = performance.now() - _t0;
|
|
43577
43933
|
for (const name of jsUserFuncNames) {
|
|
43578
|
-
|
|
43934
|
+
const original = savedBuiltins.get(name);
|
|
43935
|
+
if (original) {
|
|
43936
|
+
register(name, original);
|
|
43937
|
+
} else {
|
|
43938
|
+
unregister(name);
|
|
43939
|
+
}
|
|
43579
43940
|
}
|
|
43580
43941
|
return {
|
|
43581
43942
|
jsCode: codegen.getCode(),
|
|
@@ -44455,6 +44816,14 @@ async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths) {
|
|
|
44455
44816
|
|
|
44456
44817
|
// src/cli-fileio.ts
|
|
44457
44818
|
import { openSync, closeSync, readSync, writeSync, readFileSync as readFileSync5 } from "fs";
|
|
44819
|
+
import { homedir as homedir4 } from "os";
|
|
44820
|
+
import { join as join5 } from "path";
|
|
44821
|
+
function expandTilde(filepath) {
|
|
44822
|
+
if (filepath.startsWith("~/")) {
|
|
44823
|
+
return join5(homedir4(), filepath.slice(2));
|
|
44824
|
+
}
|
|
44825
|
+
return filepath;
|
|
44826
|
+
}
|
|
44458
44827
|
function permissionToFlags(permission) {
|
|
44459
44828
|
switch (permission) {
|
|
44460
44829
|
case "r":
|
|
@@ -44481,7 +44850,7 @@ var NodeFileIOAdapter = class {
|
|
|
44481
44850
|
fopen(filename, permission) {
|
|
44482
44851
|
try {
|
|
44483
44852
|
const flags = permissionToFlags(permission);
|
|
44484
|
-
const fd = openSync(filename, flags);
|
|
44853
|
+
const fd = openSync(expandTilde(filename), flags);
|
|
44485
44854
|
const fid = this.nextFid++;
|
|
44486
44855
|
this.openFiles.set(fid, {
|
|
44487
44856
|
fd,
|
|
@@ -44527,7 +44896,7 @@ var NodeFileIOAdapter = class {
|
|
|
44527
44896
|
return this.readLine(entry, true);
|
|
44528
44897
|
}
|
|
44529
44898
|
fileread(filename) {
|
|
44530
|
-
return readFileSync5(filename, "utf-8");
|
|
44899
|
+
return readFileSync5(expandTilde(filename), "utf-8");
|
|
44531
44900
|
}
|
|
44532
44901
|
feof(fid) {
|
|
44533
44902
|
const entry = this.getEntry(fid);
|
|
@@ -44609,8 +44978,8 @@ var NodeFileIOAdapter = class {
|
|
|
44609
44978
|
// src/cli.ts
|
|
44610
44979
|
var __filename = fileURLToPath2(import.meta.url);
|
|
44611
44980
|
var __dirname = dirname3(__filename);
|
|
44612
|
-
var packageDir2 =
|
|
44613
|
-
var addonPath =
|
|
44981
|
+
var packageDir2 = join6(__dirname, "..");
|
|
44982
|
+
var addonPath = join6(packageDir2, "build", "Release", "lapack_addon.node");
|
|
44614
44983
|
var nativeAddonLoaded = false;
|
|
44615
44984
|
try {
|
|
44616
44985
|
const req = createRequire(import.meta.url);
|
|
@@ -44625,7 +44994,7 @@ function scanMFiles(dirPath, excludeFile) {
|
|
|
44625
44994
|
try {
|
|
44626
44995
|
const entries = readdirSync2(dirPath);
|
|
44627
44996
|
for (const entry of entries) {
|
|
44628
|
-
const fullPath =
|
|
44997
|
+
const fullPath = join6(dirPath, entry);
|
|
44629
44998
|
if (excludeFile && fullPath === excludeFile) {
|
|
44630
44999
|
continue;
|
|
44631
45000
|
}
|
|
@@ -44640,6 +45009,13 @@ function scanMFiles(dirPath, excludeFile) {
|
|
|
44640
45009
|
name: fullPath,
|
|
44641
45010
|
source
|
|
44642
45011
|
});
|
|
45012
|
+
} else if (stat.isFile() && entry.endsWith(".wasm")) {
|
|
45013
|
+
const data = readFileSync6(fullPath);
|
|
45014
|
+
files.push({
|
|
45015
|
+
name: fullPath,
|
|
45016
|
+
source: "",
|
|
45017
|
+
data: new Uint8Array(data)
|
|
45018
|
+
});
|
|
44643
45019
|
}
|
|
44644
45020
|
}
|
|
44645
45021
|
} catch {
|
|
@@ -44657,7 +45033,7 @@ function findTestFiles(dir) {
|
|
|
44657
45033
|
}
|
|
44658
45034
|
entries.sort();
|
|
44659
45035
|
for (const entry of entries) {
|
|
44660
|
-
const fullPath =
|
|
45036
|
+
const fullPath = join6(current, entry);
|
|
44661
45037
|
let stat;
|
|
44662
45038
|
try {
|
|
44663
45039
|
stat = statSync2(fullPath);
|
|
@@ -44665,7 +45041,7 @@ function findTestFiles(dir) {
|
|
|
44665
45041
|
continue;
|
|
44666
45042
|
}
|
|
44667
45043
|
if (stat.isDirectory()) {
|
|
44668
|
-
if (!entry.startsWith("@") && !entry.startsWith("+")) {
|
|
45044
|
+
if (!entry.startsWith("@") && !entry.startsWith("+") && entry !== "wasm") {
|
|
44669
45045
|
walk(fullPath);
|
|
44670
45046
|
}
|
|
44671
45047
|
} else if (stat.isFile() && entry.endsWith(".m")) {
|
|
@@ -45110,7 +45486,7 @@ function finalizeDumpFile(dumpFile, mainFileName, jsCode) {
|
|
|
45110
45486
|
writeFileSync3(dumpFile, header + jsCode + "\n" + jitContent);
|
|
45111
45487
|
}
|
|
45112
45488
|
async function cmdBuildAddon() {
|
|
45113
|
-
const bindingGyp =
|
|
45489
|
+
const bindingGyp = join6(packageDir2, "binding.gyp");
|
|
45114
45490
|
if (!existsSync4(bindingGyp)) {
|
|
45115
45491
|
console.error(
|
|
45116
45492
|
"Error: binding.gyp not found in package directory: " + packageDir2
|
|
@@ -45317,7 +45693,7 @@ async function main() {
|
|
|
45317
45693
|
await cmdEval(rest);
|
|
45318
45694
|
break;
|
|
45319
45695
|
case "run-tests": {
|
|
45320
|
-
const dir = rest.length > 0 ? rest[0] :
|
|
45696
|
+
const dir = rest.length > 0 ? rest[0] : join6(packageDir2, "numbl_test_scripts");
|
|
45321
45697
|
await runTests(dir);
|
|
45322
45698
|
break;
|
|
45323
45699
|
}
|