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