Added exit builtin

This commit is contained in:
2025-03-30 16:58:43 -04:00
parent 425f5ab3bf
commit ae43f4afbf

View File

@@ -19,17 +19,17 @@ pub fn main() !void {
const p = try getPrompt(allocator); const p = try getPrompt(allocator);
defer allocator.free(p); defer allocator.free(p);
var iteration: u32 = 0; var shell_state: ShellState = .{};
while (try ln.linenoise(p)) |input| { while (try ln.linenoise(p)) |input| {
defer allocator.free(input); defer allocator.free(input);
if (input.len > 0) { if (input.len > 0) {
iteration += 1; shell_state.iteration += 1;
try ln.history.add(input); try ln.history.add(input);
const command = try tokenizeCommand(input, allocator); const command = try tokenizeCommand(input, allocator);
defer allocator.free(command); defer allocator.free(command);
if (try mathTest(rand, 100, iteration)) { if (!shell_state.should_test or try mathTest(rand, 100, shell_state.iteration)) {
_ = runCommand(command, allocator) catch |err| switch (err) { _ = execCommand(command, &shell_state, allocator) catch |err| switch (err) {
error.FileNotFound => print("mash: {s}: command not found\n", .{command[0]}), error.FileNotFound => print("mash: {s}: command not found\n", .{command[0]}),
error.AccessDenied => print("mash: {s}: Permission denied\n", .{command[0]}), error.AccessDenied => print("mash: {s}: Permission denied\n", .{command[0]}),
else => print("Unkown error: {}\n", .{err}), else => print("Unkown error: {}\n", .{err}),
@@ -42,9 +42,16 @@ pub fn main() !void {
, .{}); , .{});
} }
} }
if (shell_state.should_exit) break;
} }
} }
const ShellState = struct {
iteration: u32 = 0,
should_test: bool = true,
should_exit: bool = false,
};
const Operator = enum(u8) { const Operator = enum(u8) {
add = 0, add = 0,
subtract, subtract,
@@ -70,48 +77,55 @@ const Operator = enum(u8) {
.divide => @divTrunc(a, b), .divide => @divTrunc(a, b),
}; };
} }
};
/// Gets add or subtract for the first three commands. /// Gets add or subtract for the first three commands.
/// Includes multiplication and division after the first three. /// Includes multiplication and division after the first three.
fn getRandOp(rand: Random, iteration: u32) Operator { fn rand(r: Random, iteration: u32) Self {
if (iteration > 3) { if (iteration > 3) {
return rand.enumValue(Operator); return r.enumValue(Self);
} else { } else {
return @enumFromInt(rand.uintAtMost(u8, 1)); return @enumFromInt(r.uintAtMost(u8, 1));
}
} }
} };
/// return true if the user passed, false if the user did not. /// return true if the user passed, false if the user did not.
fn mathTest(rand: Random, limit: i32, iteration: u32) !bool { fn mathTest(rand: Random, limit: i32, iteration: u32) !bool {
const op = Operator.rand(rand, iteration);
// const operators = comptime .{
// .{ "+", add },
// .{ "-", subtract },
// .{ "*", multiply },
// .{ "/", divide },
// };
// const ops = StaticStringMap(BinaryOperator).initComptime(operators);
// _ = ops;
const op = getRandOp(rand, iteration);
const num1 = rand.intRangeAtMost(i32, 1, limit); const num1 = rand.intRangeAtMost(i32, 1, limit);
const num2 = rand.intRangeAtMost(i32, 1, limit); const num2 = rand.intRangeAtMost(i32, 1, limit);
const answer = op.apply(num1, num2); const answer = op.apply(num1, num2);
var input: i32 = undefined;
// print("release mode {any}\n", .{std.builtin.mode});
if (builtin.mode == .Debug) { if (builtin.mode == .Debug) {
print("Answer: {d}\n", .{answer}); print("Answer: {d}\n", .{answer});
} }
print("{d} {s} {d} = ", .{ num1, op.toString(), num2 }); print("{d} {s} {d} = ", .{ num1, op.toString(), num2 });
input = readInt(stdin) catch |err| { return answer == while (true) {
print("oops: {any}\n", .{err}); break readInt(stdin) catch |err| switch (err) {
return err; error.InvalidCharacter, error.EndOfStream => continue,
else => return err,
};
}; };
}
return input == answer; const BuiltinCommand = *const fn (*ShellState, [][]const u8) anyerror!void;
fn exitFn(shell_state: *ShellState, command: [][]const u8) !void {
_ = command;
shell_state.*.should_exit = true;
}
fn execCommand(command: [][]const u8, shell_state: *ShellState, allocator: Allocator) !u8 {
const builtins = comptime .{.{ "exit", exitFn }};
const builtinMap = StaticStringMap(BuiltinCommand).initComptime(builtins);
if (builtinMap.has(command[0])) {
try builtinMap.get(command[0]).?(shell_state, command);
return 0;
} else {
return runCommand(command, allocator);
}
} }
fn runCommand(command: [][]const u8, allocator: Allocator) !u8 { fn runCommand(command: [][]const u8, allocator: Allocator) !u8 {