Skip to content

Commit c571d47

Browse files
committed
core: Updated ShellInterpreter
1 parent 10fa17a commit c571d47

3 files changed

Lines changed: 243 additions & 64 deletions

File tree

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { EXIT_CODE } from "../../../constants";
2+
import { VirtualFolder } from "../../virtual-drive";
3+
import { Command } from "../command";
4+
import { Shell } from "../shell";
5+
6+
const toExitCode = (result: boolean) => result ? EXIT_CODE.success : EXIT_CODE.generalError;
7+
8+
const UNARY_OPERATORS: Record<string, (value: string, workingDirectory: VirtualFolder) => boolean> = {
9+
"-z": (value) => value.length === 0,
10+
"-n": (value) => value.length > 0,
11+
"-f": (value, workingDirectory) => workingDirectory.navigate(value)?.isFile() ?? false,
12+
"-d": (value, workingDirectory) => workingDirectory.navigate(value)?.isFolder() ?? false,
13+
"-e": (value, workingDirectory) => workingDirectory.navigate(value) != null,
14+
};
15+
16+
const BINARY_OPERATORS: Record<string, (left: string, right: string) => boolean> = {
17+
"=": (left, right) => left === right,
18+
"==": (left, right) => left === right,
19+
"!=": (left, right) => left !== right,
20+
"-eq": (left, right) => Number(left) === Number(right),
21+
"-ne": (left, right) => Number(left) !== Number(right),
22+
"-lt": (left, right) => Number(left) < Number(right),
23+
"-le": (left, right) => Number(left) <= Number(right),
24+
"-gt": (left, right) => Number(left) > Number(right),
25+
"-ge": (left, right) => Number(left) >= Number(right),
26+
};
27+
28+
class ConditionalParser {
29+
tokens: string[];
30+
index = 0;
31+
workingDirectory: VirtualFolder;
32+
33+
constructor(tokens: string[], workingDirectory: VirtualFolder) {
34+
this.tokens = tokens;
35+
this.workingDirectory = workingDirectory;
36+
}
37+
38+
parse(): boolean {
39+
return this.parseOr();
40+
}
41+
42+
parseOr(): boolean {
43+
let result = this.parseAnd();
44+
while (this.tokens[this.index] === "||") {
45+
this.index++;
46+
result = this.parseAnd() || result;
47+
}
48+
return result;
49+
}
50+
51+
parseAnd(): boolean {
52+
let result = this.parsePrimary();
53+
while (this.tokens[this.index] === "&&") {
54+
this.index++;
55+
result = this.parsePrimary() && result;
56+
}
57+
return result;
58+
}
59+
60+
parsePrimary(): boolean {
61+
const token = this.tokens[this.index++];
62+
63+
if (token === "!") return !this.parsePrimary();
64+
65+
if (token === "(") {
66+
const result = this.parseOr();
67+
this.index++; // Skip ")"
68+
return result;
69+
}
70+
71+
if (token in UNARY_OPERATORS) {
72+
const value = this.tokens[this.index++];
73+
return UNARY_OPERATORS[token](value, this.workingDirectory);
74+
}
75+
76+
const nextToken = this.tokens[this.index];
77+
if (nextToken in BINARY_OPERATORS) {
78+
this.index++;
79+
const right = this.tokens[this.index++];
80+
return BINARY_OPERATORS[nextToken](token, right);
81+
}
82+
83+
return token.length > 0;
84+
}
85+
}
86+
87+
export const doubleBracket = new Command()
88+
.setName("[[")
89+
.setRequireArgs(true)
90+
.setManual({
91+
purpose: "Evaluate a conditional expression",
92+
usage: "[[ expression ]]",
93+
})
94+
.setExecute(function(this: Command, args, { stderr, workingDirectory }) {
95+
if (args.at(-1) !== "]]")
96+
return Shell.writeError(stderr, this.name, "missing `]]'");
97+
98+
const tokens = args.slice(0, -1);
99+
if (tokens.length === 0) return EXIT_CODE.generalError;
100+
101+
try {
102+
return toExitCode(new ConditionalParser(tokens, workingDirectory).parse());
103+
} catch {
104+
return EXIT_CODE.misuseOfBuiltins;
105+
}
106+
});

packages/core/src/features/shell/commands/printenv.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ export const printenv = new Command()
1313
args.forEach((arg) => {
1414
const value = exportedVars[arg];
1515
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
16-
if (value !== undefined) stdout.write(`${value}\n`);
16+
if (value !== undefined) stdout.write(`${value}`);
1717
});
1818
return;
1919
}
2020

2121
Object.entries(exportedVars).forEach(([key, value]) => {
22-
stdout.write(`${key}=${value}\n`);
22+
stdout.write(`${key}=${value}`);
2323
});
2424
});

0 commit comments

Comments
 (0)