fix(commands): substitute parsing bug
There was a bug in the parsing logic that caused a substitution command like `s/typo/correction` to crash the bot. Correct command is of course `s/typo/correction/`, but now it at least shouldn't crash.
This commit is contained in:
parent
4e11cc9ea1
commit
8b15398196
2 changed files with 33 additions and 12 deletions
|
|
@ -1,6 +1,6 @@
|
|||
const std = @import("std");
|
||||
|
||||
const parser = @import("root.zig").parser;
|
||||
const Parser = @import("root.zig").parser.Parser;
|
||||
|
||||
/// UserCommand represents the commands that ordinary IRC users can use.
|
||||
pub const UserCommand = union(enum) {
|
||||
|
|
@ -10,23 +10,34 @@ pub const UserCommand = union(enum) {
|
|||
help: void,
|
||||
|
||||
pub fn parse(nick: []const u8, text: []const u8) ?UserCommand {
|
||||
const original = parser.init(text);
|
||||
const original = Parser.init(text);
|
||||
if (original.consume_str("!help")) |_| {
|
||||
return .help;
|
||||
}
|
||||
|
||||
if (original.consume_char('s')) |substitute| {
|
||||
const delim_parser, const delim = substitute.take_char();
|
||||
const log_prefix = "parsing substitute command";
|
||||
var parser = substitute;
|
||||
parser, const delim = parser.take_char();
|
||||
if (std.ascii.isAlphanumeric(delim)) {
|
||||
std.log.debug("parsing substitute command: delimiter cannot be a whitespace: \"{s}\"", .{text});
|
||||
std.log.debug("{s}: delimiter cannot be a whitespace: \"{s}\"", .{ log_prefix, text });
|
||||
return null;
|
||||
}
|
||||
const typo_parser, const typo = delim_parser.take_until_char(delim);
|
||||
const correction_parser, const correction = typo_parser.consume_char(delim).?.take_until_char(delim);
|
||||
if (correction_parser.consume_char(delim) == null) {
|
||||
std.log.debug("parsing substitute command: missing an ending '/' in \"{s}\"", .{text});
|
||||
var result = parser.take_until_char(delim);
|
||||
if (result == null) {
|
||||
std.log.debug(
|
||||
"{s}: cannot find typo, expecting a message on the form 's{}TYPO{}CORRECTION{}', but got {s}",
|
||||
.{ log_prefix, delim, delim, delim, text },
|
||||
);
|
||||
return null;
|
||||
}
|
||||
parser, const typo = result.?;
|
||||
result = parser.consume_char(delim).?.take_until_char(delim);
|
||||
if (result == null) {
|
||||
std.log.debug("{s}: missing an ending '/' in \"{s}\"", .{ log_prefix, text });
|
||||
return null;
|
||||
}
|
||||
parser, const correction = result.?;
|
||||
return .{
|
||||
.substitute = .{
|
||||
.author = nick,
|
||||
|
|
@ -50,7 +61,7 @@ pub const AdminCommand = union(enum) {
|
|||
err: struct { message: []const u8 },
|
||||
|
||||
pub fn parse(text: []const u8) ?AdminCommand {
|
||||
const original = parser.init(text);
|
||||
const original = Parser.init(text);
|
||||
if (original.consume_char('!')) |command| {
|
||||
if (command.consume_str("status")) |_| {
|
||||
return .status;
|
||||
|
|
@ -97,6 +108,14 @@ test "can parse s/hello/world/ successful" {
|
|||
);
|
||||
}
|
||||
|
||||
test "can parse s/hello/world and report failure" {
|
||||
try std.testing.expectEqualDeep(null, UserCommand.parse("jassob", "s/hello/world"));
|
||||
}
|
||||
|
||||
test "can parse s/hello|world| and report failure" {
|
||||
try std.testing.expectEqualDeep(null, UserCommand.parse("jassob", "s/hello/world"));
|
||||
}
|
||||
|
||||
test "correctly ignores non-messages when trying to parse" {
|
||||
try std.testing.expectEqualDeep(null, UserCommand.parse("jassob", "Hello, world"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,9 +61,11 @@ pub const Parser = struct {
|
|||
//
|
||||
// Returns a new parser window that starts after idx and the
|
||||
// extracted byte slice.
|
||||
pub fn take_until_char(self: *const Parser, c: u8) struct { Parser, []const u8 } {
|
||||
const idx = std.mem.indexOfScalar(u8, self.rest, c) orelse unreachable;
|
||||
return .{ self.seek(idx), self.rest[0..idx] };
|
||||
pub fn take_until_char(self: *const Parser, c: u8) ?struct { Parser, []const u8 } {
|
||||
if (std.mem.indexOfScalar(u8, self.rest, c)) |idx| {
|
||||
return .{ self.seek(idx), self.rest[0..idx] };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Take the current character and advance the parser one step.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue