numbl 0.1.0 → 0.1.1
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 +921 -730
- package/package.json +1 -1
package/dist-cli/cli.js
CHANGED
|
@@ -7,15 +7,17 @@ var __export = (target, all) => {
|
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
import {
|
|
10
|
-
readFileSync as
|
|
10
|
+
readFileSync as readFileSync5,
|
|
11
11
|
readSync as readSync3,
|
|
12
|
-
readdirSync as
|
|
13
|
-
statSync as
|
|
12
|
+
readdirSync as readdirSync3,
|
|
13
|
+
statSync as statSync3,
|
|
14
14
|
existsSync as existsSync2,
|
|
15
15
|
writeFileSync as writeFileSync3,
|
|
16
|
-
appendFileSync as appendFileSync2
|
|
16
|
+
appendFileSync as appendFileSync2,
|
|
17
|
+
mkdirSync as mkdirSync2
|
|
17
18
|
} from "fs";
|
|
18
|
-
import { delimiter, dirname as dirname2, join as
|
|
19
|
+
import { delimiter, dirname as dirname2, join as join5, relative, resolve as resolve2 } from "path";
|
|
20
|
+
import { homedir as homedir3 } from "os";
|
|
19
21
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20
22
|
import { createRequire } from "module";
|
|
21
23
|
import { execSync } from "child_process";
|
|
@@ -28720,6 +28722,20 @@ registerIBuiltin({
|
|
|
28720
28722
|
apply: () => RTV.char("")
|
|
28721
28723
|
})
|
|
28722
28724
|
});
|
|
28725
|
+
registerIBuiltin({
|
|
28726
|
+
name: "isnumbl",
|
|
28727
|
+
resolve: (argTypes) => {
|
|
28728
|
+
if (argTypes.length !== 0) return null;
|
|
28729
|
+
return {
|
|
28730
|
+
outputTypes: [{ kind: "boolean" }],
|
|
28731
|
+
apply: () => true
|
|
28732
|
+
};
|
|
28733
|
+
},
|
|
28734
|
+
jitEmit: (_args, types) => {
|
|
28735
|
+
if (types.length !== 0) return null;
|
|
28736
|
+
return "1";
|
|
28737
|
+
}
|
|
28738
|
+
});
|
|
28723
28739
|
registerIBuiltin({
|
|
28724
28740
|
name: "ishold",
|
|
28725
28741
|
resolve: () => ({
|
|
@@ -29031,6 +29047,7 @@ var SPECIAL_BUILTIN_NAMES = [
|
|
|
29031
29047
|
"mfilename",
|
|
29032
29048
|
"addpath",
|
|
29033
29049
|
"rmpath",
|
|
29050
|
+
"savepath",
|
|
29034
29051
|
"path",
|
|
29035
29052
|
"mkdir",
|
|
29036
29053
|
"websave",
|
|
@@ -30041,6 +30058,10 @@ function registerSpecialBuiltins(rt) {
|
|
|
30041
30058
|
if (nargout >= 1) return RTV.char(rt.searchPaths.join(";"));
|
|
30042
30059
|
return 0;
|
|
30043
30060
|
});
|
|
30061
|
+
registerSpecial("savepath", () => {
|
|
30062
|
+
rt.output("Warning: savepath is a no-op in numbl\n");
|
|
30063
|
+
return 0;
|
|
30064
|
+
});
|
|
30044
30065
|
registerSpecial("input", (_nargout, args) => {
|
|
30045
30066
|
const margs = args.map((a) => ensureRuntimeValue(a));
|
|
30046
30067
|
const prompt = margs.length >= 1 ? toString(margs[0]) : "";
|
|
@@ -35455,18 +35476,57 @@ registerIBuiltin({
|
|
|
35455
35476
|
};
|
|
35456
35477
|
}
|
|
35457
35478
|
});
|
|
35479
|
+
function str2doubleScalar(s) {
|
|
35480
|
+
s = s.trim();
|
|
35481
|
+
if (s === "") return NaN;
|
|
35482
|
+
s = s.replace(/,/g, "");
|
|
35483
|
+
const complexFull = /^([+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)\s*([+-]\s*(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)\s*[ij]$/i;
|
|
35484
|
+
const mFull = complexFull.exec(s);
|
|
35485
|
+
if (mFull) {
|
|
35486
|
+
const real = Number(mFull[1]);
|
|
35487
|
+
const imag = Number(mFull[2].replace(/\s/g, ""));
|
|
35488
|
+
if (!isNaN(real) && !isNaN(imag)) return real;
|
|
35489
|
+
}
|
|
35490
|
+
const pureImag = /^([+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)\s*[ij]$/i;
|
|
35491
|
+
const mImag = pureImag.exec(s);
|
|
35492
|
+
if (mImag) {
|
|
35493
|
+
}
|
|
35494
|
+
const n = Number(s);
|
|
35495
|
+
return isNaN(n) ? NaN : n;
|
|
35496
|
+
}
|
|
35458
35497
|
registerIBuiltin({
|
|
35459
35498
|
name: "str2double",
|
|
35460
35499
|
resolve: (argTypes) => {
|
|
35461
35500
|
if (argTypes.length !== 1) return null;
|
|
35462
|
-
|
|
35463
|
-
|
|
35464
|
-
|
|
35465
|
-
|
|
35466
|
-
|
|
35467
|
-
|
|
35468
|
-
|
|
35469
|
-
|
|
35501
|
+
const t = argTypes[0];
|
|
35502
|
+
if (isTextType(t)) {
|
|
35503
|
+
return {
|
|
35504
|
+
outputTypes: [{ kind: "number" }],
|
|
35505
|
+
apply: (args) => RTV.num(str2doubleScalar(toString(args[0])))
|
|
35506
|
+
};
|
|
35507
|
+
}
|
|
35508
|
+
if (t.kind === "cell") {
|
|
35509
|
+
return {
|
|
35510
|
+
outputTypes: [{ kind: "tensor", isComplex: false }],
|
|
35511
|
+
apply: (args) => {
|
|
35512
|
+
const cell = args[0];
|
|
35513
|
+
if (typeof cell !== "object" || cell === null || cell.kind !== "cell")
|
|
35514
|
+
throw new RuntimeError("str2double: expected cell array");
|
|
35515
|
+
const c = cell;
|
|
35516
|
+
const data = new FloatXArray(c.data.length);
|
|
35517
|
+
for (let i = 0; i < c.data.length; i++) {
|
|
35518
|
+
const el = c.data[i];
|
|
35519
|
+
if (isRuntimeString(el) || isRuntimeChar(el)) {
|
|
35520
|
+
data[i] = str2doubleScalar(toString(el));
|
|
35521
|
+
} else {
|
|
35522
|
+
data[i] = NaN;
|
|
35523
|
+
}
|
|
35524
|
+
}
|
|
35525
|
+
return RTV.tensor(data, c.shape.slice());
|
|
35526
|
+
}
|
|
35527
|
+
};
|
|
35528
|
+
}
|
|
35529
|
+
return null;
|
|
35470
35530
|
}
|
|
35471
35531
|
});
|
|
35472
35532
|
registerIBuiltin({
|
|
@@ -44569,13 +44629,20 @@ function getSourceLine(getSource, file, line) {
|
|
|
44569
44629
|
}
|
|
44570
44630
|
|
|
44571
44631
|
// src/numbl-core/version.ts
|
|
44572
|
-
var NUMBL_VERSION = "0.1.
|
|
44632
|
+
var NUMBL_VERSION = "0.1.1";
|
|
44573
44633
|
|
|
44574
44634
|
// src/cli-repl.ts
|
|
44575
44635
|
import { createInterface } from "readline";
|
|
44576
|
-
import {
|
|
44577
|
-
|
|
44578
|
-
|
|
44636
|
+
import {
|
|
44637
|
+
openSync as openSync2,
|
|
44638
|
+
closeSync as closeSync2,
|
|
44639
|
+
readFileSync as readFileSync4,
|
|
44640
|
+
readSync as readSync2,
|
|
44641
|
+
writeFileSync as writeFileSync2,
|
|
44642
|
+
appendFileSync
|
|
44643
|
+
} from "fs";
|
|
44644
|
+
import { join as join4 } from "path";
|
|
44645
|
+
import { homedir as homedir2 } from "os";
|
|
44579
44646
|
|
|
44580
44647
|
// src/numbl-core/jsUserFunctions.ts
|
|
44581
44648
|
function funcNameFromFile(fileName) {
|
|
@@ -50309,681 +50376,239 @@ ${jitSections.join("\n\n")}` : "// interpreted mode \u2014 no JS generated";
|
|
|
50309
50376
|
}
|
|
50310
50377
|
}
|
|
50311
50378
|
|
|
50312
|
-
// src/cli-
|
|
50313
|
-
|
|
50314
|
-
|
|
50315
|
-
|
|
50379
|
+
// src/cli-fileio.ts
|
|
50380
|
+
import {
|
|
50381
|
+
openSync,
|
|
50382
|
+
closeSync,
|
|
50383
|
+
readSync,
|
|
50384
|
+
writeSync,
|
|
50385
|
+
readFileSync as readFileSync3,
|
|
50386
|
+
writeFileSync,
|
|
50387
|
+
statSync as statSync2,
|
|
50388
|
+
fstatSync,
|
|
50389
|
+
mkdirSync,
|
|
50390
|
+
unlinkSync,
|
|
50391
|
+
readdirSync as readdirSync2,
|
|
50392
|
+
rmSync,
|
|
50393
|
+
rmdirSync
|
|
50394
|
+
} from "fs";
|
|
50395
|
+
import { inflateRawSync } from "zlib";
|
|
50396
|
+
import { execFileSync } from "child_process";
|
|
50397
|
+
import { homedir, tmpdir } from "os";
|
|
50398
|
+
import { join as join3, resolve, dirname, basename } from "path";
|
|
50399
|
+
|
|
50400
|
+
// src/cli-scan.ts
|
|
50401
|
+
import { readFileSync as readFileSync2, readdirSync, statSync } from "fs";
|
|
50402
|
+
import { join as join2 } from "path";
|
|
50403
|
+
function scanMFiles(dirPath, excludeFile) {
|
|
50404
|
+
const files = [];
|
|
50405
|
+
let entries;
|
|
50406
|
+
try {
|
|
50407
|
+
entries = readdirSync(dirPath);
|
|
50408
|
+
} catch {
|
|
50409
|
+
return files;
|
|
50316
50410
|
}
|
|
50317
|
-
|
|
50318
|
-
const
|
|
50319
|
-
|
|
50320
|
-
|
|
50411
|
+
for (const entry of entries) {
|
|
50412
|
+
const fullPath = join2(dirPath, entry);
|
|
50413
|
+
if (excludeFile && fullPath === excludeFile) {
|
|
50414
|
+
continue;
|
|
50415
|
+
}
|
|
50416
|
+
try {
|
|
50417
|
+
const stat = statSync(fullPath);
|
|
50418
|
+
if (stat.isDirectory()) {
|
|
50419
|
+
if (entry.startsWith("@") || entry.startsWith("+") || entry === "private") {
|
|
50420
|
+
files.push(...scanMFiles(fullPath, excludeFile));
|
|
50421
|
+
}
|
|
50422
|
+
} else if (stat.isFile() && (entry.endsWith(".m") || entry.endsWith(".js"))) {
|
|
50423
|
+
const source = readFileSync2(fullPath, "utf-8");
|
|
50424
|
+
files.push({
|
|
50425
|
+
name: fullPath,
|
|
50426
|
+
source
|
|
50427
|
+
});
|
|
50428
|
+
} else if (stat.isFile() && entry.endsWith(".wasm")) {
|
|
50429
|
+
const data = readFileSync2(fullPath);
|
|
50430
|
+
files.push({
|
|
50431
|
+
name: fullPath,
|
|
50432
|
+
source: "",
|
|
50433
|
+
data: new Uint8Array(data)
|
|
50434
|
+
});
|
|
50435
|
+
}
|
|
50436
|
+
} catch (err) {
|
|
50437
|
+
console.warn(
|
|
50438
|
+
`Warning: could not read ${fullPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
50439
|
+
);
|
|
50321
50440
|
}
|
|
50322
|
-
return result;
|
|
50323
|
-
}
|
|
50324
|
-
setEnv(name, value) {
|
|
50325
|
-
process.env[name] = value;
|
|
50326
|
-
}
|
|
50327
|
-
cwd() {
|
|
50328
|
-
return process.cwd();
|
|
50329
|
-
}
|
|
50330
|
-
chdir(dir) {
|
|
50331
|
-
process.chdir(dir);
|
|
50332
|
-
}
|
|
50333
|
-
platform() {
|
|
50334
|
-
return process.platform;
|
|
50335
|
-
}
|
|
50336
|
-
arch() {
|
|
50337
|
-
return process.arch;
|
|
50338
50441
|
}
|
|
50339
|
-
|
|
50442
|
+
return files;
|
|
50443
|
+
}
|
|
50340
50444
|
|
|
50341
|
-
// src/cli-
|
|
50342
|
-
|
|
50343
|
-
|
|
50344
|
-
|
|
50345
|
-
try {
|
|
50346
|
-
const content = readFileSync2(HISTORY_FILE, "utf8");
|
|
50347
|
-
return content.split("\n").filter((line) => line.length > 0).map((line) => line.replace(/\\n/g, "\n").replace(/\\\\/g, "\\"));
|
|
50348
|
-
} catch {
|
|
50349
|
-
return [];
|
|
50445
|
+
// src/cli-fileio.ts
|
|
50446
|
+
function expandTilde(filepath) {
|
|
50447
|
+
if (filepath.startsWith("~/")) {
|
|
50448
|
+
return join3(homedir(), filepath.slice(2));
|
|
50350
50449
|
}
|
|
50450
|
+
return filepath;
|
|
50351
50451
|
}
|
|
50352
|
-
function
|
|
50353
|
-
|
|
50354
|
-
|
|
50355
|
-
|
|
50356
|
-
|
|
50357
|
-
|
|
50358
|
-
|
|
50359
|
-
|
|
50360
|
-
|
|
50361
|
-
|
|
50362
|
-
|
|
50452
|
+
function permissionToFlags(permission) {
|
|
50453
|
+
switch (permission) {
|
|
50454
|
+
case "r":
|
|
50455
|
+
return "r";
|
|
50456
|
+
case "w":
|
|
50457
|
+
return "w";
|
|
50458
|
+
case "a":
|
|
50459
|
+
return "a";
|
|
50460
|
+
case "r+":
|
|
50461
|
+
return "r+";
|
|
50462
|
+
case "w+":
|
|
50463
|
+
return "w+";
|
|
50464
|
+
case "a+":
|
|
50465
|
+
return "a+";
|
|
50466
|
+
default:
|
|
50467
|
+
return permission;
|
|
50363
50468
|
}
|
|
50364
50469
|
}
|
|
50365
|
-
|
|
50366
|
-
|
|
50367
|
-
|
|
50368
|
-
|
|
50369
|
-
|
|
50370
|
-
|
|
50371
|
-
|
|
50372
|
-
|
|
50373
|
-
|
|
50374
|
-
|
|
50375
|
-
|
|
50376
|
-
|
|
50377
|
-
|
|
50378
|
-
|
|
50379
|
-
|
|
50380
|
-
|
|
50381
|
-
|
|
50470
|
+
var READ_CHUNK_SIZE = 8192;
|
|
50471
|
+
var NodeFileIOAdapter = class {
|
|
50472
|
+
nextFid = 3;
|
|
50473
|
+
// 0=stdin, 1=stdout, 2=stderr reserved
|
|
50474
|
+
openFiles = /* @__PURE__ */ new Map();
|
|
50475
|
+
fopen(filename, permission) {
|
|
50476
|
+
try {
|
|
50477
|
+
const flags = permissionToFlags(permission);
|
|
50478
|
+
const fd = openSync(expandTilde(filename), flags);
|
|
50479
|
+
const fid = this.nextFid++;
|
|
50480
|
+
this.openFiles.set(fid, {
|
|
50481
|
+
fd,
|
|
50482
|
+
permission,
|
|
50483
|
+
lastError: "",
|
|
50484
|
+
buffer: "",
|
|
50485
|
+
eof: false,
|
|
50486
|
+
pos: 0
|
|
50487
|
+
});
|
|
50488
|
+
return fid;
|
|
50489
|
+
} catch (e) {
|
|
50490
|
+
return -1;
|
|
50382
50491
|
}
|
|
50383
|
-
|
|
50384
|
-
|
|
50385
|
-
|
|
50386
|
-
|
|
50387
|
-
|
|
50388
|
-
|
|
50389
|
-
|
|
50390
|
-
input: process.stdin,
|
|
50391
|
-
output: process.stdout,
|
|
50392
|
-
prompt: ">> "
|
|
50393
|
-
});
|
|
50394
|
-
rl.prompt();
|
|
50395
|
-
for await (const line of rl) {
|
|
50396
|
-
const trimmed = line.trim();
|
|
50397
|
-
if (trimmed === "exit" || trimmed === "quit") break;
|
|
50398
|
-
if (trimmed === "") {
|
|
50399
|
-
rl.prompt();
|
|
50400
|
-
continue;
|
|
50401
|
-
}
|
|
50402
|
-
try {
|
|
50403
|
-
const result = executeCode(
|
|
50404
|
-
trimmed,
|
|
50405
|
-
{
|
|
50406
|
-
displayResults: true,
|
|
50407
|
-
onOutput: (text) => process.stdout.write(text),
|
|
50408
|
-
onDrawnow,
|
|
50409
|
-
onInput,
|
|
50410
|
-
initialVariableValues: variableValues,
|
|
50411
|
-
initialHoldState: holdState,
|
|
50412
|
-
optimization,
|
|
50413
|
-
system
|
|
50414
|
-
},
|
|
50415
|
-
workspaceFiles,
|
|
50416
|
-
"repl",
|
|
50417
|
-
searchPaths,
|
|
50418
|
-
nativeBridge2
|
|
50419
|
-
);
|
|
50420
|
-
variableValues = result.variableValues;
|
|
50421
|
-
holdState = result.holdState;
|
|
50422
|
-
if (result.searchPaths) {
|
|
50423
|
-
searchPaths.length = 0;
|
|
50424
|
-
searchPaths.push(...result.searchPaths);
|
|
50425
|
-
workspaceFiles.length = 0;
|
|
50426
|
-
workspaceFiles.push(...result.workspaceFiles ?? []);
|
|
50427
|
-
}
|
|
50428
|
-
if (result.plotInstructions.length > 0 && onDrawnow) {
|
|
50429
|
-
onDrawnow(result.plotInstructions);
|
|
50492
|
+
}
|
|
50493
|
+
fclose(fidOrAll) {
|
|
50494
|
+
if (fidOrAll === "all") {
|
|
50495
|
+
for (const [, entry2] of this.openFiles) {
|
|
50496
|
+
try {
|
|
50497
|
+
closeSync(entry2.fd);
|
|
50498
|
+
} catch {
|
|
50430
50499
|
}
|
|
50431
|
-
} catch (error) {
|
|
50432
|
-
const diags = diagnoseErrors(error, trimmed, "repl", workspaceFiles);
|
|
50433
|
-
console.error(formatDiagnostics(diags));
|
|
50434
50500
|
}
|
|
50435
|
-
|
|
50501
|
+
this.openFiles.clear();
|
|
50502
|
+
return 0;
|
|
50436
50503
|
}
|
|
50437
|
-
|
|
50438
|
-
|
|
50439
|
-
|
|
50440
|
-
|
|
50441
|
-
|
|
50442
|
-
|
|
50443
|
-
stdin.resume();
|
|
50444
|
-
stdout.write("\x1B[?2004h");
|
|
50445
|
-
const PS1 = ">> ";
|
|
50446
|
-
const PS2 = " ";
|
|
50447
|
-
let buf = [""];
|
|
50448
|
-
let row = 0;
|
|
50449
|
-
let col = 0;
|
|
50450
|
-
let sRow = 0;
|
|
50451
|
-
const hist = loadHistory();
|
|
50452
|
-
let hIdx = -1;
|
|
50453
|
-
let hStash = "";
|
|
50454
|
-
let hPrefix = "";
|
|
50455
|
-
let pasting = false;
|
|
50456
|
-
let pasteBuf = [];
|
|
50457
|
-
let busy = false;
|
|
50458
|
-
function display() {
|
|
50459
|
-
if (sRow > 0) stdout.write(`\x1B[${sRow}A`);
|
|
50460
|
-
stdout.write("\r\x1B[J");
|
|
50461
|
-
for (let i = 0; i < buf.length; i++) {
|
|
50462
|
-
stdout.write((i === 0 ? PS1 : PS2) + buf[i]);
|
|
50463
|
-
if (i < buf.length - 1) stdout.write("\r\n");
|
|
50504
|
+
const entry = this.openFiles.get(fidOrAll);
|
|
50505
|
+
if (!entry) return -1;
|
|
50506
|
+
try {
|
|
50507
|
+
closeSync(entry.fd);
|
|
50508
|
+
} catch {
|
|
50509
|
+
return -1;
|
|
50464
50510
|
}
|
|
50465
|
-
|
|
50466
|
-
|
|
50467
|
-
const pLen = row === 0 ? PS1.length : PS2.length;
|
|
50468
|
-
stdout.write(`\x1B[${pLen + col + 1}G`);
|
|
50469
|
-
sRow = row;
|
|
50511
|
+
this.openFiles.delete(fidOrAll);
|
|
50512
|
+
return 0;
|
|
50470
50513
|
}
|
|
50471
|
-
|
|
50472
|
-
|
|
50473
|
-
|
|
50474
|
-
|
|
50475
|
-
hStash = "";
|
|
50476
|
-
hPrefix = "";
|
|
50477
|
-
stdout.write(PS1);
|
|
50514
|
+
fgetl(fid) {
|
|
50515
|
+
const entry = this.getEntry(fid);
|
|
50516
|
+
if (!entry) return -1;
|
|
50517
|
+
return this.readLine(entry, false);
|
|
50478
50518
|
}
|
|
50479
|
-
|
|
50480
|
-
|
|
50481
|
-
|
|
50482
|
-
|
|
50519
|
+
fgets(fid) {
|
|
50520
|
+
const entry = this.getEntry(fid);
|
|
50521
|
+
if (!entry) return -1;
|
|
50522
|
+
return this.readLine(entry, true);
|
|
50483
50523
|
}
|
|
50484
|
-
|
|
50485
|
-
|
|
50486
|
-
buf[row] = buf[row].slice(0, col);
|
|
50487
|
-
buf.splice(row + 1, 0, after);
|
|
50488
|
-
row++;
|
|
50489
|
-
col = 0;
|
|
50490
|
-
display();
|
|
50524
|
+
fileread(filename) {
|
|
50525
|
+
return readFileSync3(expandTilde(filename), "utf-8");
|
|
50491
50526
|
}
|
|
50492
|
-
|
|
50493
|
-
const
|
|
50494
|
-
|
|
50495
|
-
if (
|
|
50496
|
-
|
|
50497
|
-
|
|
50498
|
-
|
|
50499
|
-
|
|
50500
|
-
|
|
50527
|
+
feof(fid) {
|
|
50528
|
+
const entry = this.getEntry(fid);
|
|
50529
|
+
if (!entry) return 1;
|
|
50530
|
+
if (entry.buffer.length > 0) return 0;
|
|
50531
|
+
if (entry.eof) return 1;
|
|
50532
|
+
const buf = Buffer.alloc(1);
|
|
50533
|
+
try {
|
|
50534
|
+
const bytesRead = readSync(entry.fd, buf, 0, 1, null);
|
|
50535
|
+
if (bytesRead === 0) {
|
|
50536
|
+
entry.eof = true;
|
|
50537
|
+
return 1;
|
|
50538
|
+
}
|
|
50539
|
+
entry.buffer = buf.toString("utf-8", 0, bytesRead);
|
|
50540
|
+
return 0;
|
|
50541
|
+
} catch {
|
|
50542
|
+
entry.eof = true;
|
|
50543
|
+
return 1;
|
|
50501
50544
|
}
|
|
50502
|
-
|
|
50503
|
-
|
|
50504
|
-
|
|
50505
|
-
|
|
50545
|
+
}
|
|
50546
|
+
ferror(fid) {
|
|
50547
|
+
const entry = this.getEntry(fid);
|
|
50548
|
+
if (!entry) return "Invalid file identifier";
|
|
50549
|
+
return entry.lastError;
|
|
50550
|
+
}
|
|
50551
|
+
fwrite(fid, text) {
|
|
50552
|
+
const entry = this.getEntry(fid);
|
|
50553
|
+
if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
|
|
50554
|
+
try {
|
|
50555
|
+
writeSync(entry.fd, text);
|
|
50556
|
+
entry.lastError = "";
|
|
50557
|
+
} catch (e) {
|
|
50558
|
+
entry.lastError = e instanceof Error ? e.message : String(e);
|
|
50559
|
+
throw e;
|
|
50506
50560
|
}
|
|
50507
|
-
|
|
50508
|
-
|
|
50509
|
-
|
|
50510
|
-
|
|
50511
|
-
|
|
50512
|
-
|
|
50561
|
+
}
|
|
50562
|
+
freadBytes(fid, count) {
|
|
50563
|
+
const entry = this.getEntry(fid);
|
|
50564
|
+
if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
|
|
50565
|
+
if (entry.buffer.length > 0) {
|
|
50566
|
+
entry.buffer = "";
|
|
50567
|
+
}
|
|
50568
|
+
const buf = Buffer.alloc(count);
|
|
50513
50569
|
try {
|
|
50514
|
-
const
|
|
50515
|
-
|
|
50516
|
-
|
|
50517
|
-
|
|
50518
|
-
|
|
50519
|
-
|
|
50520
|
-
|
|
50521
|
-
|
|
50522
|
-
|
|
50523
|
-
|
|
50524
|
-
},
|
|
50525
|
-
workspaceFiles,
|
|
50526
|
-
"repl",
|
|
50527
|
-
searchPaths,
|
|
50528
|
-
nativeBridge2
|
|
50529
|
-
);
|
|
50530
|
-
variableValues = result.variableValues;
|
|
50531
|
-
holdState = result.holdState;
|
|
50532
|
-
if (result.searchPaths) {
|
|
50533
|
-
searchPaths.length = 0;
|
|
50534
|
-
searchPaths.push(...result.searchPaths);
|
|
50535
|
-
workspaceFiles.length = 0;
|
|
50536
|
-
workspaceFiles.push(...result.workspaceFiles ?? []);
|
|
50537
|
-
}
|
|
50538
|
-
if (result.plotInstructions.length > 0 && onDrawnow) {
|
|
50539
|
-
onDrawnow(result.plotInstructions);
|
|
50540
|
-
}
|
|
50541
|
-
} catch (error) {
|
|
50542
|
-
const diags = diagnoseErrors(error, code, "repl", workspaceFiles);
|
|
50543
|
-
console.error(formatDiagnostics(diags));
|
|
50570
|
+
const bytesRead = readSync(entry.fd, buf, 0, count, entry.pos);
|
|
50571
|
+
entry.pos += bytesRead;
|
|
50572
|
+
if (bytesRead === 0) entry.eof = true;
|
|
50573
|
+
else if (bytesRead < count) entry.eof = true;
|
|
50574
|
+
entry.lastError = "";
|
|
50575
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, bytesRead);
|
|
50576
|
+
} catch (e) {
|
|
50577
|
+
entry.lastError = e instanceof Error ? e.message : String(e);
|
|
50578
|
+
entry.eof = true;
|
|
50579
|
+
return new Uint8Array(0);
|
|
50544
50580
|
}
|
|
50545
|
-
stdin.setRawMode(true);
|
|
50546
|
-
busy = false;
|
|
50547
|
-
resetInput();
|
|
50548
50581
|
}
|
|
50549
|
-
|
|
50550
|
-
|
|
50551
|
-
|
|
50552
|
-
|
|
50553
|
-
|
|
50554
|
-
|
|
50555
|
-
|
|
50556
|
-
|
|
50557
|
-
|
|
50558
|
-
|
|
50559
|
-
|
|
50560
|
-
}
|
|
50561
|
-
row += lines.length - 1;
|
|
50562
|
-
col = buf[row].length;
|
|
50563
|
-
buf[row] += after;
|
|
50582
|
+
fwriteBytes(fid, data) {
|
|
50583
|
+
const entry = this.getEntry(fid);
|
|
50584
|
+
if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
|
|
50585
|
+
try {
|
|
50586
|
+
const written = writeSync(entry.fd, data, 0, data.length, entry.pos);
|
|
50587
|
+
entry.pos += written;
|
|
50588
|
+
entry.lastError = "";
|
|
50589
|
+
return written;
|
|
50590
|
+
} catch (e) {
|
|
50591
|
+
entry.lastError = e instanceof Error ? e.message : String(e);
|
|
50592
|
+
throw e;
|
|
50564
50593
|
}
|
|
50565
|
-
display();
|
|
50566
50594
|
}
|
|
50567
|
-
|
|
50568
|
-
|
|
50569
|
-
if (
|
|
50570
|
-
|
|
50571
|
-
|
|
50572
|
-
|
|
50573
|
-
if (
|
|
50574
|
-
|
|
50575
|
-
|
|
50576
|
-
|
|
50577
|
-
break;
|
|
50578
|
-
}
|
|
50579
|
-
}
|
|
50580
|
-
if (hIdx === -1) return;
|
|
50581
|
-
} else {
|
|
50582
|
-
hIdx = hist.length - 1;
|
|
50583
|
-
}
|
|
50584
|
-
} else {
|
|
50585
|
-
let found = false;
|
|
50586
|
-
if (dir < 0) {
|
|
50587
|
-
for (let k = hIdx - 1; k >= 0; k--) {
|
|
50588
|
-
if (hPrefix.length === 0 || hist[k].startsWith(hPrefix)) {
|
|
50589
|
-
hIdx = k;
|
|
50590
|
-
found = true;
|
|
50591
|
-
break;
|
|
50592
|
-
}
|
|
50593
|
-
}
|
|
50594
|
-
if (!found) return;
|
|
50595
|
+
fseek(fid, offset, origin) {
|
|
50596
|
+
const entry = this.getEntry(fid);
|
|
50597
|
+
if (!entry) return -1;
|
|
50598
|
+
entry.buffer = "";
|
|
50599
|
+
entry.eof = false;
|
|
50600
|
+
try {
|
|
50601
|
+
if (origin === -1) {
|
|
50602
|
+
entry.pos = offset;
|
|
50603
|
+
} else if (origin === 0) {
|
|
50604
|
+
entry.pos += offset;
|
|
50595
50605
|
} else {
|
|
50596
|
-
|
|
50597
|
-
|
|
50598
|
-
hIdx = k;
|
|
50599
|
-
found = true;
|
|
50600
|
-
break;
|
|
50601
|
-
}
|
|
50602
|
-
}
|
|
50603
|
-
if (!found) {
|
|
50604
|
-
buf = hStash.split("\n");
|
|
50605
|
-
hIdx = -1;
|
|
50606
|
-
row = buf.length - 1;
|
|
50607
|
-
col = buf[row].length;
|
|
50608
|
-
display();
|
|
50609
|
-
return;
|
|
50610
|
-
}
|
|
50606
|
+
const size = fstatSync(entry.fd).size;
|
|
50607
|
+
entry.pos = size + offset;
|
|
50611
50608
|
}
|
|
50612
|
-
|
|
50613
|
-
|
|
50614
|
-
|
|
50615
|
-
col = buf[row].length;
|
|
50616
|
-
display();
|
|
50617
|
-
}
|
|
50618
|
-
function handleCSI(seq) {
|
|
50619
|
-
switch (seq) {
|
|
50620
|
-
case "A":
|
|
50621
|
-
if (buf.length > 1 && row > 0) {
|
|
50622
|
-
row--;
|
|
50623
|
-
col = Math.min(col, buf[row].length);
|
|
50624
|
-
display();
|
|
50625
|
-
} else {
|
|
50626
|
-
navHistory(-1);
|
|
50627
|
-
}
|
|
50628
|
-
break;
|
|
50629
|
-
case "B":
|
|
50630
|
-
if (buf.length > 1 && row < buf.length - 1) {
|
|
50631
|
-
row++;
|
|
50632
|
-
col = Math.min(col, buf[row].length);
|
|
50633
|
-
display();
|
|
50634
|
-
} else {
|
|
50635
|
-
navHistory(1);
|
|
50636
|
-
}
|
|
50637
|
-
break;
|
|
50638
|
-
case "C":
|
|
50639
|
-
if (col < buf[row].length) {
|
|
50640
|
-
col++;
|
|
50641
|
-
display();
|
|
50642
|
-
} else if (row < buf.length - 1) {
|
|
50643
|
-
row++;
|
|
50644
|
-
col = 0;
|
|
50645
|
-
display();
|
|
50646
|
-
}
|
|
50647
|
-
break;
|
|
50648
|
-
case "D":
|
|
50649
|
-
if (col > 0) {
|
|
50650
|
-
col--;
|
|
50651
|
-
display();
|
|
50652
|
-
} else if (row > 0) {
|
|
50653
|
-
row--;
|
|
50654
|
-
col = buf[row].length;
|
|
50655
|
-
display();
|
|
50656
|
-
}
|
|
50657
|
-
break;
|
|
50658
|
-
case "H":
|
|
50659
|
-
// Home
|
|
50660
|
-
case "1~":
|
|
50661
|
-
col = 0;
|
|
50662
|
-
display();
|
|
50663
|
-
break;
|
|
50664
|
-
case "F":
|
|
50665
|
-
// End
|
|
50666
|
-
case "4~":
|
|
50667
|
-
col = buf[row].length;
|
|
50668
|
-
display();
|
|
50669
|
-
break;
|
|
50670
|
-
case "3~":
|
|
50671
|
-
if (col < buf[row].length) {
|
|
50672
|
-
buf[row] = buf[row].slice(0, col) + buf[row].slice(col + 1);
|
|
50673
|
-
display();
|
|
50674
|
-
} else if (row < buf.length - 1) {
|
|
50675
|
-
buf[row] += buf[row + 1];
|
|
50676
|
-
buf.splice(row + 1, 1);
|
|
50677
|
-
display();
|
|
50678
|
-
}
|
|
50679
|
-
break;
|
|
50680
|
-
case "13;2u":
|
|
50681
|
-
insertNewline();
|
|
50682
|
-
break;
|
|
50683
|
-
}
|
|
50684
|
-
}
|
|
50685
|
-
resetInput();
|
|
50686
|
-
return new Promise((resolve3) => {
|
|
50687
|
-
stdin.on("data", (chunk) => {
|
|
50688
|
-
if (busy) return;
|
|
50689
|
-
const data = chunk.toString("utf8");
|
|
50690
|
-
let i = 0;
|
|
50691
|
-
while (i < data.length) {
|
|
50692
|
-
if (busy) return;
|
|
50693
|
-
if (data.startsWith("\x1B[200~", i)) {
|
|
50694
|
-
pasting = true;
|
|
50695
|
-
pasteBuf = [];
|
|
50696
|
-
i += 6;
|
|
50697
|
-
continue;
|
|
50698
|
-
}
|
|
50699
|
-
if (data.startsWith("\x1B[201~", i)) {
|
|
50700
|
-
pasting = false;
|
|
50701
|
-
handlePaste(pasteBuf.join(""));
|
|
50702
|
-
i += 6;
|
|
50703
|
-
continue;
|
|
50704
|
-
}
|
|
50705
|
-
if (pasting) {
|
|
50706
|
-
const end = data.indexOf("\x1B[201~", i);
|
|
50707
|
-
if (end >= 0) {
|
|
50708
|
-
pasteBuf.push(data.slice(i, end));
|
|
50709
|
-
pasting = false;
|
|
50710
|
-
handlePaste(pasteBuf.join(""));
|
|
50711
|
-
i = end + 6;
|
|
50712
|
-
} else {
|
|
50713
|
-
pasteBuf.push(data.slice(i));
|
|
50714
|
-
i = data.length;
|
|
50715
|
-
}
|
|
50716
|
-
continue;
|
|
50717
|
-
}
|
|
50718
|
-
if (data[i] === "\x1B" && i + 1 < data.length && (data[i + 1] === "\r" || data[i + 1] === "\n")) {
|
|
50719
|
-
insertNewline();
|
|
50720
|
-
i += 2;
|
|
50721
|
-
continue;
|
|
50722
|
-
}
|
|
50723
|
-
if (data.startsWith("\x1B[", i)) {
|
|
50724
|
-
let j = i + 2;
|
|
50725
|
-
while (j < data.length && (data.charCodeAt(j) < 64 || data.charCodeAt(j) > 126))
|
|
50726
|
-
j++;
|
|
50727
|
-
if (j >= data.length) {
|
|
50728
|
-
i = data.length;
|
|
50729
|
-
continue;
|
|
50730
|
-
}
|
|
50731
|
-
handleCSI(data.slice(i + 2, j + 1));
|
|
50732
|
-
i = j + 1;
|
|
50733
|
-
continue;
|
|
50734
|
-
}
|
|
50735
|
-
if (data[i] === "\x1B") {
|
|
50736
|
-
i++;
|
|
50737
|
-
continue;
|
|
50738
|
-
}
|
|
50739
|
-
const code = data.charCodeAt(i);
|
|
50740
|
-
i++;
|
|
50741
|
-
if (code === 13 || code === 10) {
|
|
50742
|
-
try {
|
|
50743
|
-
exec2();
|
|
50744
|
-
} catch (err) {
|
|
50745
|
-
console.error("Unexpected REPL error:", err);
|
|
50746
|
-
busy = false;
|
|
50747
|
-
resetInput();
|
|
50748
|
-
}
|
|
50749
|
-
} else if (code === 127 || code === 8) {
|
|
50750
|
-
if (col > 0) {
|
|
50751
|
-
buf[row] = buf[row].slice(0, col - 1) + buf[row].slice(col);
|
|
50752
|
-
col--;
|
|
50753
|
-
display();
|
|
50754
|
-
} else if (row > 0) {
|
|
50755
|
-
col = buf[row - 1].length;
|
|
50756
|
-
buf[row - 1] += buf[row];
|
|
50757
|
-
buf.splice(row, 1);
|
|
50758
|
-
row--;
|
|
50759
|
-
display();
|
|
50760
|
-
}
|
|
50761
|
-
} else if (code === 1) {
|
|
50762
|
-
col = 0;
|
|
50763
|
-
display();
|
|
50764
|
-
} else if (code === 5) {
|
|
50765
|
-
col = buf[row].length;
|
|
50766
|
-
display();
|
|
50767
|
-
} else if (code === 11) {
|
|
50768
|
-
buf[row] = buf[row].slice(0, col);
|
|
50769
|
-
display();
|
|
50770
|
-
} else if (code === 21) {
|
|
50771
|
-
buf[row] = buf[row].slice(col);
|
|
50772
|
-
col = 0;
|
|
50773
|
-
display();
|
|
50774
|
-
} else if (code === 3) {
|
|
50775
|
-
const below = buf.length - 1 - sRow;
|
|
50776
|
-
if (below > 0) stdout.write(`\x1B[${below}B`);
|
|
50777
|
-
stdout.write("\r\n^C\r\n");
|
|
50778
|
-
sRow = 0;
|
|
50779
|
-
resetInput();
|
|
50780
|
-
} else if (code === 4) {
|
|
50781
|
-
if (buf.length === 1 && buf[0] === "") {
|
|
50782
|
-
stdout.write("\r\n");
|
|
50783
|
-
cleanup();
|
|
50784
|
-
resolve3();
|
|
50785
|
-
return;
|
|
50786
|
-
}
|
|
50787
|
-
} else if (code === 12) {
|
|
50788
|
-
stdout.write("\x1B[2J\x1B[H");
|
|
50789
|
-
sRow = 0;
|
|
50790
|
-
display();
|
|
50791
|
-
} else if (code >= 32) {
|
|
50792
|
-
buf[row] = buf[row].slice(0, col) + data[i - 1] + buf[row].slice(col);
|
|
50793
|
-
col++;
|
|
50794
|
-
display();
|
|
50795
|
-
}
|
|
50796
|
-
}
|
|
50797
|
-
});
|
|
50798
|
-
});
|
|
50799
|
-
}
|
|
50800
|
-
|
|
50801
|
-
// src/cli-fileio.ts
|
|
50802
|
-
import {
|
|
50803
|
-
openSync,
|
|
50804
|
-
closeSync,
|
|
50805
|
-
readSync as readSync2,
|
|
50806
|
-
writeSync,
|
|
50807
|
-
readFileSync as readFileSync3,
|
|
50808
|
-
writeFileSync as writeFileSync2,
|
|
50809
|
-
statSync,
|
|
50810
|
-
fstatSync,
|
|
50811
|
-
mkdirSync,
|
|
50812
|
-
unlinkSync,
|
|
50813
|
-
readdirSync,
|
|
50814
|
-
rmSync,
|
|
50815
|
-
rmdirSync
|
|
50816
|
-
} from "fs";
|
|
50817
|
-
import { inflateRawSync } from "zlib";
|
|
50818
|
-
import { execFileSync } from "child_process";
|
|
50819
|
-
import { homedir as homedir2, tmpdir } from "os";
|
|
50820
|
-
import { join as join3, resolve, dirname, basename } from "path";
|
|
50821
|
-
function expandTilde(filepath) {
|
|
50822
|
-
if (filepath.startsWith("~/")) {
|
|
50823
|
-
return join3(homedir2(), filepath.slice(2));
|
|
50824
|
-
}
|
|
50825
|
-
return filepath;
|
|
50826
|
-
}
|
|
50827
|
-
function permissionToFlags(permission) {
|
|
50828
|
-
switch (permission) {
|
|
50829
|
-
case "r":
|
|
50830
|
-
return "r";
|
|
50831
|
-
case "w":
|
|
50832
|
-
return "w";
|
|
50833
|
-
case "a":
|
|
50834
|
-
return "a";
|
|
50835
|
-
case "r+":
|
|
50836
|
-
return "r+";
|
|
50837
|
-
case "w+":
|
|
50838
|
-
return "w+";
|
|
50839
|
-
case "a+":
|
|
50840
|
-
return "a+";
|
|
50841
|
-
default:
|
|
50842
|
-
return permission;
|
|
50843
|
-
}
|
|
50844
|
-
}
|
|
50845
|
-
var READ_CHUNK_SIZE = 8192;
|
|
50846
|
-
var NodeFileIOAdapter = class {
|
|
50847
|
-
nextFid = 3;
|
|
50848
|
-
// 0=stdin, 1=stdout, 2=stderr reserved
|
|
50849
|
-
openFiles = /* @__PURE__ */ new Map();
|
|
50850
|
-
fopen(filename, permission) {
|
|
50851
|
-
try {
|
|
50852
|
-
const flags = permissionToFlags(permission);
|
|
50853
|
-
const fd = openSync(expandTilde(filename), flags);
|
|
50854
|
-
const fid = this.nextFid++;
|
|
50855
|
-
this.openFiles.set(fid, {
|
|
50856
|
-
fd,
|
|
50857
|
-
permission,
|
|
50858
|
-
lastError: "",
|
|
50859
|
-
buffer: "",
|
|
50860
|
-
eof: false,
|
|
50861
|
-
pos: 0
|
|
50862
|
-
});
|
|
50863
|
-
return fid;
|
|
50864
|
-
} catch (e) {
|
|
50865
|
-
return -1;
|
|
50866
|
-
}
|
|
50867
|
-
}
|
|
50868
|
-
fclose(fidOrAll) {
|
|
50869
|
-
if (fidOrAll === "all") {
|
|
50870
|
-
for (const [, entry2] of this.openFiles) {
|
|
50871
|
-
try {
|
|
50872
|
-
closeSync(entry2.fd);
|
|
50873
|
-
} catch {
|
|
50874
|
-
}
|
|
50875
|
-
}
|
|
50876
|
-
this.openFiles.clear();
|
|
50877
|
-
return 0;
|
|
50878
|
-
}
|
|
50879
|
-
const entry = this.openFiles.get(fidOrAll);
|
|
50880
|
-
if (!entry) return -1;
|
|
50881
|
-
try {
|
|
50882
|
-
closeSync(entry.fd);
|
|
50883
|
-
} catch {
|
|
50884
|
-
return -1;
|
|
50885
|
-
}
|
|
50886
|
-
this.openFiles.delete(fidOrAll);
|
|
50887
|
-
return 0;
|
|
50888
|
-
}
|
|
50889
|
-
fgetl(fid) {
|
|
50890
|
-
const entry = this.getEntry(fid);
|
|
50891
|
-
if (!entry) return -1;
|
|
50892
|
-
return this.readLine(entry, false);
|
|
50893
|
-
}
|
|
50894
|
-
fgets(fid) {
|
|
50895
|
-
const entry = this.getEntry(fid);
|
|
50896
|
-
if (!entry) return -1;
|
|
50897
|
-
return this.readLine(entry, true);
|
|
50898
|
-
}
|
|
50899
|
-
fileread(filename) {
|
|
50900
|
-
return readFileSync3(expandTilde(filename), "utf-8");
|
|
50901
|
-
}
|
|
50902
|
-
feof(fid) {
|
|
50903
|
-
const entry = this.getEntry(fid);
|
|
50904
|
-
if (!entry) return 1;
|
|
50905
|
-
if (entry.buffer.length > 0) return 0;
|
|
50906
|
-
if (entry.eof) return 1;
|
|
50907
|
-
const buf = Buffer.alloc(1);
|
|
50908
|
-
try {
|
|
50909
|
-
const bytesRead = readSync2(entry.fd, buf, 0, 1, null);
|
|
50910
|
-
if (bytesRead === 0) {
|
|
50911
|
-
entry.eof = true;
|
|
50912
|
-
return 1;
|
|
50913
|
-
}
|
|
50914
|
-
entry.buffer = buf.toString("utf-8", 0, bytesRead);
|
|
50915
|
-
return 0;
|
|
50916
|
-
} catch {
|
|
50917
|
-
entry.eof = true;
|
|
50918
|
-
return 1;
|
|
50919
|
-
}
|
|
50920
|
-
}
|
|
50921
|
-
ferror(fid) {
|
|
50922
|
-
const entry = this.getEntry(fid);
|
|
50923
|
-
if (!entry) return "Invalid file identifier";
|
|
50924
|
-
return entry.lastError;
|
|
50925
|
-
}
|
|
50926
|
-
fwrite(fid, text) {
|
|
50927
|
-
const entry = this.getEntry(fid);
|
|
50928
|
-
if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
|
|
50929
|
-
try {
|
|
50930
|
-
writeSync(entry.fd, text);
|
|
50931
|
-
entry.lastError = "";
|
|
50932
|
-
} catch (e) {
|
|
50933
|
-
entry.lastError = e instanceof Error ? e.message : String(e);
|
|
50934
|
-
throw e;
|
|
50935
|
-
}
|
|
50936
|
-
}
|
|
50937
|
-
freadBytes(fid, count) {
|
|
50938
|
-
const entry = this.getEntry(fid);
|
|
50939
|
-
if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
|
|
50940
|
-
if (entry.buffer.length > 0) {
|
|
50941
|
-
entry.buffer = "";
|
|
50942
|
-
}
|
|
50943
|
-
const buf = Buffer.alloc(count);
|
|
50944
|
-
try {
|
|
50945
|
-
const bytesRead = readSync2(entry.fd, buf, 0, count, entry.pos);
|
|
50946
|
-
entry.pos += bytesRead;
|
|
50947
|
-
if (bytesRead === 0) entry.eof = true;
|
|
50948
|
-
else if (bytesRead < count) entry.eof = true;
|
|
50949
|
-
entry.lastError = "";
|
|
50950
|
-
return new Uint8Array(buf.buffer, buf.byteOffset, bytesRead);
|
|
50951
|
-
} catch (e) {
|
|
50952
|
-
entry.lastError = e instanceof Error ? e.message : String(e);
|
|
50953
|
-
entry.eof = true;
|
|
50954
|
-
return new Uint8Array(0);
|
|
50955
|
-
}
|
|
50956
|
-
}
|
|
50957
|
-
fwriteBytes(fid, data) {
|
|
50958
|
-
const entry = this.getEntry(fid);
|
|
50959
|
-
if (!entry) throw new Error(`Invalid file identifier: ${fid}`);
|
|
50960
|
-
try {
|
|
50961
|
-
const written = writeSync(entry.fd, data, 0, data.length, entry.pos);
|
|
50962
|
-
entry.pos += written;
|
|
50963
|
-
entry.lastError = "";
|
|
50964
|
-
return written;
|
|
50965
|
-
} catch (e) {
|
|
50966
|
-
entry.lastError = e instanceof Error ? e.message : String(e);
|
|
50967
|
-
throw e;
|
|
50968
|
-
}
|
|
50969
|
-
}
|
|
50970
|
-
fseek(fid, offset, origin) {
|
|
50971
|
-
const entry = this.getEntry(fid);
|
|
50972
|
-
if (!entry) return -1;
|
|
50973
|
-
entry.buffer = "";
|
|
50974
|
-
entry.eof = false;
|
|
50975
|
-
try {
|
|
50976
|
-
if (origin === -1) {
|
|
50977
|
-
entry.pos = offset;
|
|
50978
|
-
} else if (origin === 0) {
|
|
50979
|
-
entry.pos += offset;
|
|
50980
|
-
} else {
|
|
50981
|
-
const size = fstatSync(entry.fd).size;
|
|
50982
|
-
entry.pos = size + offset;
|
|
50983
|
-
}
|
|
50984
|
-
return 0;
|
|
50985
|
-
} catch {
|
|
50986
|
-
return -1;
|
|
50609
|
+
return 0;
|
|
50610
|
+
} catch {
|
|
50611
|
+
return -1;
|
|
50987
50612
|
}
|
|
50988
50613
|
}
|
|
50989
50614
|
ftell(fid) {
|
|
@@ -50999,7 +50624,7 @@ var NodeFileIOAdapter = class {
|
|
|
50999
50624
|
}
|
|
51000
50625
|
existsPath(path) {
|
|
51001
50626
|
try {
|
|
51002
|
-
const s =
|
|
50627
|
+
const s = statSync2(expandTilde(path));
|
|
51003
50628
|
return s.isDirectory() ? "dir" : "file";
|
|
51004
50629
|
} catch {
|
|
51005
50630
|
return null;
|
|
@@ -51077,7 +50702,7 @@ var NodeFileIOAdapter = class {
|
|
|
51077
50702
|
);
|
|
51078
50703
|
let entries;
|
|
51079
50704
|
try {
|
|
51080
|
-
entries =
|
|
50705
|
+
entries = readdirSync2(dir);
|
|
51081
50706
|
} catch {
|
|
51082
50707
|
return;
|
|
51083
50708
|
}
|
|
@@ -51150,7 +50775,7 @@ var NodeFileIOAdapter = class {
|
|
|
51150
50775
|
}
|
|
51151
50776
|
const outPath = join3(dest, entryName);
|
|
51152
50777
|
mkdirSync(dirname(outPath), { recursive: true });
|
|
51153
|
-
|
|
50778
|
+
writeFileSync(outPath, fileData);
|
|
51154
50779
|
extracted.push(outPath);
|
|
51155
50780
|
}
|
|
51156
50781
|
return extracted;
|
|
@@ -51164,7 +50789,7 @@ var NodeFileIOAdapter = class {
|
|
|
51164
50789
|
return this.listDirGlob(p2);
|
|
51165
50790
|
}
|
|
51166
50791
|
try {
|
|
51167
|
-
const s =
|
|
50792
|
+
const s = statSync2(p2);
|
|
51168
50793
|
if (s.isDirectory()) {
|
|
51169
50794
|
const absDir = resolve(p2);
|
|
51170
50795
|
const results = [];
|
|
@@ -51176,7 +50801,7 @@ var NodeFileIOAdapter = class {
|
|
|
51176
50801
|
mtimeMs: s.mtimeMs
|
|
51177
50802
|
});
|
|
51178
50803
|
try {
|
|
51179
|
-
const parentStat =
|
|
50804
|
+
const parentStat = statSync2(resolve(absDir, ".."));
|
|
51180
50805
|
results.push({
|
|
51181
50806
|
name: "..",
|
|
51182
50807
|
folder: absDir,
|
|
@@ -51193,10 +50818,10 @@ var NodeFileIOAdapter = class {
|
|
|
51193
50818
|
mtimeMs: 0
|
|
51194
50819
|
});
|
|
51195
50820
|
}
|
|
51196
|
-
const entries =
|
|
50821
|
+
const entries = readdirSync2(absDir);
|
|
51197
50822
|
for (const entry of entries) {
|
|
51198
50823
|
try {
|
|
51199
|
-
const es =
|
|
50824
|
+
const es = statSync2(join3(absDir, entry));
|
|
51200
50825
|
results.push({
|
|
51201
50826
|
name: entry,
|
|
51202
50827
|
folder: absDir,
|
|
@@ -51238,14 +50863,14 @@ var NodeFileIOAdapter = class {
|
|
|
51238
50863
|
const results = [];
|
|
51239
50864
|
let entries;
|
|
51240
50865
|
try {
|
|
51241
|
-
entries =
|
|
50866
|
+
entries = readdirSync2(absDir);
|
|
51242
50867
|
} catch {
|
|
51243
50868
|
return [];
|
|
51244
50869
|
}
|
|
51245
50870
|
for (const entry of entries) {
|
|
51246
50871
|
if (re2.test(entry)) {
|
|
51247
50872
|
try {
|
|
51248
|
-
const es =
|
|
50873
|
+
const es = statSync2(join3(absDir, entry));
|
|
51249
50874
|
results.push({
|
|
51250
50875
|
name: entry,
|
|
51251
50876
|
folder: absDir,
|
|
@@ -51270,7 +50895,7 @@ var NodeFileIOAdapter = class {
|
|
|
51270
50895
|
const results = [];
|
|
51271
50896
|
const walkDir = (dir) => {
|
|
51272
50897
|
try {
|
|
51273
|
-
const ds =
|
|
50898
|
+
const ds = statSync2(dir);
|
|
51274
50899
|
results.push({
|
|
51275
50900
|
name: ".",
|
|
51276
50901
|
folder: dir,
|
|
@@ -51288,7 +50913,7 @@ var NodeFileIOAdapter = class {
|
|
|
51288
50913
|
});
|
|
51289
50914
|
}
|
|
51290
50915
|
try {
|
|
51291
|
-
const ps =
|
|
50916
|
+
const ps = statSync2(resolve(dir, ".."));
|
|
51292
50917
|
results.push({
|
|
51293
50918
|
name: "..",
|
|
51294
50919
|
folder: dir,
|
|
@@ -51307,14 +50932,14 @@ var NodeFileIOAdapter = class {
|
|
|
51307
50932
|
}
|
|
51308
50933
|
let entries;
|
|
51309
50934
|
try {
|
|
51310
|
-
entries =
|
|
50935
|
+
entries = readdirSync2(dir);
|
|
51311
50936
|
} catch {
|
|
51312
50937
|
return;
|
|
51313
50938
|
}
|
|
51314
50939
|
const subdirs = [];
|
|
51315
50940
|
for (const entry of entries) {
|
|
51316
50941
|
try {
|
|
51317
|
-
const es =
|
|
50942
|
+
const es = statSync2(join3(dir, entry));
|
|
51318
50943
|
results.push({
|
|
51319
50944
|
name: entry,
|
|
51320
50945
|
folder: dir,
|
|
@@ -51347,7 +50972,7 @@ var NodeFileIOAdapter = class {
|
|
|
51347
50972
|
const buf = Buffer.alloc(READ_CHUNK_SIZE);
|
|
51348
50973
|
let bytesRead;
|
|
51349
50974
|
try {
|
|
51350
|
-
bytesRead =
|
|
50975
|
+
bytesRead = readSync(entry.fd, buf, 0, READ_CHUNK_SIZE, null);
|
|
51351
50976
|
entry.lastError = "";
|
|
51352
50977
|
} catch (e) {
|
|
51353
50978
|
entry.lastError = e instanceof Error ? e.message : String(e);
|
|
@@ -51375,11 +51000,573 @@ var NodeFileIOAdapter = class {
|
|
|
51375
51000
|
}
|
|
51376
51001
|
};
|
|
51377
51002
|
|
|
51003
|
+
// src/cli-system.ts
|
|
51004
|
+
var NodeSystemAdapter = class {
|
|
51005
|
+
getEnv(name) {
|
|
51006
|
+
return process.env[name];
|
|
51007
|
+
}
|
|
51008
|
+
getAllEnv() {
|
|
51009
|
+
const result = {};
|
|
51010
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
51011
|
+
if (v !== void 0) result[k] = v;
|
|
51012
|
+
}
|
|
51013
|
+
return result;
|
|
51014
|
+
}
|
|
51015
|
+
setEnv(name, value) {
|
|
51016
|
+
process.env[name] = value;
|
|
51017
|
+
}
|
|
51018
|
+
cwd() {
|
|
51019
|
+
return process.cwd();
|
|
51020
|
+
}
|
|
51021
|
+
chdir(dir) {
|
|
51022
|
+
process.chdir(dir);
|
|
51023
|
+
}
|
|
51024
|
+
platform() {
|
|
51025
|
+
return process.platform;
|
|
51026
|
+
}
|
|
51027
|
+
arch() {
|
|
51028
|
+
return process.arch;
|
|
51029
|
+
}
|
|
51030
|
+
};
|
|
51031
|
+
|
|
51032
|
+
// src/cli-repl.ts
|
|
51033
|
+
var HISTORY_FILE = join4(homedir2(), ".numbl_history");
|
|
51034
|
+
var HISTORY_MAX = 1e3;
|
|
51035
|
+
function loadHistory() {
|
|
51036
|
+
try {
|
|
51037
|
+
const content = readFileSync4(HISTORY_FILE, "utf8");
|
|
51038
|
+
return content.split("\n").filter((line) => line.length > 0).map((line) => line.replace(/\\n/g, "\n").replace(/\\\\/g, "\\"));
|
|
51039
|
+
} catch {
|
|
51040
|
+
return [];
|
|
51041
|
+
}
|
|
51042
|
+
}
|
|
51043
|
+
function saveHistoryEntry(entry, hist) {
|
|
51044
|
+
try {
|
|
51045
|
+
if (hist.length <= HISTORY_MAX) {
|
|
51046
|
+
const encoded = entry.replace(/\\/g, "\\\\").replace(/\n/g, "\\n");
|
|
51047
|
+
appendFileSync(HISTORY_FILE, encoded + "\n", "utf8");
|
|
51048
|
+
} else {
|
|
51049
|
+
const trimmed = hist.slice(-HISTORY_MAX);
|
|
51050
|
+
const content = trimmed.map((e) => e.replace(/\\/g, "\\\\").replace(/\n/g, "\\n")).join("\n") + "\n";
|
|
51051
|
+
writeFileSync2(HISTORY_FILE, content, "utf8");
|
|
51052
|
+
}
|
|
51053
|
+
} catch {
|
|
51054
|
+
}
|
|
51055
|
+
}
|
|
51056
|
+
async function runRepl(initialWorkspaceFiles, onDrawnow, initialSearchPaths, nativeBridge2, optimization) {
|
|
51057
|
+
let variableValues = {};
|
|
51058
|
+
let holdState = false;
|
|
51059
|
+
const workspaceFiles = [...initialWorkspaceFiles];
|
|
51060
|
+
const searchPaths = [...initialSearchPaths ?? []];
|
|
51061
|
+
const fileIO = new NodeFileIOAdapter();
|
|
51062
|
+
const system = new NodeSystemAdapter();
|
|
51063
|
+
const onInput = (prompt) => {
|
|
51064
|
+
process.stdout.write(prompt);
|
|
51065
|
+
const ttyFd = openSync2("/dev/tty", "r");
|
|
51066
|
+
try {
|
|
51067
|
+
const buf2 = Buffer.alloc(1);
|
|
51068
|
+
let line = "";
|
|
51069
|
+
while (true) {
|
|
51070
|
+
const bytesRead = readSync2(ttyFd, buf2, 0, 1, null);
|
|
51071
|
+
if (bytesRead === 0) break;
|
|
51072
|
+
const ch = buf2.toString("utf8");
|
|
51073
|
+
if (ch === "\n") break;
|
|
51074
|
+
if (ch === "\r") continue;
|
|
51075
|
+
line += ch;
|
|
51076
|
+
}
|
|
51077
|
+
return line;
|
|
51078
|
+
} finally {
|
|
51079
|
+
closeSync2(ttyFd);
|
|
51080
|
+
}
|
|
51081
|
+
};
|
|
51082
|
+
console.log(
|
|
51083
|
+
"numbl REPL \u2014 type 'exit' or press Ctrl+D to quit, Alt+Enter for new line"
|
|
51084
|
+
);
|
|
51085
|
+
if (!process.stdin.isTTY) {
|
|
51086
|
+
const rl = createInterface({
|
|
51087
|
+
input: process.stdin,
|
|
51088
|
+
output: process.stdout,
|
|
51089
|
+
prompt: ">> "
|
|
51090
|
+
});
|
|
51091
|
+
rl.prompt();
|
|
51092
|
+
for await (const line of rl) {
|
|
51093
|
+
const trimmed = line.trim();
|
|
51094
|
+
if (trimmed === "exit" || trimmed === "quit") break;
|
|
51095
|
+
if (trimmed === "") {
|
|
51096
|
+
rl.prompt();
|
|
51097
|
+
continue;
|
|
51098
|
+
}
|
|
51099
|
+
try {
|
|
51100
|
+
const result = executeCode(
|
|
51101
|
+
trimmed,
|
|
51102
|
+
{
|
|
51103
|
+
displayResults: true,
|
|
51104
|
+
onOutput: (text) => process.stdout.write(text),
|
|
51105
|
+
onDrawnow,
|
|
51106
|
+
onInput,
|
|
51107
|
+
initialVariableValues: variableValues,
|
|
51108
|
+
initialHoldState: holdState,
|
|
51109
|
+
optimization,
|
|
51110
|
+
fileIO,
|
|
51111
|
+
system
|
|
51112
|
+
},
|
|
51113
|
+
workspaceFiles,
|
|
51114
|
+
"repl",
|
|
51115
|
+
searchPaths,
|
|
51116
|
+
nativeBridge2
|
|
51117
|
+
);
|
|
51118
|
+
variableValues = result.variableValues;
|
|
51119
|
+
holdState = result.holdState;
|
|
51120
|
+
if (result.searchPaths) {
|
|
51121
|
+
searchPaths.length = 0;
|
|
51122
|
+
searchPaths.push(...result.searchPaths);
|
|
51123
|
+
workspaceFiles.length = 0;
|
|
51124
|
+
workspaceFiles.push(...result.workspaceFiles ?? []);
|
|
51125
|
+
}
|
|
51126
|
+
if (result.plotInstructions.length > 0 && onDrawnow) {
|
|
51127
|
+
onDrawnow(result.plotInstructions);
|
|
51128
|
+
}
|
|
51129
|
+
} catch (error) {
|
|
51130
|
+
const diags = diagnoseErrors(error, trimmed, "repl", workspaceFiles);
|
|
51131
|
+
console.error(formatDiagnostics(diags));
|
|
51132
|
+
}
|
|
51133
|
+
rl.prompt();
|
|
51134
|
+
}
|
|
51135
|
+
console.log("");
|
|
51136
|
+
process.exit(0);
|
|
51137
|
+
}
|
|
51138
|
+
const stdin = process.stdin;
|
|
51139
|
+
const stdout = process.stdout;
|
|
51140
|
+
stdin.setRawMode(true);
|
|
51141
|
+
stdin.resume();
|
|
51142
|
+
stdout.write("\x1B[?2004h");
|
|
51143
|
+
const PS1 = ">> ";
|
|
51144
|
+
const PS2 = " ";
|
|
51145
|
+
let buf = [""];
|
|
51146
|
+
let row = 0;
|
|
51147
|
+
let col = 0;
|
|
51148
|
+
let sRow = 0;
|
|
51149
|
+
const hist = loadHistory();
|
|
51150
|
+
let hIdx = -1;
|
|
51151
|
+
let hStash = "";
|
|
51152
|
+
let hPrefix = "";
|
|
51153
|
+
let pasting = false;
|
|
51154
|
+
let pasteBuf = [];
|
|
51155
|
+
let busy = false;
|
|
51156
|
+
function display() {
|
|
51157
|
+
if (sRow > 0) stdout.write(`\x1B[${sRow}A`);
|
|
51158
|
+
stdout.write("\r\x1B[J");
|
|
51159
|
+
for (let i = 0; i < buf.length; i++) {
|
|
51160
|
+
stdout.write((i === 0 ? PS1 : PS2) + buf[i]);
|
|
51161
|
+
if (i < buf.length - 1) stdout.write("\r\n");
|
|
51162
|
+
}
|
|
51163
|
+
const fromEnd = buf.length - 1 - row;
|
|
51164
|
+
if (fromEnd > 0) stdout.write(`\x1B[${fromEnd}A`);
|
|
51165
|
+
const pLen = row === 0 ? PS1.length : PS2.length;
|
|
51166
|
+
stdout.write(`\x1B[${pLen + col + 1}G`);
|
|
51167
|
+
sRow = row;
|
|
51168
|
+
}
|
|
51169
|
+
function resetInput() {
|
|
51170
|
+
buf = [""];
|
|
51171
|
+
row = col = sRow = 0;
|
|
51172
|
+
hIdx = -1;
|
|
51173
|
+
hStash = "";
|
|
51174
|
+
hPrefix = "";
|
|
51175
|
+
stdout.write(PS1);
|
|
51176
|
+
}
|
|
51177
|
+
function cleanup() {
|
|
51178
|
+
stdout.write("\x1B[?2004l");
|
|
51179
|
+
stdin.setRawMode(false);
|
|
51180
|
+
stdin.pause();
|
|
51181
|
+
}
|
|
51182
|
+
function insertNewline() {
|
|
51183
|
+
const after = buf[row].slice(col);
|
|
51184
|
+
buf[row] = buf[row].slice(0, col);
|
|
51185
|
+
buf.splice(row + 1, 0, after);
|
|
51186
|
+
row++;
|
|
51187
|
+
col = 0;
|
|
51188
|
+
display();
|
|
51189
|
+
}
|
|
51190
|
+
function exec2() {
|
|
51191
|
+
const code = buf.join("\n").trim();
|
|
51192
|
+
const below = buf.length - 1 - sRow;
|
|
51193
|
+
if (below > 0) stdout.write(`\x1B[${below}B`);
|
|
51194
|
+
stdout.write("\r\n");
|
|
51195
|
+
sRow = 0;
|
|
51196
|
+
if (!code) {
|
|
51197
|
+
resetInput();
|
|
51198
|
+
return;
|
|
51199
|
+
}
|
|
51200
|
+
if (code === "exit" || code === "quit") {
|
|
51201
|
+
cleanup();
|
|
51202
|
+
console.log("");
|
|
51203
|
+
process.exit(0);
|
|
51204
|
+
}
|
|
51205
|
+
const entry = buf.join("\n");
|
|
51206
|
+
hist.push(entry);
|
|
51207
|
+
saveHistoryEntry(entry, hist);
|
|
51208
|
+
hIdx = -1;
|
|
51209
|
+
busy = true;
|
|
51210
|
+
stdin.setRawMode(false);
|
|
51211
|
+
stdin.pause();
|
|
51212
|
+
try {
|
|
51213
|
+
const result = executeCode(
|
|
51214
|
+
code,
|
|
51215
|
+
{
|
|
51216
|
+
displayResults: true,
|
|
51217
|
+
onOutput: (text) => stdout.write(text),
|
|
51218
|
+
onDrawnow,
|
|
51219
|
+
onInput,
|
|
51220
|
+
initialVariableValues: variableValues,
|
|
51221
|
+
initialHoldState: holdState,
|
|
51222
|
+
optimization,
|
|
51223
|
+
fileIO,
|
|
51224
|
+
system
|
|
51225
|
+
},
|
|
51226
|
+
workspaceFiles,
|
|
51227
|
+
"repl",
|
|
51228
|
+
searchPaths,
|
|
51229
|
+
nativeBridge2
|
|
51230
|
+
);
|
|
51231
|
+
variableValues = result.variableValues;
|
|
51232
|
+
holdState = result.holdState;
|
|
51233
|
+
if (result.searchPaths) {
|
|
51234
|
+
searchPaths.length = 0;
|
|
51235
|
+
searchPaths.push(...result.searchPaths);
|
|
51236
|
+
workspaceFiles.length = 0;
|
|
51237
|
+
workspaceFiles.push(...result.workspaceFiles ?? []);
|
|
51238
|
+
}
|
|
51239
|
+
if (result.plotInstructions.length > 0 && onDrawnow) {
|
|
51240
|
+
onDrawnow(result.plotInstructions);
|
|
51241
|
+
}
|
|
51242
|
+
} catch (error) {
|
|
51243
|
+
const diags = diagnoseErrors(error, code, "repl", workspaceFiles);
|
|
51244
|
+
console.error(formatDiagnostics(diags));
|
|
51245
|
+
}
|
|
51246
|
+
stdin.resume();
|
|
51247
|
+
stdin.setRawMode(true);
|
|
51248
|
+
busy = false;
|
|
51249
|
+
resetInput();
|
|
51250
|
+
}
|
|
51251
|
+
function handlePaste(text) {
|
|
51252
|
+
text = text.replace(/(\r\n|\r|\n)$/, "");
|
|
51253
|
+
const lines = text.split(/\r\n|\r|\n/);
|
|
51254
|
+
if (lines.length === 1) {
|
|
51255
|
+
buf[row] = buf[row].slice(0, col) + lines[0] + buf[row].slice(col);
|
|
51256
|
+
col += lines[0].length;
|
|
51257
|
+
} else {
|
|
51258
|
+
const after = buf[row].slice(col);
|
|
51259
|
+
buf[row] = buf[row].slice(0, col) + lines[0];
|
|
51260
|
+
for (let j = 1; j < lines.length; j++) {
|
|
51261
|
+
buf.splice(row + j, 0, lines[j]);
|
|
51262
|
+
}
|
|
51263
|
+
row += lines.length - 1;
|
|
51264
|
+
col = buf[row].length;
|
|
51265
|
+
buf[row] += after;
|
|
51266
|
+
}
|
|
51267
|
+
display();
|
|
51268
|
+
}
|
|
51269
|
+
function navHistory(dir) {
|
|
51270
|
+
if (hist.length === 0) return;
|
|
51271
|
+
if (hIdx === -1 && dir > 0) return;
|
|
51272
|
+
if (hIdx === -1) {
|
|
51273
|
+
hStash = buf.join("\n");
|
|
51274
|
+
hPrefix = hStash;
|
|
51275
|
+
if (hPrefix.length > 0) {
|
|
51276
|
+
for (let k = hist.length - 1; k >= 0; k--) {
|
|
51277
|
+
if (hist[k].startsWith(hPrefix)) {
|
|
51278
|
+
hIdx = k;
|
|
51279
|
+
break;
|
|
51280
|
+
}
|
|
51281
|
+
}
|
|
51282
|
+
if (hIdx === -1) return;
|
|
51283
|
+
} else {
|
|
51284
|
+
hIdx = hist.length - 1;
|
|
51285
|
+
}
|
|
51286
|
+
} else {
|
|
51287
|
+
let found = false;
|
|
51288
|
+
if (dir < 0) {
|
|
51289
|
+
for (let k = hIdx - 1; k >= 0; k--) {
|
|
51290
|
+
if (hPrefix.length === 0 || hist[k].startsWith(hPrefix)) {
|
|
51291
|
+
hIdx = k;
|
|
51292
|
+
found = true;
|
|
51293
|
+
break;
|
|
51294
|
+
}
|
|
51295
|
+
}
|
|
51296
|
+
if (!found) return;
|
|
51297
|
+
} else {
|
|
51298
|
+
for (let k = hIdx + 1; k < hist.length; k++) {
|
|
51299
|
+
if (hPrefix.length === 0 || hist[k].startsWith(hPrefix)) {
|
|
51300
|
+
hIdx = k;
|
|
51301
|
+
found = true;
|
|
51302
|
+
break;
|
|
51303
|
+
}
|
|
51304
|
+
}
|
|
51305
|
+
if (!found) {
|
|
51306
|
+
buf = hStash.split("\n");
|
|
51307
|
+
hIdx = -1;
|
|
51308
|
+
row = buf.length - 1;
|
|
51309
|
+
col = buf[row].length;
|
|
51310
|
+
display();
|
|
51311
|
+
return;
|
|
51312
|
+
}
|
|
51313
|
+
}
|
|
51314
|
+
}
|
|
51315
|
+
buf = hist[hIdx].split("\n");
|
|
51316
|
+
row = buf.length - 1;
|
|
51317
|
+
col = buf[row].length;
|
|
51318
|
+
display();
|
|
51319
|
+
}
|
|
51320
|
+
function handleCSI(seq) {
|
|
51321
|
+
switch (seq) {
|
|
51322
|
+
case "A":
|
|
51323
|
+
if (buf.length > 1 && row > 0) {
|
|
51324
|
+
row--;
|
|
51325
|
+
col = Math.min(col, buf[row].length);
|
|
51326
|
+
display();
|
|
51327
|
+
} else {
|
|
51328
|
+
navHistory(-1);
|
|
51329
|
+
}
|
|
51330
|
+
break;
|
|
51331
|
+
case "B":
|
|
51332
|
+
if (buf.length > 1 && row < buf.length - 1) {
|
|
51333
|
+
row++;
|
|
51334
|
+
col = Math.min(col, buf[row].length);
|
|
51335
|
+
display();
|
|
51336
|
+
} else {
|
|
51337
|
+
navHistory(1);
|
|
51338
|
+
}
|
|
51339
|
+
break;
|
|
51340
|
+
case "C":
|
|
51341
|
+
if (col < buf[row].length) {
|
|
51342
|
+
col++;
|
|
51343
|
+
display();
|
|
51344
|
+
} else if (row < buf.length - 1) {
|
|
51345
|
+
row++;
|
|
51346
|
+
col = 0;
|
|
51347
|
+
display();
|
|
51348
|
+
}
|
|
51349
|
+
break;
|
|
51350
|
+
case "D":
|
|
51351
|
+
if (col > 0) {
|
|
51352
|
+
col--;
|
|
51353
|
+
display();
|
|
51354
|
+
} else if (row > 0) {
|
|
51355
|
+
row--;
|
|
51356
|
+
col = buf[row].length;
|
|
51357
|
+
display();
|
|
51358
|
+
}
|
|
51359
|
+
break;
|
|
51360
|
+
case "H":
|
|
51361
|
+
// Home
|
|
51362
|
+
case "1~":
|
|
51363
|
+
col = 0;
|
|
51364
|
+
display();
|
|
51365
|
+
break;
|
|
51366
|
+
case "F":
|
|
51367
|
+
// End
|
|
51368
|
+
case "4~":
|
|
51369
|
+
col = buf[row].length;
|
|
51370
|
+
display();
|
|
51371
|
+
break;
|
|
51372
|
+
case "3~":
|
|
51373
|
+
if (col < buf[row].length) {
|
|
51374
|
+
buf[row] = buf[row].slice(0, col) + buf[row].slice(col + 1);
|
|
51375
|
+
display();
|
|
51376
|
+
} else if (row < buf.length - 1) {
|
|
51377
|
+
buf[row] += buf[row + 1];
|
|
51378
|
+
buf.splice(row + 1, 1);
|
|
51379
|
+
display();
|
|
51380
|
+
}
|
|
51381
|
+
break;
|
|
51382
|
+
case "13;2u":
|
|
51383
|
+
insertNewline();
|
|
51384
|
+
break;
|
|
51385
|
+
}
|
|
51386
|
+
}
|
|
51387
|
+
resetInput();
|
|
51388
|
+
return new Promise((resolve3) => {
|
|
51389
|
+
stdin.on("data", (chunk) => {
|
|
51390
|
+
if (busy) return;
|
|
51391
|
+
const data = chunk.toString("utf8");
|
|
51392
|
+
let i = 0;
|
|
51393
|
+
while (i < data.length) {
|
|
51394
|
+
if (busy) return;
|
|
51395
|
+
if (data.startsWith("\x1B[200~", i)) {
|
|
51396
|
+
pasting = true;
|
|
51397
|
+
pasteBuf = [];
|
|
51398
|
+
i += 6;
|
|
51399
|
+
continue;
|
|
51400
|
+
}
|
|
51401
|
+
if (data.startsWith("\x1B[201~", i)) {
|
|
51402
|
+
pasting = false;
|
|
51403
|
+
handlePaste(pasteBuf.join(""));
|
|
51404
|
+
i += 6;
|
|
51405
|
+
continue;
|
|
51406
|
+
}
|
|
51407
|
+
if (pasting) {
|
|
51408
|
+
const end = data.indexOf("\x1B[201~", i);
|
|
51409
|
+
if (end >= 0) {
|
|
51410
|
+
pasteBuf.push(data.slice(i, end));
|
|
51411
|
+
pasting = false;
|
|
51412
|
+
handlePaste(pasteBuf.join(""));
|
|
51413
|
+
i = end + 6;
|
|
51414
|
+
} else {
|
|
51415
|
+
pasteBuf.push(data.slice(i));
|
|
51416
|
+
i = data.length;
|
|
51417
|
+
}
|
|
51418
|
+
continue;
|
|
51419
|
+
}
|
|
51420
|
+
if (data[i] === "\x1B" && i + 1 < data.length && (data[i + 1] === "\r" || data[i + 1] === "\n")) {
|
|
51421
|
+
insertNewline();
|
|
51422
|
+
i += 2;
|
|
51423
|
+
continue;
|
|
51424
|
+
}
|
|
51425
|
+
if (data.startsWith("\x1B[", i)) {
|
|
51426
|
+
let j = i + 2;
|
|
51427
|
+
while (j < data.length && (data.charCodeAt(j) < 64 || data.charCodeAt(j) > 126))
|
|
51428
|
+
j++;
|
|
51429
|
+
if (j >= data.length) {
|
|
51430
|
+
i = data.length;
|
|
51431
|
+
continue;
|
|
51432
|
+
}
|
|
51433
|
+
handleCSI(data.slice(i + 2, j + 1));
|
|
51434
|
+
i = j + 1;
|
|
51435
|
+
continue;
|
|
51436
|
+
}
|
|
51437
|
+
if (data[i] === "\x1B") {
|
|
51438
|
+
i++;
|
|
51439
|
+
continue;
|
|
51440
|
+
}
|
|
51441
|
+
const code = data.charCodeAt(i);
|
|
51442
|
+
i++;
|
|
51443
|
+
if (code === 13 || code === 10) {
|
|
51444
|
+
try {
|
|
51445
|
+
exec2();
|
|
51446
|
+
} catch (err) {
|
|
51447
|
+
console.error("Unexpected REPL error:", err);
|
|
51448
|
+
busy = false;
|
|
51449
|
+
resetInput();
|
|
51450
|
+
}
|
|
51451
|
+
} else if (code === 127 || code === 8) {
|
|
51452
|
+
if (col > 0) {
|
|
51453
|
+
buf[row] = buf[row].slice(0, col - 1) + buf[row].slice(col);
|
|
51454
|
+
col--;
|
|
51455
|
+
display();
|
|
51456
|
+
} else if (row > 0) {
|
|
51457
|
+
col = buf[row - 1].length;
|
|
51458
|
+
buf[row - 1] += buf[row];
|
|
51459
|
+
buf.splice(row, 1);
|
|
51460
|
+
row--;
|
|
51461
|
+
display();
|
|
51462
|
+
}
|
|
51463
|
+
} else if (code === 1) {
|
|
51464
|
+
col = 0;
|
|
51465
|
+
display();
|
|
51466
|
+
} else if (code === 5) {
|
|
51467
|
+
col = buf[row].length;
|
|
51468
|
+
display();
|
|
51469
|
+
} else if (code === 11) {
|
|
51470
|
+
buf[row] = buf[row].slice(0, col);
|
|
51471
|
+
display();
|
|
51472
|
+
} else if (code === 21) {
|
|
51473
|
+
buf[row] = buf[row].slice(col);
|
|
51474
|
+
col = 0;
|
|
51475
|
+
display();
|
|
51476
|
+
} else if (code === 3) {
|
|
51477
|
+
const below = buf.length - 1 - sRow;
|
|
51478
|
+
if (below > 0) stdout.write(`\x1B[${below}B`);
|
|
51479
|
+
stdout.write("\r\n^C\r\n");
|
|
51480
|
+
sRow = 0;
|
|
51481
|
+
resetInput();
|
|
51482
|
+
} else if (code === 4) {
|
|
51483
|
+
if (buf.length === 1 && buf[0] === "") {
|
|
51484
|
+
stdout.write("\r\n");
|
|
51485
|
+
cleanup();
|
|
51486
|
+
resolve3();
|
|
51487
|
+
return;
|
|
51488
|
+
}
|
|
51489
|
+
} else if (code === 12) {
|
|
51490
|
+
stdout.write("\x1B[2J\x1B[H");
|
|
51491
|
+
sRow = 0;
|
|
51492
|
+
display();
|
|
51493
|
+
} else if (code >= 32) {
|
|
51494
|
+
buf[row] = buf[row].slice(0, col) + data[i - 1] + buf[row].slice(col);
|
|
51495
|
+
col++;
|
|
51496
|
+
display();
|
|
51497
|
+
}
|
|
51498
|
+
}
|
|
51499
|
+
});
|
|
51500
|
+
});
|
|
51501
|
+
}
|
|
51502
|
+
|
|
51503
|
+
// src/vfs/unzipToFiles.ts
|
|
51504
|
+
import { inflateSync } from "fflate";
|
|
51505
|
+
var TEXT_DECODER = new TextDecoder("utf-8");
|
|
51506
|
+
function unzipToFiles(zipData) {
|
|
51507
|
+
let eocdOffset = -1;
|
|
51508
|
+
for (let i = zipData.length - 22; i >= 0; i--) {
|
|
51509
|
+
if (zipData[i] === 80 && zipData[i + 1] === 75 && zipData[i + 2] === 5 && zipData[i + 3] === 6) {
|
|
51510
|
+
eocdOffset = i;
|
|
51511
|
+
break;
|
|
51512
|
+
}
|
|
51513
|
+
}
|
|
51514
|
+
if (eocdOffset === -1) throw new Error("Invalid ZIP file");
|
|
51515
|
+
const view = new DataView(
|
|
51516
|
+
zipData.buffer,
|
|
51517
|
+
zipData.byteOffset,
|
|
51518
|
+
zipData.byteLength
|
|
51519
|
+
);
|
|
51520
|
+
const cdOffset = view.getUint32(eocdOffset + 16, true);
|
|
51521
|
+
const cdEntries = view.getUint16(eocdOffset + 10, true);
|
|
51522
|
+
const files = [];
|
|
51523
|
+
let pos = cdOffset;
|
|
51524
|
+
for (let i = 0; i < cdEntries; i++) {
|
|
51525
|
+
if (view.getUint32(pos, true) !== 33639248) {
|
|
51526
|
+
throw new Error("Corrupt ZIP central directory");
|
|
51527
|
+
}
|
|
51528
|
+
const method = view.getUint16(pos + 10, true);
|
|
51529
|
+
const nameLen = view.getUint16(pos + 28, true);
|
|
51530
|
+
const extraLen = view.getUint16(pos + 30, true);
|
|
51531
|
+
const commentLen = view.getUint16(pos + 32, true);
|
|
51532
|
+
const localHeaderOffset = view.getUint32(pos + 42, true);
|
|
51533
|
+
const entryName = TEXT_DECODER.decode(
|
|
51534
|
+
zipData.subarray(pos + 46, pos + 46 + nameLen)
|
|
51535
|
+
);
|
|
51536
|
+
pos += 46 + nameLen + extraLen + commentLen;
|
|
51537
|
+
if (entryName.endsWith("/")) continue;
|
|
51538
|
+
const localPos = localHeaderOffset;
|
|
51539
|
+
if (view.getUint32(localPos, true) !== 67324752) {
|
|
51540
|
+
throw new Error("Corrupt ZIP local header");
|
|
51541
|
+
}
|
|
51542
|
+
const localNameLen = view.getUint16(localPos + 26, true);
|
|
51543
|
+
const localExtraLen = view.getUint16(localPos + 28, true);
|
|
51544
|
+
const compressedSize = view.getUint32(localPos + 18, true);
|
|
51545
|
+
const dataStart = localPos + 30 + localNameLen + localExtraLen;
|
|
51546
|
+
const compressedData = zipData.subarray(
|
|
51547
|
+
dataStart,
|
|
51548
|
+
dataStart + compressedSize
|
|
51549
|
+
);
|
|
51550
|
+
let content;
|
|
51551
|
+
if (method === 0) {
|
|
51552
|
+
content = new Uint8Array(compressedData);
|
|
51553
|
+
} else if (method === 8) {
|
|
51554
|
+
content = inflateSync(compressedData);
|
|
51555
|
+
} else {
|
|
51556
|
+
throw new Error(
|
|
51557
|
+
`Unsupported ZIP compression method ${method} for ${entryName}`
|
|
51558
|
+
);
|
|
51559
|
+
}
|
|
51560
|
+
files.push({ path: entryName, content });
|
|
51561
|
+
}
|
|
51562
|
+
return files;
|
|
51563
|
+
}
|
|
51564
|
+
|
|
51378
51565
|
// src/cli.ts
|
|
51379
51566
|
var __filename = fileURLToPath2(import.meta.url);
|
|
51380
51567
|
var __dirname = dirname2(__filename);
|
|
51381
|
-
var packageDir =
|
|
51382
|
-
var addonPath =
|
|
51568
|
+
var packageDir = join5(__dirname, "..");
|
|
51569
|
+
var addonPath = join5(packageDir, "build", "Release", "numbl_addon.node");
|
|
51383
51570
|
var nativeAddonLoaded = false;
|
|
51384
51571
|
if (!process.env.NUMBL_NO_NATIVE) {
|
|
51385
51572
|
try {
|
|
@@ -51408,62 +51595,51 @@ try {
|
|
|
51408
51595
|
nativeBridge = { load: (path) => koffi.load(path) };
|
|
51409
51596
|
} catch {
|
|
51410
51597
|
}
|
|
51411
|
-
|
|
51412
|
-
|
|
51413
|
-
|
|
51414
|
-
|
|
51415
|
-
|
|
51416
|
-
|
|
51417
|
-
|
|
51598
|
+
var MHL_URL = "https://github.com/mip-org/mip-core/releases/download/mip-main/mip-main-any.mhl";
|
|
51599
|
+
var mipCoreDir = join5(
|
|
51600
|
+
homedir3(),
|
|
51601
|
+
".numbl",
|
|
51602
|
+
"mip",
|
|
51603
|
+
"packages",
|
|
51604
|
+
"mip-org",
|
|
51605
|
+
"core",
|
|
51606
|
+
"mip"
|
|
51607
|
+
);
|
|
51608
|
+
var mipCoreSearchPath = join5(mipCoreDir, "mip");
|
|
51609
|
+
async function ensureMipCorePackage() {
|
|
51610
|
+
if (existsSync2(join5(mipCoreSearchPath, "mip.m"))) return;
|
|
51611
|
+
console.error("Installing mip core package...");
|
|
51612
|
+
const resp = await fetch(MHL_URL);
|
|
51613
|
+
if (!resp.ok) {
|
|
51614
|
+
console.error(
|
|
51615
|
+
`Warning: failed to download mip core package (HTTP ${resp.status})`
|
|
51616
|
+
);
|
|
51617
|
+
return;
|
|
51418
51618
|
}
|
|
51419
|
-
|
|
51420
|
-
|
|
51421
|
-
|
|
51422
|
-
|
|
51423
|
-
}
|
|
51424
|
-
|
|
51425
|
-
const stat = statSync2(fullPath);
|
|
51426
|
-
if (stat.isDirectory()) {
|
|
51427
|
-
if (entry.startsWith("@") || entry.startsWith("+") || entry === "private") {
|
|
51428
|
-
files.push(...scanMFiles(fullPath, excludeFile));
|
|
51429
|
-
}
|
|
51430
|
-
} else if (stat.isFile() && (entry.endsWith(".m") || entry.endsWith(".js"))) {
|
|
51431
|
-
const source = readFileSync4(fullPath, "utf-8");
|
|
51432
|
-
files.push({
|
|
51433
|
-
name: fullPath,
|
|
51434
|
-
source
|
|
51435
|
-
});
|
|
51436
|
-
} else if (stat.isFile() && entry.endsWith(".wasm")) {
|
|
51437
|
-
const data = readFileSync4(fullPath);
|
|
51438
|
-
files.push({
|
|
51439
|
-
name: fullPath,
|
|
51440
|
-
source: "",
|
|
51441
|
-
data: new Uint8Array(data)
|
|
51442
|
-
});
|
|
51443
|
-
}
|
|
51444
|
-
} catch (err) {
|
|
51445
|
-
console.warn(
|
|
51446
|
-
`Warning: could not read ${fullPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
51447
|
-
);
|
|
51448
|
-
}
|
|
51619
|
+
const buf = new Uint8Array(await resp.arrayBuffer());
|
|
51620
|
+
const files = unzipToFiles(buf);
|
|
51621
|
+
for (const f of files) {
|
|
51622
|
+
const dest = join5(mipCoreDir, f.path);
|
|
51623
|
+
mkdirSync2(dirname2(dest), { recursive: true });
|
|
51624
|
+
writeFileSync3(dest, f.content);
|
|
51449
51625
|
}
|
|
51450
|
-
|
|
51626
|
+
console.error("mip core package installed.");
|
|
51451
51627
|
}
|
|
51452
51628
|
function findTestFiles(dir) {
|
|
51453
51629
|
const results = [];
|
|
51454
51630
|
function walk(current) {
|
|
51455
51631
|
let entries;
|
|
51456
51632
|
try {
|
|
51457
|
-
entries =
|
|
51633
|
+
entries = readdirSync3(current);
|
|
51458
51634
|
} catch {
|
|
51459
51635
|
return;
|
|
51460
51636
|
}
|
|
51461
51637
|
entries.sort();
|
|
51462
51638
|
for (const entry of entries) {
|
|
51463
|
-
const fullPath =
|
|
51639
|
+
const fullPath = join5(current, entry);
|
|
51464
51640
|
let stat;
|
|
51465
51641
|
try {
|
|
51466
|
-
stat =
|
|
51642
|
+
stat = statSync3(fullPath);
|
|
51467
51643
|
} catch {
|
|
51468
51644
|
continue;
|
|
51469
51645
|
}
|
|
@@ -51472,7 +51648,7 @@ function findTestFiles(dir) {
|
|
|
51472
51648
|
walk(fullPath);
|
|
51473
51649
|
}
|
|
51474
51650
|
} else if (stat.isFile() && entry.endsWith(".m")) {
|
|
51475
|
-
const content =
|
|
51651
|
+
const content = readFileSync5(fullPath, "utf-8");
|
|
51476
51652
|
if (content.includes("SUCCESS")) {
|
|
51477
51653
|
results.push(fullPath);
|
|
51478
51654
|
}
|
|
@@ -51514,7 +51690,7 @@ async function runTests(dir, optimization) {
|
|
|
51514
51690
|
const failedScripts = [];
|
|
51515
51691
|
for (const filepath of testFiles) {
|
|
51516
51692
|
const rel = relative(process.cwd(), filepath);
|
|
51517
|
-
const source =
|
|
51693
|
+
const source = readFileSync5(filepath, "utf-8");
|
|
51518
51694
|
const mainFileName = filepath;
|
|
51519
51695
|
const scriptDir = dirname2(filepath);
|
|
51520
51696
|
const searchPaths = [scriptDir];
|
|
@@ -51729,8 +51905,9 @@ async function cmdRun(args) {
|
|
|
51729
51905
|
console.error("Error: numbl run accepts only one file argument");
|
|
51730
51906
|
process.exit(1);
|
|
51731
51907
|
}
|
|
51908
|
+
await ensureMipCorePackage();
|
|
51732
51909
|
const filepath = resolve2(process.cwd(), opts.positional[0]);
|
|
51733
|
-
const code =
|
|
51910
|
+
const code = readFileSync5(filepath, "utf-8");
|
|
51734
51911
|
const mainFileName = filepath;
|
|
51735
51912
|
const searchPaths = [];
|
|
51736
51913
|
let workspaceFiles = [];
|
|
@@ -51743,6 +51920,10 @@ async function cmdRun(args) {
|
|
|
51743
51920
|
searchPaths.push(p2);
|
|
51744
51921
|
workspaceFiles.push(...scanMFiles(p2));
|
|
51745
51922
|
}
|
|
51923
|
+
if (existsSync2(mipCoreSearchPath)) {
|
|
51924
|
+
searchPaths.push(mipCoreSearchPath);
|
|
51925
|
+
workspaceFiles.push(...scanMFiles(mipCoreSearchPath));
|
|
51926
|
+
}
|
|
51746
51927
|
await executeWithOptions(
|
|
51747
51928
|
code,
|
|
51748
51929
|
mainFileName,
|
|
@@ -51761,12 +51942,17 @@ async function cmdEval(args) {
|
|
|
51761
51942
|
console.error("Error: numbl eval accepts only one code argument");
|
|
51762
51943
|
process.exit(1);
|
|
51763
51944
|
}
|
|
51945
|
+
await ensureMipCorePackage();
|
|
51764
51946
|
const searchPaths = [];
|
|
51765
51947
|
const workspaceFiles = [];
|
|
51766
51948
|
for (const p2 of opts.extraPaths) {
|
|
51767
51949
|
searchPaths.push(p2);
|
|
51768
51950
|
workspaceFiles.push(...scanMFiles(p2));
|
|
51769
51951
|
}
|
|
51952
|
+
if (existsSync2(mipCoreSearchPath)) {
|
|
51953
|
+
searchPaths.push(mipCoreSearchPath);
|
|
51954
|
+
workspaceFiles.push(...scanMFiles(mipCoreSearchPath));
|
|
51955
|
+
}
|
|
51770
51956
|
await executeWithOptions(
|
|
51771
51957
|
opts.positional[0],
|
|
51772
51958
|
"eval.m",
|
|
@@ -51978,13 +52164,13 @@ function finalizeDumpFile(dumpFile, mainFileName, jsCode) {
|
|
|
51978
52164
|
}
|
|
51979
52165
|
let jitContent = "";
|
|
51980
52166
|
try {
|
|
51981
|
-
jitContent =
|
|
52167
|
+
jitContent = readFileSync5(dumpFile, "utf-8");
|
|
51982
52168
|
} catch {
|
|
51983
52169
|
}
|
|
51984
52170
|
writeFileSync3(dumpFile, header + jsCode + "\n" + jitContent);
|
|
51985
52171
|
}
|
|
51986
52172
|
async function cmdBuildAddon() {
|
|
51987
|
-
const bindingGyp =
|
|
52173
|
+
const bindingGyp = join5(packageDir, "binding.gyp");
|
|
51988
52174
|
if (!existsSync2(bindingGyp)) {
|
|
51989
52175
|
console.error(
|
|
51990
52176
|
"Error: binding.gyp not found in package directory: " + packageDir
|
|
@@ -52030,8 +52216,13 @@ function cmdListBuiltins() {
|
|
|
52030
52216
|
}
|
|
52031
52217
|
async function cmdRepl(args) {
|
|
52032
52218
|
const opts = parseOptions(args);
|
|
52219
|
+
await ensureMipCorePackage();
|
|
52033
52220
|
const replSearchPaths = [...opts.extraPaths];
|
|
52034
52221
|
const replFiles = opts.extraPaths.flatMap((d) => scanMFiles(d));
|
|
52222
|
+
if (existsSync2(mipCoreSearchPath)) {
|
|
52223
|
+
replSearchPaths.push(mipCoreSearchPath);
|
|
52224
|
+
replFiles.push(...scanMFiles(mipCoreSearchPath));
|
|
52225
|
+
}
|
|
52035
52226
|
const replPlotOpts = opts.plotPort !== void 0 ? { port: opts.plotPort, host: "0.0.0.0" } : void 0;
|
|
52036
52227
|
const { onDrawnow: replDrawnow } = createPlotHandler(
|
|
52037
52228
|
!opts.plot,
|
|
@@ -52097,7 +52288,7 @@ function cmdShowProfile(args) {
|
|
|
52097
52288
|
console.error(`Error: profile file not found: ${filepath}`);
|
|
52098
52289
|
process.exit(1);
|
|
52099
52290
|
}
|
|
52100
|
-
const data = JSON.parse(
|
|
52291
|
+
const data = JSON.parse(readFileSync5(filepath, "utf-8"));
|
|
52101
52292
|
const fmt = (n, decimals = 1) => n.toFixed(decimals);
|
|
52102
52293
|
const pad = (s, w) => s.padStart(w);
|
|
52103
52294
|
const execTime = data.executionTimeMs || 1;
|
|
@@ -52179,7 +52370,7 @@ async function main() {
|
|
|
52179
52370
|
break;
|
|
52180
52371
|
case "run-tests": {
|
|
52181
52372
|
const testOpts = parseOptions(rest);
|
|
52182
|
-
const dir = testOpts.positional.length > 0 ? testOpts.positional[0] :
|
|
52373
|
+
const dir = testOpts.positional.length > 0 ? testOpts.positional[0] : join5(packageDir, "numbl_test_scripts");
|
|
52183
52374
|
await runTests(dir, testOpts.optimization);
|
|
52184
52375
|
break;
|
|
52185
52376
|
}
|