Added exit builtin
This commit is contained in:
74
src/main.zig
74
src/main.zig
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user