shell-dsl 0.0.7 → 0.0.8
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 +3 -1
- package/dist/cjs/index.cjs +14 -4
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/commands/awk/awk.cjs +276 -0
- package/dist/cjs/src/commands/awk/awk.cjs.map +10 -0
- package/dist/cjs/src/commands/break-continue/break-continue.cjs +56 -0
- package/dist/cjs/src/commands/break-continue/break-continue.cjs.map +10 -0
- package/dist/cjs/src/commands/cat/cat.cjs +57 -0
- package/dist/cjs/src/commands/cat/cat.cjs.map +10 -0
- package/dist/cjs/src/commands/cp/cp.cjs +126 -0
- package/dist/cjs/src/commands/cp/cp.cjs.map +10 -0
- package/dist/cjs/src/commands/echo/echo.cjs +50 -0
- package/dist/cjs/src/commands/echo/echo.cjs.map +10 -0
- package/dist/cjs/src/commands/find/find.cjs +251 -0
- package/dist/cjs/src/commands/find/find.cjs.map +10 -0
- package/dist/cjs/src/commands/grep/grep.cjs +510 -0
- package/dist/cjs/src/commands/grep/grep.cjs.map +10 -0
- package/dist/cjs/src/commands/head/head.cjs +95 -0
- package/dist/cjs/src/commands/head/head.cjs.map +10 -0
- package/dist/cjs/src/commands/index.cjs +136 -0
- package/dist/cjs/src/commands/index.cjs.map +10 -0
- package/dist/cjs/src/commands/ls/ls.cjs +119 -0
- package/dist/cjs/src/commands/ls/ls.cjs.map +10 -0
- package/dist/cjs/src/commands/mkdir/mkdir.cjs +64 -0
- package/dist/cjs/src/commands/mkdir/mkdir.cjs.map +10 -0
- package/dist/cjs/src/commands/mv/mv.cjs +118 -0
- package/dist/cjs/src/commands/mv/mv.cjs.map +10 -0
- package/dist/cjs/src/commands/pwd/pwd.cjs +41 -0
- package/dist/cjs/src/commands/pwd/pwd.cjs.map +10 -0
- package/dist/cjs/src/commands/rm/rm.cjs +82 -0
- package/dist/cjs/src/commands/rm/rm.cjs.map +10 -0
- package/dist/cjs/src/commands/sed/sed.cjs +218 -0
- package/dist/cjs/src/commands/sed/sed.cjs.map +10 -0
- package/dist/cjs/src/commands/sort/sort.cjs +105 -0
- package/dist/cjs/src/commands/sort/sort.cjs.map +10 -0
- package/dist/cjs/src/commands/tail/tail.cjs +95 -0
- package/dist/cjs/src/commands/tail/tail.cjs.map +10 -0
- package/dist/cjs/src/commands/tee/tee.cjs +65 -0
- package/dist/cjs/src/commands/tee/tee.cjs.map +10 -0
- package/dist/cjs/src/commands/test/test.cjs +148 -0
- package/dist/cjs/src/commands/test/test.cjs.map +10 -0
- package/dist/cjs/src/commands/touch/touch.cjs +70 -0
- package/dist/cjs/src/commands/touch/touch.cjs.map +10 -0
- package/dist/cjs/src/commands/tree/tree.cjs +161 -0
- package/dist/cjs/src/commands/tree/tree.cjs.map +10 -0
- package/dist/cjs/src/commands/true-false/true-false.cjs +43 -0
- package/dist/cjs/src/commands/true-false/true-false.cjs.map +10 -0
- package/dist/cjs/src/commands/uniq/uniq.cjs +116 -0
- package/dist/cjs/src/commands/uniq/uniq.cjs.map +10 -0
- package/dist/cjs/src/commands/wc/wc.cjs +116 -0
- package/dist/cjs/src/commands/wc/wc.cjs.map +10 -0
- package/dist/cjs/src/index.cjs +10 -2
- package/dist/cjs/src/index.cjs.map +3 -3
- package/dist/cjs/src/interpreter/index.cjs +4 -2
- package/dist/cjs/src/interpreter/index.cjs.map +3 -3
- package/dist/cjs/src/interpreter/interpreter.cjs +381 -2
- package/dist/cjs/src/interpreter/interpreter.cjs.map +3 -3
- package/dist/cjs/src/lexer/index.cjs +3 -2
- package/dist/cjs/src/lexer/index.cjs.map +3 -3
- package/dist/cjs/src/lexer/lexer.cjs +202 -7
- package/dist/cjs/src/lexer/lexer.cjs.map +3 -3
- package/dist/cjs/src/lexer/tokens.cjs +31 -2
- package/dist/cjs/src/lexer/tokens.cjs.map +3 -3
- package/dist/cjs/src/parser/ast.cjs +25 -1
- package/dist/cjs/src/parser/ast.cjs.map +3 -3
- package/dist/cjs/src/parser/index.cjs +7 -1
- package/dist/cjs/src/parser/index.cjs.map +3 -3
- package/dist/cjs/src/parser/parser.cjs +211 -7
- package/dist/cjs/src/parser/parser.cjs.map +3 -3
- package/dist/cjs/src/shell-dsl.cjs +2 -2
- package/dist/cjs/src/shell-dsl.cjs.map +3 -3
- package/dist/mjs/index.mjs +25 -5
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/src/commands/awk/awk.mjs +246 -0
- package/dist/mjs/src/commands/awk/awk.mjs.map +10 -0
- package/dist/mjs/src/commands/break-continue/break-continue.mjs +26 -0
- package/dist/mjs/src/commands/break-continue/break-continue.mjs.map +10 -0
- package/dist/mjs/src/commands/cat/cat.mjs +27 -0
- package/dist/mjs/src/commands/cat/cat.mjs.map +10 -0
- package/dist/mjs/src/commands/cp/cp.mjs +96 -0
- package/dist/mjs/src/commands/cp/cp.mjs.map +10 -0
- package/dist/mjs/src/commands/echo/echo.mjs +20 -0
- package/dist/mjs/src/commands/echo/echo.mjs.map +10 -0
- package/dist/mjs/src/commands/find/find.mjs +221 -0
- package/dist/mjs/src/commands/find/find.mjs.map +10 -0
- package/dist/mjs/src/commands/grep/grep.mjs +480 -0
- package/dist/mjs/src/commands/grep/grep.mjs.map +10 -0
- package/dist/mjs/src/commands/head/head.mjs +65 -0
- package/dist/mjs/src/commands/head/head.mjs.map +10 -0
- package/dist/mjs/src/commands/index.mjs +106 -0
- package/dist/mjs/src/commands/index.mjs.map +10 -0
- package/dist/mjs/src/commands/ls/ls.mjs +89 -0
- package/dist/mjs/src/commands/ls/ls.mjs.map +10 -0
- package/dist/mjs/src/commands/mkdir/mkdir.mjs +34 -0
- package/dist/mjs/src/commands/mkdir/mkdir.mjs.map +10 -0
- package/dist/mjs/src/commands/mv/mv.mjs +88 -0
- package/dist/mjs/src/commands/mv/mv.mjs.map +10 -0
- package/dist/mjs/src/commands/pwd/pwd.mjs +11 -0
- package/dist/mjs/src/commands/pwd/pwd.mjs.map +10 -0
- package/dist/mjs/src/commands/rm/rm.mjs +52 -0
- package/dist/mjs/src/commands/rm/rm.mjs.map +10 -0
- package/dist/mjs/src/commands/sed/sed.mjs +188 -0
- package/dist/mjs/src/commands/sed/sed.mjs.map +10 -0
- package/dist/mjs/src/commands/sort/sort.mjs +75 -0
- package/dist/mjs/src/commands/sort/sort.mjs.map +10 -0
- package/dist/mjs/src/commands/tail/tail.mjs +65 -0
- package/dist/mjs/src/commands/tail/tail.mjs.map +10 -0
- package/dist/mjs/src/commands/tee/tee.mjs +35 -0
- package/dist/mjs/src/commands/tee/tee.mjs.map +10 -0
- package/dist/mjs/src/commands/test/test.mjs +118 -0
- package/dist/mjs/src/commands/test/test.mjs.map +10 -0
- package/dist/mjs/src/commands/touch/touch.mjs +40 -0
- package/dist/mjs/src/commands/touch/touch.mjs.map +10 -0
- package/dist/mjs/src/commands/tree/tree.mjs +131 -0
- package/dist/mjs/src/commands/tree/tree.mjs.map +10 -0
- package/dist/mjs/src/commands/true-false/true-false.mjs +13 -0
- package/dist/mjs/src/commands/true-false/true-false.mjs.map +10 -0
- package/dist/mjs/src/commands/uniq/uniq.mjs +86 -0
- package/dist/mjs/src/commands/uniq/uniq.mjs.map +10 -0
- package/dist/mjs/src/commands/wc/wc.mjs +86 -0
- package/dist/mjs/src/commands/wc/wc.mjs.map +10 -0
- package/dist/mjs/src/index.mjs +18 -4
- package/dist/mjs/src/index.mjs.map +3 -3
- package/dist/mjs/src/interpreter/index.mjs +5 -3
- package/dist/mjs/src/interpreter/index.mjs.map +2 -2
- package/dist/mjs/src/interpreter/interpreter.mjs +381 -2
- package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
- package/dist/mjs/src/lexer/index.mjs +4 -3
- package/dist/mjs/src/lexer/index.mjs.map +2 -2
- package/dist/mjs/src/lexer/lexer.mjs +202 -7
- package/dist/mjs/src/lexer/lexer.mjs.map +3 -3
- package/dist/mjs/src/lexer/tokens.mjs +31 -2
- package/dist/mjs/src/lexer/tokens.mjs.map +3 -3
- package/dist/mjs/src/parser/ast.mjs +25 -1
- package/dist/mjs/src/parser/ast.mjs.map +3 -3
- package/dist/mjs/src/parser/index.mjs +14 -2
- package/dist/mjs/src/parser/index.mjs.map +3 -3
- package/dist/mjs/src/parser/parser.mjs +211 -7
- package/dist/mjs/src/parser/parser.mjs.map +3 -3
- package/dist/mjs/src/shell-dsl.mjs +2 -2
- package/dist/mjs/src/shell-dsl.mjs.map +3 -3
- package/dist/types/index.d.ts +2 -2
- package/dist/types/src/commands/awk/awk.d.ts +2 -0
- package/dist/types/src/commands/break-continue/break-continue.d.ts +3 -0
- package/dist/types/src/commands/cat/cat.d.ts +2 -0
- package/dist/types/src/commands/cp/cp.d.ts +2 -0
- package/dist/types/src/commands/echo/echo.d.ts +2 -0
- package/dist/types/src/commands/find/find.d.ts +2 -0
- package/dist/types/src/commands/grep/grep.d.ts +2 -0
- package/dist/types/src/commands/head/head.d.ts +2 -0
- package/dist/types/src/commands/index.d.ts +25 -0
- package/dist/types/src/commands/ls/ls.d.ts +2 -0
- package/dist/types/src/commands/mkdir/mkdir.d.ts +2 -0
- package/dist/types/src/commands/mv/mv.d.ts +2 -0
- package/dist/types/src/commands/pwd/pwd.d.ts +2 -0
- package/dist/types/src/commands/rm/rm.d.ts +2 -0
- package/dist/types/src/commands/sed/sed.d.ts +2 -0
- package/dist/types/src/commands/sort/sort.d.ts +2 -0
- package/dist/types/src/commands/tail/tail.d.ts +2 -0
- package/dist/types/src/commands/tee/tee.d.ts +2 -0
- package/dist/types/{commands → src/commands/test}/test.d.ts +1 -1
- package/dist/types/src/commands/touch/touch.d.ts +2 -0
- package/dist/types/src/commands/tree/tree.d.ts +2 -0
- package/dist/types/{commands → src/commands/true-false}/true-false.d.ts +1 -1
- package/dist/types/src/commands/uniq/uniq.d.ts +2 -0
- package/dist/types/src/commands/wc/wc.d.ts +2 -0
- package/dist/types/src/index.d.ts +3 -3
- package/dist/types/src/interpreter/index.d.ts +1 -1
- package/dist/types/src/interpreter/interpreter.d.ts +18 -0
- package/dist/types/src/lexer/index.d.ts +2 -2
- package/dist/types/src/lexer/lexer.d.ts +11 -2
- package/dist/types/src/lexer/tokens.d.ts +16 -0
- package/dist/types/src/parser/ast.d.ts +46 -1
- package/dist/types/src/parser/index.d.ts +2 -2
- package/dist/types/src/parser/parser.d.ts +14 -0
- package/package.json +1 -1
- package/dist/types/commands/cat.d.ts +0 -2
- package/dist/types/commands/cp.d.ts +0 -2
- package/dist/types/commands/echo.d.ts +0 -2
- package/dist/types/commands/find.d.ts +0 -2
- package/dist/types/commands/grep.d.ts +0 -2
- package/dist/types/commands/head.d.ts +0 -2
- package/dist/types/commands/index.d.ts +0 -22
- package/dist/types/commands/ls.d.ts +0 -2
- package/dist/types/commands/mkdir.d.ts +0 -2
- package/dist/types/commands/mv.d.ts +0 -2
- package/dist/types/commands/pwd.d.ts +0 -2
- package/dist/types/commands/rm.d.ts +0 -2
- package/dist/types/commands/sort.d.ts +0 -2
- package/dist/types/commands/tail.d.ts +0 -2
- package/dist/types/commands/tee.d.ts +0 -2
- package/dist/types/commands/touch.d.ts +0 -2
- package/dist/types/commands/tree.d.ts +0 -2
- package/dist/types/commands/uniq.d.ts +0 -2
- package/dist/types/commands/wc.d.ts +0 -2
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
+
var __toCommonJS = (from) => {
|
|
7
|
+
var entry = __moduleCache.get(from), desc;
|
|
8
|
+
if (entry)
|
|
9
|
+
return entry;
|
|
10
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
+
get: () => from[key],
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
}));
|
|
16
|
+
__moduleCache.set(from, entry);
|
|
17
|
+
return entry;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, {
|
|
22
|
+
get: all[name],
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
set: (newValue) => all[name] = () => newValue
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/commands/wc/wc.ts
|
|
30
|
+
var exports_wc = {};
|
|
31
|
+
__export(exports_wc, {
|
|
32
|
+
wc: () => wc
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(exports_wc);
|
|
35
|
+
var wc = async (ctx) => {
|
|
36
|
+
let showLines = false;
|
|
37
|
+
let showWords = false;
|
|
38
|
+
let showChars = false;
|
|
39
|
+
const files = [];
|
|
40
|
+
for (const arg of ctx.args) {
|
|
41
|
+
if (arg === "-l") {
|
|
42
|
+
showLines = true;
|
|
43
|
+
} else if (arg === "-w") {
|
|
44
|
+
showWords = true;
|
|
45
|
+
} else if (arg === "-c" || arg === "-m") {
|
|
46
|
+
showChars = true;
|
|
47
|
+
} else if (arg.startsWith("-")) {
|
|
48
|
+
for (const flag of arg.slice(1)) {
|
|
49
|
+
if (flag === "l")
|
|
50
|
+
showLines = true;
|
|
51
|
+
else if (flag === "w")
|
|
52
|
+
showWords = true;
|
|
53
|
+
else if (flag === "c" || flag === "m")
|
|
54
|
+
showChars = true;
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
files.push(arg);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!showLines && !showWords && !showChars) {
|
|
61
|
+
showLines = true;
|
|
62
|
+
showWords = true;
|
|
63
|
+
showChars = true;
|
|
64
|
+
}
|
|
65
|
+
const countContent = (content) => {
|
|
66
|
+
const lines = content.split(`
|
|
67
|
+
`).length - (content.endsWith(`
|
|
68
|
+
`) ? 1 : 0);
|
|
69
|
+
const words = content.split(/\s+/).filter((w) => w.length > 0).length;
|
|
70
|
+
const chars = content.length;
|
|
71
|
+
return { lines, words, chars };
|
|
72
|
+
};
|
|
73
|
+
const formatOutput = (counts, filename) => {
|
|
74
|
+
const parts = [];
|
|
75
|
+
if (showLines)
|
|
76
|
+
parts.push(String(counts.lines).padStart(8));
|
|
77
|
+
if (showWords)
|
|
78
|
+
parts.push(String(counts.words).padStart(8));
|
|
79
|
+
if (showChars)
|
|
80
|
+
parts.push(String(counts.chars).padStart(8));
|
|
81
|
+
if (filename)
|
|
82
|
+
parts.push(" " + filename);
|
|
83
|
+
return parts.join("") + `
|
|
84
|
+
`;
|
|
85
|
+
};
|
|
86
|
+
if (files.length === 0) {
|
|
87
|
+
const content = await ctx.stdin.text();
|
|
88
|
+
const counts = countContent(content);
|
|
89
|
+
await ctx.stdout.writeText(formatOutput(counts));
|
|
90
|
+
} else {
|
|
91
|
+
let totalLines = 0;
|
|
92
|
+
let totalWords = 0;
|
|
93
|
+
let totalChars = 0;
|
|
94
|
+
for (const file of files) {
|
|
95
|
+
try {
|
|
96
|
+
const path = ctx.fs.resolve(ctx.cwd, file);
|
|
97
|
+
const content = (await ctx.fs.readFile(path)).toString();
|
|
98
|
+
const counts = countContent(content);
|
|
99
|
+
totalLines += counts.lines;
|
|
100
|
+
totalWords += counts.words;
|
|
101
|
+
totalChars += counts.chars;
|
|
102
|
+
await ctx.stdout.writeText(formatOutput(counts, file));
|
|
103
|
+
} catch (err) {
|
|
104
|
+
await ctx.stderr.writeText(`wc: ${file}: No such file or directory
|
|
105
|
+
`);
|
|
106
|
+
return 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (files.length > 1) {
|
|
110
|
+
await ctx.stdout.writeText(formatOutput({ lines: totalLines, words: totalWords, chars: totalChars }, "total"));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return 0;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
//# debugId=075B5E90AE53867D64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/commands/wc/wc.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { Command } from \"../../types.cjs\";\n\nexport const wc: Command = async (ctx) => {\n let showLines = false;\n let showWords = false;\n let showChars = false;\n const files: string[] = [];\n\n // Parse arguments\n for (const arg of ctx.args) {\n if (arg === \"-l\") {\n showLines = true;\n } else if (arg === \"-w\") {\n showWords = true;\n } else if (arg === \"-c\" || arg === \"-m\") {\n showChars = true;\n } else if (arg.startsWith(\"-\")) {\n // Handle combined flags\n for (const flag of arg.slice(1)) {\n if (flag === \"l\") showLines = true;\n else if (flag === \"w\") showWords = true;\n else if (flag === \"c\" || flag === \"m\") showChars = true;\n }\n } else {\n files.push(arg);\n }\n }\n\n // Default: show all\n if (!showLines && !showWords && !showChars) {\n showLines = true;\n showWords = true;\n showChars = true;\n }\n\n const countContent = (content: string) => {\n const lines = content.split(\"\\n\").length - (content.endsWith(\"\\n\") ? 1 : 0);\n const words = content.split(/\\s+/).filter((w) => w.length > 0).length;\n const chars = content.length;\n return { lines, words, chars };\n };\n\n const formatOutput = (counts: { lines: number; words: number; chars: number }, filename?: string) => {\n const parts: string[] = [];\n if (showLines) parts.push(String(counts.lines).padStart(8));\n if (showWords) parts.push(String(counts.words).padStart(8));\n if (showChars) parts.push(String(counts.chars).padStart(8));\n if (filename) parts.push(\" \" + filename);\n return parts.join(\"\") + \"\\n\";\n };\n\n if (files.length === 0) {\n // Read from stdin\n const content = await ctx.stdin.text();\n const counts = countContent(content);\n await ctx.stdout.writeText(formatOutput(counts));\n } else {\n let totalLines = 0;\n let totalWords = 0;\n let totalChars = 0;\n\n for (const file of files) {\n try {\n const path = ctx.fs.resolve(ctx.cwd, file);\n const content = (await ctx.fs.readFile(path)).toString();\n const counts = countContent(content);\n totalLines += counts.lines;\n totalWords += counts.words;\n totalChars += counts.chars;\n await ctx.stdout.writeText(formatOutput(counts, file));\n } catch (err) {\n await ctx.stderr.writeText(`wc: ${file}: No such file or directory\\n`);\n return 1;\n }\n }\n\n if (files.length > 1) {\n await ctx.stdout.writeText(\n formatOutput({ lines: totalLines, words: totalWords, chars: totalChars }, \"total\")\n );\n }\n }\n\n return 0;\n};\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "075B5E90AE53867D64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/cjs/src/index.cjs
CHANGED
|
@@ -32,16 +32,22 @@ __export(exports_src, {
|
|
|
32
32
|
tokenToString: () => import_lexer.tokenToString,
|
|
33
33
|
parse: () => import_parser.parse,
|
|
34
34
|
lex: () => import_lexer.lex,
|
|
35
|
+
isWhileNode: () => import_parser2.isWhileNode,
|
|
35
36
|
isVariableNode: () => import_parser2.isVariableNode,
|
|
37
|
+
isUntilNode: () => import_parser2.isUntilNode,
|
|
36
38
|
isSubstitutionNode: () => import_parser2.isSubstitutionNode,
|
|
37
39
|
isSequenceNode: () => import_parser2.isSequenceNode,
|
|
38
40
|
isRawValue: () => import_types.isRawValue,
|
|
39
41
|
isPipelineNode: () => import_parser2.isPipelineNode,
|
|
40
42
|
isOrNode: () => import_parser2.isOrNode,
|
|
41
43
|
isLiteralNode: () => import_parser2.isLiteralNode,
|
|
44
|
+
isIfNode: () => import_parser2.isIfNode,
|
|
42
45
|
isGlobNode: () => import_parser2.isGlobNode,
|
|
46
|
+
isForNode: () => import_parser2.isForNode,
|
|
43
47
|
isConcatNode: () => import_parser2.isConcatNode,
|
|
44
48
|
isCommandNode: () => import_parser2.isCommandNode,
|
|
49
|
+
isCaseNode: () => import_parser2.isCaseNode,
|
|
50
|
+
isArithmeticNode: () => import_parser2.isArithmeticNode,
|
|
45
51
|
isAndNode: () => import_parser2.isAndNode,
|
|
46
52
|
escapeForInterpolation: () => import_utils.escapeForInterpolation,
|
|
47
53
|
escape: () => import_utils.escape,
|
|
@@ -63,7 +69,9 @@ __export(exports_src, {
|
|
|
63
69
|
Lexer: () => import_lexer.Lexer,
|
|
64
70
|
LexError: () => import_errors.LexError,
|
|
65
71
|
Interpreter: () => import_interpreter.Interpreter,
|
|
66
|
-
FileSystem: () => import_fs2.FileSystem
|
|
72
|
+
FileSystem: () => import_fs2.FileSystem,
|
|
73
|
+
ContinueException: () => import_interpreter.ContinueException,
|
|
74
|
+
BreakException: () => import_interpreter.BreakException
|
|
67
75
|
});
|
|
68
76
|
module.exports = __toCommonJS(exports_src);
|
|
69
77
|
var import_shell_dsl = require("./shell-dsl.cjs");
|
|
@@ -80,4 +88,4 @@ var import_io = require("./io/index.cjs");
|
|
|
80
88
|
var import_io2 = require("./io/index.cjs");
|
|
81
89
|
var import_utils = require("./utils/index.cjs");
|
|
82
90
|
|
|
83
|
-
//# debugId=
|
|
91
|
+
//# debugId=A00B7F9271C525C564756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.cjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.cjs\";\n\n// Types\nexport type {\n VirtualFS,\n FileStat,\n Command,\n CommandContext,\n Stdin,\n Stdout,\n Stderr,\n OutputCollector,\n ExecResult,\n ShellConfig,\n RawValue,\n} from \"./types.cjs\";\nexport { isRawValue } from \"./types.cjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.cjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.cjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.cjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.cjs\";\nexport type {\n ASTNode,\n Redirect,\n CommandNode,\n PipelineNode,\n AndNode,\n OrNode,\n SequenceNode,\n LiteralNode,\n VariableNode,\n SubstitutionNode,\n GlobNode,\n ConcatNode,\n} from \"./parser/index.cjs\";\nexport {\n isCommandNode,\n isPipelineNode,\n isAndNode,\n isOrNode,\n isSequenceNode,\n isLiteralNode,\n isVariableNode,\n isSubstitutionNode,\n isGlobNode,\n isConcatNode,\n} from \"./parser/index.cjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions } from \"./interpreter/index.cjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.cjs\";\nexport {\n FileSystem,\n ReadOnlyFileSystem,\n type Permission,\n type PermissionRules,\n type UnderlyingFS,\n} from \"./fs/index.cjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.cjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.cjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation } from \"./utils/index.cjs\";\n"
|
|
5
|
+
"// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.cjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.cjs\";\n\n// Types\nexport type {\n VirtualFS,\n FileStat,\n Command,\n CommandContext,\n Stdin,\n Stdout,\n Stderr,\n OutputCollector,\n ExecResult,\n ShellConfig,\n RawValue,\n} from \"./types.cjs\";\nexport { isRawValue } from \"./types.cjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.cjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.cjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.cjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.cjs\";\nexport type {\n ASTNode,\n Redirect,\n CommandNode,\n PipelineNode,\n AndNode,\n OrNode,\n SequenceNode,\n LiteralNode,\n VariableNode,\n SubstitutionNode,\n GlobNode,\n ConcatNode,\n IfNode,\n ForNode,\n WhileNode,\n UntilNode,\n CaseNode,\n CaseClause,\n ArithmeticNode,\n} from \"./parser/index.cjs\";\nexport {\n isCommandNode,\n isPipelineNode,\n isAndNode,\n isOrNode,\n isSequenceNode,\n isLiteralNode,\n isVariableNode,\n isSubstitutionNode,\n isGlobNode,\n isConcatNode,\n isIfNode,\n isForNode,\n isWhileNode,\n isUntilNode,\n isCaseNode,\n isArithmeticNode,\n} from \"./parser/index.cjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter/index.cjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.cjs\";\nexport {\n FileSystem,\n ReadOnlyFileSystem,\n type Permission,\n type PermissionRules,\n type UnderlyingFS,\n} from \"./fs/index.cjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.cjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.cjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation } from \"./utils/index.cjs\";\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACuD,IAAvD;AACuD,IAAvD;AAgB2B,IAA3B;AAGiD,IAAjD;AAG0C,IAA1C;AAI8B,IAA9B;AAuCO,IAjBP;AAoBwF,IAAxF;AAGgC,IAAhC;AAOO,IANP;AASuC,IAAvC;AACwF,IAAxF;AAG+C,IAA/C;",
|
|
8
|
+
"debugId": "A00B7F9271C525C564756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -30,10 +30,12 @@ var __export = (target, all) => {
|
|
|
30
30
|
var exports_interpreter = {};
|
|
31
31
|
__export(exports_interpreter, {
|
|
32
32
|
createCommandContext: () => import_context.createCommandContext,
|
|
33
|
-
Interpreter: () => import_interpreter.Interpreter
|
|
33
|
+
Interpreter: () => import_interpreter.Interpreter,
|
|
34
|
+
ContinueException: () => import_interpreter.ContinueException,
|
|
35
|
+
BreakException: () => import_interpreter.BreakException
|
|
34
36
|
});
|
|
35
37
|
module.exports = __toCommonJS(exports_interpreter);
|
|
36
38
|
var import_interpreter = require("./interpreter.cjs");
|
|
37
39
|
var import_context = require("./context.cjs");
|
|
38
40
|
|
|
39
|
-
//# debugId=
|
|
41
|
+
//# debugId=50C2A317A8EA744B64756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/interpreter/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"export { Interpreter, type InterpreterOptions } from \"./interpreter.cjs\";\nexport { createCommandContext, type ContextOptions } from \"./context.cjs\";\n"
|
|
5
|
+
"export { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter.cjs\";\nexport { createCommandContext, type ContextOptions } from \"./context.cjs\";\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAwF,IAAxF;AAC0D,IAA1D;",
|
|
8
|
+
"debugId": "50C2A317A8EA744B64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -29,19 +29,38 @@ var __export = (target, all) => {
|
|
|
29
29
|
// src/interpreter/interpreter.ts
|
|
30
30
|
var exports_interpreter = {};
|
|
31
31
|
__export(exports_interpreter, {
|
|
32
|
-
Interpreter: () => Interpreter
|
|
32
|
+
Interpreter: () => Interpreter,
|
|
33
|
+
ContinueException: () => ContinueException,
|
|
34
|
+
BreakException: () => BreakException
|
|
33
35
|
});
|
|
34
36
|
module.exports = __toCommonJS(exports_interpreter);
|
|
35
37
|
var import_context = require("./context.cjs");
|
|
36
38
|
var import_stdin = require("../io/stdin.cjs");
|
|
37
39
|
var import_stdout = require("../io/stdout.cjs");
|
|
38
40
|
|
|
41
|
+
class BreakException extends Error {
|
|
42
|
+
levels;
|
|
43
|
+
constructor(levels = 1) {
|
|
44
|
+
super("break");
|
|
45
|
+
this.levels = levels;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class ContinueException extends Error {
|
|
50
|
+
levels;
|
|
51
|
+
constructor(levels = 1) {
|
|
52
|
+
super("continue");
|
|
53
|
+
this.levels = levels;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
39
57
|
class Interpreter {
|
|
40
58
|
fs;
|
|
41
59
|
cwd;
|
|
42
60
|
env;
|
|
43
61
|
commands;
|
|
44
62
|
redirectObjects;
|
|
63
|
+
loopDepth = 0;
|
|
45
64
|
constructor(options) {
|
|
46
65
|
this.fs = options.fs;
|
|
47
66
|
this.cwd = options.cwd;
|
|
@@ -49,6 +68,9 @@ class Interpreter {
|
|
|
49
68
|
this.commands = options.commands;
|
|
50
69
|
this.redirectObjects = options.redirectObjects ?? {};
|
|
51
70
|
}
|
|
71
|
+
getLoopDepth() {
|
|
72
|
+
return this.loopDepth;
|
|
73
|
+
}
|
|
52
74
|
async execute(ast) {
|
|
53
75
|
const stdout = import_stdout.createStdout();
|
|
54
76
|
const stderr = import_stdout.createStderr();
|
|
@@ -73,6 +95,16 @@ class Interpreter {
|
|
|
73
95
|
return this.executeAnd(node.left, node.right, stdinSource, stdout, stderr);
|
|
74
96
|
case "or":
|
|
75
97
|
return this.executeOr(node.left, node.right, stdinSource, stdout, stderr);
|
|
98
|
+
case "if":
|
|
99
|
+
return this.executeIf(node, stdinSource, stdout, stderr);
|
|
100
|
+
case "for":
|
|
101
|
+
return this.executeFor(node, stdinSource, stdout, stderr);
|
|
102
|
+
case "while":
|
|
103
|
+
return this.executeWhile(node, stdinSource, stdout, stderr);
|
|
104
|
+
case "until":
|
|
105
|
+
return this.executeUntil(node, stdinSource, stdout, stderr);
|
|
106
|
+
case "case":
|
|
107
|
+
return this.executeCase(node, stdinSource, stdout, stderr);
|
|
76
108
|
default:
|
|
77
109
|
throw new Error(`Cannot execute node type: ${node.type}`);
|
|
78
110
|
}
|
|
@@ -145,6 +177,9 @@ class Interpreter {
|
|
|
145
177
|
try {
|
|
146
178
|
exitCode = await command(ctx);
|
|
147
179
|
} catch (err) {
|
|
180
|
+
if (err instanceof BreakException || err instanceof ContinueException) {
|
|
181
|
+
throw err;
|
|
182
|
+
}
|
|
148
183
|
const message = err instanceof Error ? err.message : String(err);
|
|
149
184
|
await stderr.writeText(`${name}: ${message}
|
|
150
185
|
`);
|
|
@@ -348,6 +383,183 @@ class Interpreter {
|
|
|
348
383
|
}
|
|
349
384
|
return this.executeNode(right, stdinSource, stdout, stderr);
|
|
350
385
|
}
|
|
386
|
+
async executeIf(node, stdinSource, stdout, stderr) {
|
|
387
|
+
const conditionCode = await this.executeNode(node.condition, stdinSource, stdout, stderr);
|
|
388
|
+
if (conditionCode === 0) {
|
|
389
|
+
return this.executeNode(node.thenBranch, stdinSource, stdout, stderr);
|
|
390
|
+
}
|
|
391
|
+
for (const elif of node.elifBranches) {
|
|
392
|
+
const elifConditionCode = await this.executeNode(elif.condition, stdinSource, stdout, stderr);
|
|
393
|
+
if (elifConditionCode === 0) {
|
|
394
|
+
return this.executeNode(elif.body, stdinSource, stdout, stderr);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (node.elseBranch) {
|
|
398
|
+
return this.executeNode(node.elseBranch, stdinSource, stdout, stderr);
|
|
399
|
+
}
|
|
400
|
+
return 0;
|
|
401
|
+
}
|
|
402
|
+
async executeFor(node, stdinSource, stdout, stderr) {
|
|
403
|
+
const expandedItems = [];
|
|
404
|
+
for (const item of node.items) {
|
|
405
|
+
const evaluated = await this.evaluateNode(item);
|
|
406
|
+
if (item.type === "glob") {
|
|
407
|
+
const matches = await this.fs.glob(evaluated, { cwd: this.cwd });
|
|
408
|
+
if (matches.length > 0) {
|
|
409
|
+
expandedItems.push(...matches);
|
|
410
|
+
} else {
|
|
411
|
+
expandedItems.push(evaluated);
|
|
412
|
+
}
|
|
413
|
+
} else {
|
|
414
|
+
expandedItems.push(evaluated);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (expandedItems.length === 0) {
|
|
418
|
+
return 0;
|
|
419
|
+
}
|
|
420
|
+
let lastExitCode = 0;
|
|
421
|
+
this.loopDepth++;
|
|
422
|
+
try {
|
|
423
|
+
for (const value of expandedItems) {
|
|
424
|
+
this.env[node.variable] = value;
|
|
425
|
+
try {
|
|
426
|
+
lastExitCode = await this.executeNode(node.body, stdinSource, stdout, stderr);
|
|
427
|
+
} catch (e) {
|
|
428
|
+
if (e instanceof ContinueException) {
|
|
429
|
+
if (e.levels > 1) {
|
|
430
|
+
e.levels--;
|
|
431
|
+
throw e;
|
|
432
|
+
}
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
if (e instanceof BreakException) {
|
|
436
|
+
if (e.levels > 1) {
|
|
437
|
+
e.levels--;
|
|
438
|
+
throw e;
|
|
439
|
+
}
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
throw e;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
} finally {
|
|
446
|
+
this.loopDepth--;
|
|
447
|
+
}
|
|
448
|
+
return lastExitCode;
|
|
449
|
+
}
|
|
450
|
+
async executeWhile(node, stdinSource, stdout, stderr) {
|
|
451
|
+
let lastExitCode = 0;
|
|
452
|
+
this.loopDepth++;
|
|
453
|
+
try {
|
|
454
|
+
while (true) {
|
|
455
|
+
const conditionCode = await this.executeNode(node.condition, stdinSource, stdout, stderr);
|
|
456
|
+
if (conditionCode !== 0) {
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
try {
|
|
460
|
+
lastExitCode = await this.executeNode(node.body, stdinSource, stdout, stderr);
|
|
461
|
+
} catch (e) {
|
|
462
|
+
if (e instanceof ContinueException) {
|
|
463
|
+
if (e.levels > 1) {
|
|
464
|
+
e.levels--;
|
|
465
|
+
throw e;
|
|
466
|
+
}
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
if (e instanceof BreakException) {
|
|
470
|
+
if (e.levels > 1) {
|
|
471
|
+
e.levels--;
|
|
472
|
+
throw e;
|
|
473
|
+
}
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
throw e;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
} finally {
|
|
480
|
+
this.loopDepth--;
|
|
481
|
+
}
|
|
482
|
+
return lastExitCode;
|
|
483
|
+
}
|
|
484
|
+
async executeUntil(node, stdinSource, stdout, stderr) {
|
|
485
|
+
let lastExitCode = 0;
|
|
486
|
+
this.loopDepth++;
|
|
487
|
+
try {
|
|
488
|
+
while (true) {
|
|
489
|
+
const conditionCode = await this.executeNode(node.condition, stdinSource, stdout, stderr);
|
|
490
|
+
if (conditionCode === 0) {
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
try {
|
|
494
|
+
lastExitCode = await this.executeNode(node.body, stdinSource, stdout, stderr);
|
|
495
|
+
} catch (e) {
|
|
496
|
+
if (e instanceof ContinueException) {
|
|
497
|
+
if (e.levels > 1) {
|
|
498
|
+
e.levels--;
|
|
499
|
+
throw e;
|
|
500
|
+
}
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
if (e instanceof BreakException) {
|
|
504
|
+
if (e.levels > 1) {
|
|
505
|
+
e.levels--;
|
|
506
|
+
throw e;
|
|
507
|
+
}
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
throw e;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
} finally {
|
|
514
|
+
this.loopDepth--;
|
|
515
|
+
}
|
|
516
|
+
return lastExitCode;
|
|
517
|
+
}
|
|
518
|
+
async executeCase(node, stdinSource, stdout, stderr) {
|
|
519
|
+
const word = await this.evaluateNode(node.word);
|
|
520
|
+
for (const clause of node.clauses) {
|
|
521
|
+
for (const patternNode of clause.patterns) {
|
|
522
|
+
const pattern = await this.evaluateNode(patternNode);
|
|
523
|
+
if (this.matchCasePattern(word, pattern)) {
|
|
524
|
+
return this.executeNode(clause.body, stdinSource, stdout, stderr);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return 0;
|
|
529
|
+
}
|
|
530
|
+
matchCasePattern(word, pattern) {
|
|
531
|
+
let regexStr = "^";
|
|
532
|
+
for (let i = 0;i < pattern.length; i++) {
|
|
533
|
+
const char = pattern[i];
|
|
534
|
+
if (char === "*") {
|
|
535
|
+
regexStr += ".*";
|
|
536
|
+
} else if (char === "?") {
|
|
537
|
+
regexStr += ".";
|
|
538
|
+
} else if (char === "[") {
|
|
539
|
+
let j = i + 1;
|
|
540
|
+
while (j < pattern.length && pattern[j] !== "]") {
|
|
541
|
+
j++;
|
|
542
|
+
}
|
|
543
|
+
if (j < pattern.length) {
|
|
544
|
+
regexStr += pattern.slice(i, j + 1);
|
|
545
|
+
i = j;
|
|
546
|
+
} else {
|
|
547
|
+
regexStr += "\\[";
|
|
548
|
+
}
|
|
549
|
+
} else if (/[.+^${}()|\\]/.test(char)) {
|
|
550
|
+
regexStr += "\\" + char;
|
|
551
|
+
} else {
|
|
552
|
+
regexStr += char;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
regexStr += "$";
|
|
556
|
+
try {
|
|
557
|
+
const regex = new RegExp(regexStr);
|
|
558
|
+
return regex.test(word);
|
|
559
|
+
} catch {
|
|
560
|
+
return word === pattern;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
351
563
|
async evaluateNode(node, localEnv) {
|
|
352
564
|
const env = localEnv ?? this.env;
|
|
353
565
|
switch (node.type) {
|
|
@@ -369,10 +581,177 @@ class Interpreter {
|
|
|
369
581
|
const output = await subStdout.collect();
|
|
370
582
|
return output.toString("utf-8").replace(/\n+$/, "");
|
|
371
583
|
}
|
|
584
|
+
case "arithmetic": {
|
|
585
|
+
const result = this.evaluateArithmetic(node.expression, env);
|
|
586
|
+
return String(result);
|
|
587
|
+
}
|
|
372
588
|
default:
|
|
373
589
|
throw new Error(`Cannot evaluate node type: ${node.type}`);
|
|
374
590
|
}
|
|
375
591
|
}
|
|
592
|
+
evaluateArithmetic(expression, env) {
|
|
593
|
+
let expandedExpr = expression;
|
|
594
|
+
expandedExpr = expandedExpr.replace(/\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g, (_, name) => {
|
|
595
|
+
return env[name] ?? "0";
|
|
596
|
+
});
|
|
597
|
+
expandedExpr = expandedExpr.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, name) => {
|
|
598
|
+
return env[name] ?? "0";
|
|
599
|
+
});
|
|
600
|
+
expandedExpr = expandedExpr.replace(/\b([a-zA-Z_][a-zA-Z0-9_]*)\b/g, (match) => {
|
|
601
|
+
if (/^\d+$/.test(match))
|
|
602
|
+
return match;
|
|
603
|
+
return env[match] ?? "0";
|
|
604
|
+
});
|
|
605
|
+
return this.parseArithmeticExpr(expandedExpr.trim());
|
|
606
|
+
}
|
|
607
|
+
parseArithmeticExpr(expr) {
|
|
608
|
+
let pos = 0;
|
|
609
|
+
const skipWhitespace = () => {
|
|
610
|
+
while (pos < expr.length && /\s/.test(expr[pos]))
|
|
611
|
+
pos++;
|
|
612
|
+
};
|
|
613
|
+
const parseNumber = () => {
|
|
614
|
+
skipWhitespace();
|
|
615
|
+
let numStr = "";
|
|
616
|
+
const negative = expr[pos] === "-";
|
|
617
|
+
if (negative) {
|
|
618
|
+
pos++;
|
|
619
|
+
skipWhitespace();
|
|
620
|
+
}
|
|
621
|
+
while (pos < expr.length && /[0-9]/.test(expr[pos])) {
|
|
622
|
+
numStr += expr[pos];
|
|
623
|
+
pos++;
|
|
624
|
+
}
|
|
625
|
+
if (numStr === "")
|
|
626
|
+
return 0;
|
|
627
|
+
return negative ? -parseInt(numStr, 10) : parseInt(numStr, 10);
|
|
628
|
+
};
|
|
629
|
+
const parsePrimary = () => {
|
|
630
|
+
skipWhitespace();
|
|
631
|
+
if (expr[pos] === "(") {
|
|
632
|
+
pos++;
|
|
633
|
+
const result = parseOr();
|
|
634
|
+
skipWhitespace();
|
|
635
|
+
if (expr[pos] === ")")
|
|
636
|
+
pos++;
|
|
637
|
+
return result;
|
|
638
|
+
}
|
|
639
|
+
return parseNumber();
|
|
640
|
+
};
|
|
641
|
+
const parseUnary = () => {
|
|
642
|
+
skipWhitespace();
|
|
643
|
+
if (expr[pos] === "-" && !/[0-9]/.test(expr[pos + 1] ?? "")) {
|
|
644
|
+
pos++;
|
|
645
|
+
return -parseUnary();
|
|
646
|
+
}
|
|
647
|
+
if (expr[pos] === "!") {
|
|
648
|
+
pos++;
|
|
649
|
+
return parseUnary() === 0 ? 1 : 0;
|
|
650
|
+
}
|
|
651
|
+
return parsePrimary();
|
|
652
|
+
};
|
|
653
|
+
const parseMulDiv = () => {
|
|
654
|
+
let left = parseUnary();
|
|
655
|
+
while (true) {
|
|
656
|
+
skipWhitespace();
|
|
657
|
+
const op = expr[pos];
|
|
658
|
+
if (op === "*" || op === "/" || op === "%") {
|
|
659
|
+
pos++;
|
|
660
|
+
const right = parseUnary();
|
|
661
|
+
if (op === "*")
|
|
662
|
+
left = left * right;
|
|
663
|
+
else if (op === "/")
|
|
664
|
+
left = right === 0 ? 0 : Math.trunc(left / right);
|
|
665
|
+
else
|
|
666
|
+
left = right === 0 ? 0 : left % right;
|
|
667
|
+
} else {
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return left;
|
|
672
|
+
};
|
|
673
|
+
const parseAddSub = () => {
|
|
674
|
+
let left = parseMulDiv();
|
|
675
|
+
while (true) {
|
|
676
|
+
skipWhitespace();
|
|
677
|
+
const op = expr[pos];
|
|
678
|
+
if (op === "+" || op === "-" && !/[0-9]/.test(expr[pos + 1] ?? "")) {
|
|
679
|
+
pos++;
|
|
680
|
+
const right = parseMulDiv();
|
|
681
|
+
if (op === "+")
|
|
682
|
+
left = left + right;
|
|
683
|
+
else
|
|
684
|
+
left = left - right;
|
|
685
|
+
} else {
|
|
686
|
+
break;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return left;
|
|
690
|
+
};
|
|
691
|
+
const parseComparison = () => {
|
|
692
|
+
let left = parseAddSub();
|
|
693
|
+
while (true) {
|
|
694
|
+
skipWhitespace();
|
|
695
|
+
if (expr.slice(pos, pos + 2) === "<=") {
|
|
696
|
+
pos += 2;
|
|
697
|
+
const right = parseAddSub();
|
|
698
|
+
left = left <= right ? 1 : 0;
|
|
699
|
+
} else if (expr.slice(pos, pos + 2) === ">=") {
|
|
700
|
+
pos += 2;
|
|
701
|
+
const right = parseAddSub();
|
|
702
|
+
left = left >= right ? 1 : 0;
|
|
703
|
+
} else if (expr.slice(pos, pos + 2) === "==") {
|
|
704
|
+
pos += 2;
|
|
705
|
+
const right = parseAddSub();
|
|
706
|
+
left = left === right ? 1 : 0;
|
|
707
|
+
} else if (expr.slice(pos, pos + 2) === "!=") {
|
|
708
|
+
pos += 2;
|
|
709
|
+
const right = parseAddSub();
|
|
710
|
+
left = left !== right ? 1 : 0;
|
|
711
|
+
} else if (expr[pos] === "<") {
|
|
712
|
+
pos++;
|
|
713
|
+
const right = parseAddSub();
|
|
714
|
+
left = left < right ? 1 : 0;
|
|
715
|
+
} else if (expr[pos] === ">") {
|
|
716
|
+
pos++;
|
|
717
|
+
const right = parseAddSub();
|
|
718
|
+
left = left > right ? 1 : 0;
|
|
719
|
+
} else {
|
|
720
|
+
break;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return left;
|
|
724
|
+
};
|
|
725
|
+
const parseAnd = () => {
|
|
726
|
+
let left = parseComparison();
|
|
727
|
+
while (true) {
|
|
728
|
+
skipWhitespace();
|
|
729
|
+
if (expr.slice(pos, pos + 2) === "&&") {
|
|
730
|
+
pos += 2;
|
|
731
|
+
const right = parseComparison();
|
|
732
|
+
left = left !== 0 && right !== 0 ? 1 : 0;
|
|
733
|
+
} else {
|
|
734
|
+
break;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return left;
|
|
738
|
+
};
|
|
739
|
+
const parseOr = () => {
|
|
740
|
+
let left = parseAnd();
|
|
741
|
+
while (true) {
|
|
742
|
+
skipWhitespace();
|
|
743
|
+
if (expr.slice(pos, pos + 2) === "||") {
|
|
744
|
+
pos += 2;
|
|
745
|
+
const right = parseAnd();
|
|
746
|
+
left = left !== 0 || right !== 0 ? 1 : 0;
|
|
747
|
+
} else {
|
|
748
|
+
break;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return left;
|
|
752
|
+
};
|
|
753
|
+
return parseOr();
|
|
754
|
+
}
|
|
376
755
|
setCwd(cwd) {
|
|
377
756
|
this.cwd = cwd;
|
|
378
757
|
}
|
|
@@ -387,4 +766,4 @@ class Interpreter {
|
|
|
387
766
|
}
|
|
388
767
|
}
|
|
389
768
|
|
|
390
|
-
//# debugId=
|
|
769
|
+
//# debugId=E87B7B56CD04A5F564756E2164756E21
|