diff --git a/src/lang.zig b/src/lang.zig index cf5b1e6..7b6ec82 100644 --- a/src/lang.zig +++ b/src/lang.zig @@ -6,6 +6,7 @@ pub const ParseError = error{ NoCommandGiven, UnknownCommand, ArgRequired, + FloatParseFail, }; pub const CommandType = enum { @@ -232,6 +233,40 @@ pub const Lang = struct { return null; } + fn expectSingle(self: *Lang, args: ArgList) !void { + if (args.len != 1) { + std.debug.warn("expected 1 argument, found {}\n", args.len); + return error.ArgRequired; + } + } + + fn expectFloat(self: *Lang, count: usize, args: ArgList) !void { + var i: usize = 0; + + if (args.len != count) { + std.debug.warn("expected {} arguments, found {}\n", count, args.len); + return error.ArgRequired; + } + + while (i < count) : (i += 1) { + var arg = args.at(i); + + _ = std.fmt.parseFloat(f32, arg) catch |err| { + std.debug.warn("failed to parse f32: {}\n", err); + return error.FloatParseFail; + }; + } + } + + fn validateCommand(self: *Lang, cmd: *Command) !void { + switch (cmd.command) { + .Quicksave, .Noop => {}, + .Load, .RunQS => try self.expectSingle(cmd.args), + .Amp => try self.expectFloat(3, cmd.args), + else => std.debug.warn("WARN unchecked command {}\n", cmd.command), + } + } + pub fn parse(self: *Lang, data: []const u8) !CommandList { var splitted_it = std.mem.separate(data, ";"); try self.fillKeywords(); @@ -261,14 +296,17 @@ pub const Lang = struct { } var args = ArgList.init(self.allocator); - while (tok_it.next()) |arg| { try args.append(arg); } // construct final Command based on command var cmd_ptr = try self.allocator.create(Command); + errdefer self.allocator.destroy(cmd_ptr); + cmd_ptr.* = Command{ .command = ctype, .args = args }; + try self.validateCommand(cmd_ptr); + try cmds.append(cmd_ptr); }