numbl 0.0.4 → 0.0.6
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 +26 -0
- package/dist-cli/cli.js +194 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,32 @@ numbl # interactive REPL
|
|
|
26
26
|
numbl --info # check native addon status
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
## Try it with Docker
|
|
30
|
+
|
|
31
|
+
Run the REPL instantly — no installation required:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
docker run -it node:22 npx numbl
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
With plotting support (open http://localhost:8234 in your browser):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
docker run -it -p 8234:8234 node:22 npx numbl --plot-port 8234
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
With native LAPACK support for fast linear algebra:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
docker run -it node:22 bash -c "apt-get update && apt-get install -y libopenblas-dev && npx numbl build-addon && npx numbl"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
With both LAPACK and plotting:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
docker run -it -p 8234:8234 node:22 bash -c "apt-get update && apt-get install -y libopenblas-dev && npx numbl build-addon && npx numbl --plot-port 8234"
|
|
53
|
+
```
|
|
54
|
+
|
|
29
55
|
## Upgrading
|
|
30
56
|
|
|
31
57
|
```bash
|
package/dist-cli/cli.js
CHANGED
|
@@ -202,6 +202,21 @@ function shareRuntimeValue(v) {
|
|
|
202
202
|
_rc: v._rc
|
|
203
203
|
};
|
|
204
204
|
}
|
|
205
|
+
if (v.kind === "class_instance" && !v.isHandleClass) {
|
|
206
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
207
|
+
for (const [k, fv] of v.fields) {
|
|
208
|
+
newFields.set(k, shareRuntimeValue(fv));
|
|
209
|
+
}
|
|
210
|
+
const copy = {
|
|
211
|
+
kind: "class_instance",
|
|
212
|
+
className: v.className,
|
|
213
|
+
fields: newFields,
|
|
214
|
+
isHandleClass: false
|
|
215
|
+
};
|
|
216
|
+
if (v.$m) copy.$m = v.$m;
|
|
217
|
+
if (v._builtinData) copy._builtinData = shareRuntimeValue(v._builtinData);
|
|
218
|
+
return copy;
|
|
219
|
+
}
|
|
205
220
|
return v;
|
|
206
221
|
}
|
|
207
222
|
|
|
@@ -12679,6 +12694,13 @@ function indexIntoRTValue(base, indices) {
|
|
|
12679
12694
|
return base;
|
|
12680
12695
|
}
|
|
12681
12696
|
}
|
|
12697
|
+
if (base.kind === "struct" || base.kind === "class_instance") {
|
|
12698
|
+
if (indices.length === 1) {
|
|
12699
|
+
const i = Math.round(toNumber(indices[0]));
|
|
12700
|
+
if (i !== 1) throw new RuntimeError("Index exceeds struct dimensions");
|
|
12701
|
+
return base;
|
|
12702
|
+
}
|
|
12703
|
+
}
|
|
12682
12704
|
if (base.kind === "struct_array") {
|
|
12683
12705
|
if (indices.length === 1) {
|
|
12684
12706
|
const idx = indices[0];
|
|
@@ -12717,6 +12739,12 @@ function storeIntoRTValueIndex(base, indices, rhs) {
|
|
|
12717
12739
|
const idx = indices[0];
|
|
12718
12740
|
if (idx.kind === "number") {
|
|
12719
12741
|
toDelete.add(Math.round(idx.value) - 1);
|
|
12742
|
+
} else if (idx.kind === "logical") {
|
|
12743
|
+
if (idx.value) toDelete.add(0);
|
|
12744
|
+
} else if (idx.kind === "tensor" && idx._isLogical) {
|
|
12745
|
+
for (let i = 0; i < idx.data.length; i++) {
|
|
12746
|
+
if (idx.data[i] !== 0) toDelete.add(i);
|
|
12747
|
+
}
|
|
12720
12748
|
} else if (idx.kind === "tensor") {
|
|
12721
12749
|
for (let i = 0; i < idx.data.length; i++) {
|
|
12722
12750
|
toDelete.add(Math.round(idx.data[i]) - 1);
|
|
@@ -12743,6 +12771,12 @@ function storeIntoRTValueIndex(base, indices, rhs) {
|
|
|
12743
12771
|
const s = /* @__PURE__ */ new Set();
|
|
12744
12772
|
if (idx.kind === "number") {
|
|
12745
12773
|
s.add(Math.round(idx.value) - 1);
|
|
12774
|
+
} else if (idx.kind === "logical") {
|
|
12775
|
+
if (idx.value) s.add(0);
|
|
12776
|
+
} else if (idx.kind === "tensor" && idx._isLogical) {
|
|
12777
|
+
for (let i = 0; i < idx.data.length; i++) {
|
|
12778
|
+
if (idx.data[i] !== 0) s.add(i);
|
|
12779
|
+
}
|
|
12746
12780
|
} else if (idx.kind === "tensor") {
|
|
12747
12781
|
for (let i = 0; i < idx.data.length; i++)
|
|
12748
12782
|
s.add(Math.round(idx.data[i]) - 1);
|
|
@@ -13281,6 +13315,26 @@ function storeIntoRTValueIndex(base, indices, rhs) {
|
|
|
13281
13315
|
base = RTV.cell([...base.data], [...base.shape]);
|
|
13282
13316
|
}
|
|
13283
13317
|
if (indices.length === 1) {
|
|
13318
|
+
if (indices[0].kind === "tensor" && !indices[0]._isLogical) {
|
|
13319
|
+
const idx = indices[0];
|
|
13320
|
+
if (rhs.kind !== "cell" || rhs.data.length !== idx.data.length) {
|
|
13321
|
+
throw new RuntimeError("Subscripted assignment dimension mismatch");
|
|
13322
|
+
}
|
|
13323
|
+
let maxIdx = -1;
|
|
13324
|
+
for (let j = 0; j < idx.data.length; j++) {
|
|
13325
|
+
const pos = Math.round(idx.data[j]) - 1;
|
|
13326
|
+
if (pos < 0) throw new RuntimeError("Cell index exceeds bounds");
|
|
13327
|
+
if (pos > maxIdx) maxIdx = pos;
|
|
13328
|
+
}
|
|
13329
|
+
while (base.data.length <= maxIdx)
|
|
13330
|
+
base.data.push(RTV.tensor(new FloatXArray(0), [0, 0]));
|
|
13331
|
+
for (let j = 0; j < idx.data.length; j++) {
|
|
13332
|
+
const pos = Math.round(idx.data[j]) - 1;
|
|
13333
|
+
base.data[pos] = rhs.data[j];
|
|
13334
|
+
}
|
|
13335
|
+
base.shape = [1, base.data.length];
|
|
13336
|
+
return base;
|
|
13337
|
+
}
|
|
13284
13338
|
const i = Math.round(toNumber(indices[0])) - 1;
|
|
13285
13339
|
if (i < 0) throw new RuntimeError("Cell index exceeds bounds");
|
|
13286
13340
|
if (i >= base.data.length) {
|
|
@@ -16718,8 +16772,14 @@ function elemwise(fn, o) {
|
|
|
16718
16772
|
const apply = (args) => {
|
|
16719
16773
|
if (args.length !== 1) throw new RuntimeError(`Expected 1 argument`);
|
|
16720
16774
|
const v = args[0];
|
|
16721
|
-
if (v.kind === "number")
|
|
16722
|
-
|
|
16775
|
+
if (v.kind === "number") {
|
|
16776
|
+
const result = fn(v.value);
|
|
16777
|
+
return o?.isLogical ? RTV.logical(!!result) : RTV.num(result);
|
|
16778
|
+
}
|
|
16779
|
+
if (v.kind === "logical") {
|
|
16780
|
+
const result = fn(v.value ? 1 : 0);
|
|
16781
|
+
return o?.isLogical ? RTV.logical(!!result) : RTV.num(result);
|
|
16782
|
+
}
|
|
16723
16783
|
if (v.kind === "tensor") {
|
|
16724
16784
|
const result = new FloatXArray(v.data.length);
|
|
16725
16785
|
for (let i = 0; i < v.data.length; i++) result[i] = fn(v.data[i]);
|
|
@@ -16731,14 +16791,18 @@ function elemwise(fn, o) {
|
|
|
16731
16791
|
throw new RuntimeError("Expected numeric argument");
|
|
16732
16792
|
};
|
|
16733
16793
|
if (o?.nativeJs) {
|
|
16794
|
+
const outKind = o.isLogical ? "Logical" : "Num";
|
|
16734
16795
|
ret.push({
|
|
16735
16796
|
check: (argTypes) => {
|
|
16736
16797
|
if (argTypes.length !== 1) return null;
|
|
16737
16798
|
if (argTypes[0].kind !== "Num") return null;
|
|
16738
|
-
return { outputTypes: [{ kind:
|
|
16799
|
+
return { outputTypes: [{ kind: outKind }] };
|
|
16739
16800
|
},
|
|
16740
16801
|
apply,
|
|
16741
|
-
|
|
16802
|
+
// Disable native JS fast-path for logical builtins — their scalar
|
|
16803
|
+
// results must stay as RuntimeValue logicals so the codegen emits
|
|
16804
|
+
// $rt.not() instead of the `=== 0` fast path.
|
|
16805
|
+
nativeJsFn: o.isLogical ? void 0 : o.nativeJs
|
|
16742
16806
|
});
|
|
16743
16807
|
}
|
|
16744
16808
|
ret.push({
|
|
@@ -17311,20 +17375,17 @@ function registerArrayFunctions() {
|
|
|
17311
17375
|
}
|
|
17312
17376
|
}
|
|
17313
17377
|
]);
|
|
17314
|
-
|
|
17315
|
-
|
|
17316
|
-
|
|
17317
|
-
|
|
17318
|
-
|
|
17319
|
-
|
|
17320
|
-
|
|
17321
|
-
|
|
17322
|
-
|
|
17323
|
-
|
|
17324
|
-
|
|
17325
|
-
}
|
|
17326
|
-
}
|
|
17327
|
-
]);
|
|
17378
|
+
const nanApply = (args) => {
|
|
17379
|
+
if (args.length === 0) return RTV.num(NaN);
|
|
17380
|
+
const shape = parseShapeArgs2(args);
|
|
17381
|
+
if (shape.length === 1) shape.push(shape[0]);
|
|
17382
|
+
const n = numel(shape);
|
|
17383
|
+
const data = new FloatXArray(n);
|
|
17384
|
+
data.fill(NaN);
|
|
17385
|
+
return RTV.tensor(data, shape);
|
|
17386
|
+
};
|
|
17387
|
+
register("NaN", [{ check: arrayConstructorCheck, apply: nanApply }]);
|
|
17388
|
+
register("nan", [{ check: arrayConstructorCheck, apply: nanApply }]);
|
|
17328
17389
|
register("eye", [
|
|
17329
17390
|
{
|
|
17330
17391
|
check: arrayConstructorCheck,
|
|
@@ -19600,7 +19661,52 @@ function registerReductionFunctions() {
|
|
|
19600
19661
|
if (args.length < 2)
|
|
19601
19662
|
throw new RuntimeError("ismember requires 2 arguments");
|
|
19602
19663
|
const v = args[0];
|
|
19603
|
-
const
|
|
19664
|
+
const b = args[1];
|
|
19665
|
+
const isStringLike = (x) => x.kind === "string" || x.kind === "char";
|
|
19666
|
+
const isCellOfStrings = (x) => x.kind === "cell" && x.data.every(
|
|
19667
|
+
(e) => e.kind === "string" || e.kind === "char"
|
|
19668
|
+
);
|
|
19669
|
+
if (isStringLike(v) || isCellOfStrings(v) || isStringLike(b) || isCellOfStrings(b)) {
|
|
19670
|
+
const bStrings = [];
|
|
19671
|
+
if (isStringLike(b)) {
|
|
19672
|
+
bStrings.push(toString(b));
|
|
19673
|
+
} else if (isCellOfStrings(b)) {
|
|
19674
|
+
if (b.kind !== "cell") throw new RuntimeError("unexpected type");
|
|
19675
|
+
for (const e of b.data)
|
|
19676
|
+
bStrings.push(toString(e));
|
|
19677
|
+
} else {
|
|
19678
|
+
throw new RuntimeError("ismember: incompatible argument types");
|
|
19679
|
+
}
|
|
19680
|
+
const bSet = new Set(bStrings);
|
|
19681
|
+
if (isStringLike(v)) {
|
|
19682
|
+
const found = bSet.has(toString(v));
|
|
19683
|
+
const lia = RTV.logical(found);
|
|
19684
|
+
if (nargout > 1) {
|
|
19685
|
+
const idx = found ? bStrings.indexOf(toString(v)) + 1 : 0;
|
|
19686
|
+
return [lia, RTV.num(idx)];
|
|
19687
|
+
}
|
|
19688
|
+
return lia;
|
|
19689
|
+
}
|
|
19690
|
+
if (v.kind === "cell" && isCellOfStrings(v)) {
|
|
19691
|
+
const vData = v.data;
|
|
19692
|
+
const tfData = new FloatXArray(vData.length);
|
|
19693
|
+
const locData = nargout > 1 ? new FloatXArray(vData.length) : void 0;
|
|
19694
|
+
for (let i = 0; i < vData.length; i++) {
|
|
19695
|
+
const s = toString(vData[i]);
|
|
19696
|
+
const found = bSet.has(s);
|
|
19697
|
+
tfData[i] = found ? 1 : 0;
|
|
19698
|
+
if (locData) locData[i] = found ? bStrings.indexOf(s) + 1 : 0;
|
|
19699
|
+
}
|
|
19700
|
+
const t = RTV.tensor(tfData, [...v.shape]);
|
|
19701
|
+
t._isLogical = true;
|
|
19702
|
+
if (nargout > 1) {
|
|
19703
|
+
return [t, RTV.tensor(locData, [...v.shape])];
|
|
19704
|
+
}
|
|
19705
|
+
return t;
|
|
19706
|
+
}
|
|
19707
|
+
throw new RuntimeError("ismember: incompatible argument types");
|
|
19708
|
+
}
|
|
19709
|
+
const bArr = toNumArray(b, "ismember");
|
|
19604
19710
|
const bMap = /* @__PURE__ */ new Map();
|
|
19605
19711
|
for (let i = 0; i < bArr.length; i++) {
|
|
19606
19712
|
if (!bMap.has(bArr[i])) bMap.set(bArr[i], i + 1);
|
|
@@ -21541,21 +21647,20 @@ function registerMiscFunctions() {
|
|
|
21541
21647
|
return RTV.struct(fields);
|
|
21542
21648
|
})
|
|
21543
21649
|
);
|
|
21544
|
-
|
|
21545
|
-
|
|
21546
|
-
|
|
21547
|
-
|
|
21548
|
-
|
|
21549
|
-
|
|
21550
|
-
|
|
21551
|
-
|
|
21552
|
-
|
|
21553
|
-
|
|
21554
|
-
|
|
21555
|
-
|
|
21556
|
-
|
|
21557
|
-
|
|
21558
|
-
);
|
|
21650
|
+
const fieldnamesApply = builtinSingle((args) => {
|
|
21651
|
+
if (args.length !== 1)
|
|
21652
|
+
throw new RuntimeError("fieldnames requires 1 argument");
|
|
21653
|
+
const v = args[0];
|
|
21654
|
+
if (v.kind !== "struct" && v.kind !== "class_instance")
|
|
21655
|
+
throw new RuntimeError("fieldnames: argument must be a struct");
|
|
21656
|
+
const names = [...v.fields.keys()];
|
|
21657
|
+
return RTV.cell(
|
|
21658
|
+
names.map((n) => RTV.string(n)),
|
|
21659
|
+
[names.length, 1]
|
|
21660
|
+
);
|
|
21661
|
+
});
|
|
21662
|
+
register("fieldnames", fieldnamesApply);
|
|
21663
|
+
register("fields", fieldnamesApply);
|
|
21559
21664
|
register(
|
|
21560
21665
|
"isfield",
|
|
21561
21666
|
builtinSingle((args) => {
|
|
@@ -22361,7 +22466,6 @@ var dummyHandleFunctions = [
|
|
|
22361
22466
|
"gcf",
|
|
22362
22467
|
"gca",
|
|
22363
22468
|
"shg",
|
|
22364
|
-
"ishold",
|
|
22365
22469
|
"dir",
|
|
22366
22470
|
"newplot",
|
|
22367
22471
|
"caxis",
|
|
@@ -22401,7 +22505,7 @@ function registerDummyArrayFunctions() {
|
|
|
22401
22505
|
register(name, fn);
|
|
22402
22506
|
}
|
|
22403
22507
|
}
|
|
22404
|
-
var returnDummyBooleanFunctions = ["ispc", "ismac", "isunix"];
|
|
22508
|
+
var returnDummyBooleanFunctions = ["ispc", "ismac", "isunix", "ishold"];
|
|
22405
22509
|
function registerDummyBooleanFunctions() {
|
|
22406
22510
|
const fn = builtinSingle(() => RTV.logical(false), {
|
|
22407
22511
|
outputType: IType.Logical
|
|
@@ -22419,12 +22523,27 @@ function registerDummyCellArrayFunctions() {
|
|
|
22419
22523
|
register(name, fn);
|
|
22420
22524
|
}
|
|
22421
22525
|
}
|
|
22526
|
+
function registerHandleGetSet() {
|
|
22527
|
+
register(
|
|
22528
|
+
"get",
|
|
22529
|
+
builtinSingle(() => RTV.dummyHandle(), {
|
|
22530
|
+
outputType: IType.DummyHandle
|
|
22531
|
+
})
|
|
22532
|
+
);
|
|
22533
|
+
register(
|
|
22534
|
+
"set",
|
|
22535
|
+
builtinSingle(() => void 0, {
|
|
22536
|
+
outputType: IType.Void
|
|
22537
|
+
})
|
|
22538
|
+
);
|
|
22539
|
+
}
|
|
22422
22540
|
var registerDummyFunctions = () => {
|
|
22423
22541
|
registerDummyHandleFunctions();
|
|
22424
22542
|
registerDummyStringFunctions();
|
|
22425
22543
|
registerDummyArrayFunctions();
|
|
22426
22544
|
registerDummyBooleanFunctions();
|
|
22427
22545
|
registerDummyCellArrayFunctions();
|
|
22546
|
+
registerHandleGetSet();
|
|
22428
22547
|
};
|
|
22429
22548
|
|
|
22430
22549
|
// src/numbl-core/builtins/index.ts
|
|
@@ -25823,9 +25942,6 @@ var CodegenExprs = class extends CodegenBase {
|
|
|
25823
25942
|
if (kind.name === "isa") return `$rt.isa(${args[0]}, ${args[1]})`;
|
|
25824
25943
|
if (kind.name === "figure")
|
|
25825
25944
|
return `$rt.plot_instr({type: "set_figure_handle", handle: ${args[0] ?? "1"}})`;
|
|
25826
|
-
if (kind.name === "plot") {
|
|
25827
|
-
return `$rt.plot_call([${args.join(", ")}])`;
|
|
25828
|
-
}
|
|
25829
25945
|
if (kind.name === "hold")
|
|
25830
25946
|
return `$rt.plot_instr({type: "set_hold", value: ${args[0]}})`;
|
|
25831
25947
|
if (kind.name === "drawnow") {
|
|
@@ -28358,6 +28474,7 @@ var Runtime = class {
|
|
|
28358
28474
|
}
|
|
28359
28475
|
/** Unwrap a RuntimeValue result to native JS types for the fast path */
|
|
28360
28476
|
unwrapResult(result) {
|
|
28477
|
+
if (result === void 0) return void 0;
|
|
28361
28478
|
if (Array.isArray(result)) {
|
|
28362
28479
|
return result.map((r) => {
|
|
28363
28480
|
if (r.kind === "number") return r.value;
|
|
@@ -29595,6 +29712,9 @@ var Runtime = class {
|
|
|
29595
29712
|
);
|
|
29596
29713
|
if (fn) return fn.fn(nargout, ...args);
|
|
29597
29714
|
}
|
|
29715
|
+
if (name === "plot") {
|
|
29716
|
+
return this.plot_call(args);
|
|
29717
|
+
}
|
|
29598
29718
|
const builtin = this.builtins[name];
|
|
29599
29719
|
if (builtin) return builtin(nargout, args);
|
|
29600
29720
|
throw new RuntimeError(`Undefined function or variable: '${name}'`);
|
|
@@ -30212,7 +30332,7 @@ var MIME_TYPES = {
|
|
|
30212
30332
|
".png": "image/png",
|
|
30213
30333
|
".json": "application/json"
|
|
30214
30334
|
};
|
|
30215
|
-
async function startPlotServer() {
|
|
30335
|
+
async function startPlotServer(options) {
|
|
30216
30336
|
const thisDir = fileURLToPath(new URL(".", import.meta.url));
|
|
30217
30337
|
const distDir = join(thisDir, "..", "dist-plot-viewer");
|
|
30218
30338
|
if (!existsSync(distDir)) {
|
|
@@ -30266,11 +30386,13 @@ Expected directory: ${distDir}`
|
|
|
30266
30386
|
res.end("Not found");
|
|
30267
30387
|
}
|
|
30268
30388
|
});
|
|
30389
|
+
const listenPort = options?.port ?? 0;
|
|
30390
|
+
const listenHost = options?.host ?? "127.0.0.1";
|
|
30269
30391
|
await new Promise((resolve2) => {
|
|
30270
|
-
server.listen(
|
|
30392
|
+
server.listen(listenPort, listenHost, () => resolve2());
|
|
30271
30393
|
});
|
|
30272
30394
|
const port = server.address().port;
|
|
30273
|
-
const url = `http
|
|
30395
|
+
const url = `http://${listenHost}:${port}/`;
|
|
30274
30396
|
console.error(`[numbl] Plot server at ${url}`);
|
|
30275
30397
|
openBrowser(url);
|
|
30276
30398
|
let closedResolve;
|
|
@@ -30526,9 +30648,11 @@ function jsonReplacer(_key, value) {
|
|
|
30526
30648
|
}
|
|
30527
30649
|
return value;
|
|
30528
30650
|
}
|
|
30529
|
-
async function runRepl() {
|
|
30651
|
+
async function runRepl(plot, plotPort) {
|
|
30530
30652
|
const workspaceFiles = scanMFiles(process.cwd());
|
|
30531
30653
|
let variableValues = {};
|
|
30654
|
+
const plotOpts = plotPort !== void 0 ? { port: plotPort, host: "0.0.0.0" } : void 0;
|
|
30655
|
+
const { onDrawnow } = createPlotHandler(!plot, plotOpts);
|
|
30532
30656
|
const rl = createInterface({
|
|
30533
30657
|
input: process.stdin,
|
|
30534
30658
|
output: process.stdout,
|
|
@@ -30553,12 +30677,16 @@ async function runRepl() {
|
|
|
30553
30677
|
onOutput: (text) => {
|
|
30554
30678
|
process.stdout.write(text);
|
|
30555
30679
|
},
|
|
30680
|
+
onDrawnow,
|
|
30556
30681
|
initialVariableValues: variableValues
|
|
30557
30682
|
},
|
|
30558
30683
|
workspaceFiles,
|
|
30559
30684
|
"repl"
|
|
30560
30685
|
);
|
|
30561
30686
|
variableValues = result.variableValues;
|
|
30687
|
+
if (result.plotInstructions.length > 0 && onDrawnow) {
|
|
30688
|
+
onDrawnow(result.plotInstructions);
|
|
30689
|
+
}
|
|
30562
30690
|
} catch (error) {
|
|
30563
30691
|
const diags = diagnoseErrors(error, trimmed, "repl", workspaceFiles);
|
|
30564
30692
|
console.error(formatDiagnostics(diags));
|
|
@@ -30750,6 +30878,7 @@ async function main() {
|
|
|
30750
30878
|
let noAsync = false;
|
|
30751
30879
|
let noDce = false;
|
|
30752
30880
|
let plot = false;
|
|
30881
|
+
let plotPort;
|
|
30753
30882
|
let addScriptPath = false;
|
|
30754
30883
|
for (let i = 0; i < args.length; i++) {
|
|
30755
30884
|
if (args[i] === "--dump-js") {
|
|
@@ -30781,6 +30910,18 @@ async function main() {
|
|
|
30781
30910
|
noDce = true;
|
|
30782
30911
|
} else if (args[i] === "--plot") {
|
|
30783
30912
|
plot = true;
|
|
30913
|
+
} else if (args[i] === "--plot-port") {
|
|
30914
|
+
i++;
|
|
30915
|
+
if (i >= args.length) {
|
|
30916
|
+
console.error("Error: --plot-port requires a port number");
|
|
30917
|
+
process.exit(1);
|
|
30918
|
+
}
|
|
30919
|
+
plotPort = parseInt(args[i], 10);
|
|
30920
|
+
if (isNaN(plotPort)) {
|
|
30921
|
+
console.error("Error: --plot-port requires a valid port number");
|
|
30922
|
+
process.exit(1);
|
|
30923
|
+
}
|
|
30924
|
+
plot = true;
|
|
30784
30925
|
} else if (args[i] === "--add-script-path") {
|
|
30785
30926
|
addScriptPath = true;
|
|
30786
30927
|
} else if (args[i] === "--path") {
|
|
@@ -30810,7 +30951,7 @@ async function main() {
|
|
|
30810
30951
|
return;
|
|
30811
30952
|
}
|
|
30812
30953
|
if (evalCode === null && positional.length === 0) {
|
|
30813
|
-
await runRepl();
|
|
30954
|
+
await runRepl(plot, plotPort);
|
|
30814
30955
|
return;
|
|
30815
30956
|
}
|
|
30816
30957
|
let code = "";
|
|
@@ -30945,14 +31086,19 @@ async function main() {
|
|
|
30945
31086
|
workspaceFiles,
|
|
30946
31087
|
mainFileName
|
|
30947
31088
|
);
|
|
31089
|
+
const syncPlotOpts = plotPort !== void 0 ? { port: plotPort, host: "0.0.0.0" } : void 0;
|
|
30948
31090
|
if (result.plotInstructions.length > 0 && plot) {
|
|
30949
|
-
const plotServer = await startPlotServer();
|
|
31091
|
+
const plotServer = await startPlotServer(syncPlotOpts);
|
|
30950
31092
|
plotServer.sendInstructions(result.plotInstructions);
|
|
30951
31093
|
plotServer.scriptDone();
|
|
30952
31094
|
await plotServer.closed;
|
|
30953
31095
|
}
|
|
30954
31096
|
} else {
|
|
30955
|
-
const {
|
|
31097
|
+
const asyncPlotOpts = plotPort !== void 0 ? { port: plotPort, host: "0.0.0.0" } : void 0;
|
|
31098
|
+
const { onDrawnow, flushAndWait } = createPlotHandler(
|
|
31099
|
+
!plot,
|
|
31100
|
+
asyncPlotOpts
|
|
31101
|
+
);
|
|
30956
31102
|
const result = await executeCode(
|
|
30957
31103
|
code,
|
|
30958
31104
|
{
|
|
@@ -30975,7 +31121,7 @@ async function main() {
|
|
|
30975
31121
|
process.exit(1);
|
|
30976
31122
|
}
|
|
30977
31123
|
}
|
|
30978
|
-
function createPlotHandler(disabled) {
|
|
31124
|
+
function createPlotHandler(disabled, plotOpts) {
|
|
30979
31125
|
if (disabled) {
|
|
30980
31126
|
return {
|
|
30981
31127
|
onDrawnow: void 0,
|
|
@@ -30992,7 +31138,7 @@ function createPlotHandler(disabled) {
|
|
|
30992
31138
|
} else {
|
|
30993
31139
|
pendingBatches.push(instructions);
|
|
30994
31140
|
if (!serverStarting) {
|
|
30995
|
-
serverStarting = startPlotServer().then((ps) => {
|
|
31141
|
+
serverStarting = startPlotServer(plotOpts).then((ps) => {
|
|
30996
31142
|
plotServer = ps;
|
|
30997
31143
|
for (const batch of pendingBatches) {
|
|
30998
31144
|
ps.sendInstructions(batch);
|