2020-08-21 21:49:22 +00:00
|
|
|
use nom::{alt, complete, named, tag, take_while, tuple, IResult};
|
2020-04-21 03:15:13 +00:00
|
|
|
|
2020-08-21 21:49:22 +00:00
|
|
|
use crate::cofd::parser::{create_chance_die, parse_dice_pool};
|
2020-08-28 22:02:41 +00:00
|
|
|
use crate::commands::{Command, HelpCommand, PoolRollCommand, RollCommand};
|
2020-04-21 03:15:13 +00:00
|
|
|
use crate::dice::parser::parse_element_expression;
|
2020-08-28 22:02:41 +00:00
|
|
|
use crate::help::parse_help_topic;
|
|
|
|
use crate::parser::{eat_whitespace, trim};
|
2020-04-21 03:15:13 +00:00
|
|
|
|
|
|
|
// Parse a roll expression.
|
2020-04-21 06:15:18 +00:00
|
|
|
fn parse_roll(input: &str) -> IResult<&str, Box<dyn Command>> {
|
2020-04-21 03:15:13 +00:00
|
|
|
let (input, _) = eat_whitespace(input)?;
|
|
|
|
let (input, expression) = parse_element_expression(input)?;
|
2020-04-21 06:15:18 +00:00
|
|
|
Ok((input, Box::new(RollCommand(expression))))
|
2020-04-21 03:15:13 +00:00
|
|
|
}
|
|
|
|
|
2020-08-21 21:49:22 +00:00
|
|
|
fn parse_pool_roll(input: &str) -> IResult<&str, Box<dyn Command>> {
|
|
|
|
let (input, _) = eat_whitespace(input)?;
|
|
|
|
let (input, pool) = parse_dice_pool(input)?;
|
|
|
|
Ok((input, Box::new(PoolRollCommand(pool))))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn chance_die() -> IResult<&'static str, Box<dyn Command>> {
|
|
|
|
let (input, pool) = create_chance_die()?;
|
|
|
|
Ok((input, Box::new(PoolRollCommand(pool))))
|
|
|
|
}
|
|
|
|
|
2020-08-28 22:02:41 +00:00
|
|
|
fn help(topic: &str) -> IResult<&str, Box<dyn Command>> {
|
|
|
|
let (topic, _) = eat_whitespace(topic)?;
|
|
|
|
let topic = parse_help_topic(&trim(topic));
|
|
|
|
Ok(("", Box::new(HelpCommand(topic))))
|
|
|
|
}
|
|
|
|
|
2020-04-21 06:15:18 +00:00
|
|
|
/// Potentially parse a command expression. If we recognize the command, an error should be raised
|
|
|
|
/// if the command is misparsed. If we don't recognize the command, ignore it and return none
|
2020-04-21 06:07:03 +00:00
|
|
|
pub fn parse_command(original_input: &str) -> IResult<&str, Option<Box<dyn Command>>> {
|
|
|
|
let (input, _) = eat_whitespace(original_input)?;
|
2020-08-21 21:49:22 +00:00
|
|
|
|
|
|
|
//Parser understands either specific !commands with no input, or any !command with extra input.
|
|
|
|
named!(command(&str) -> (&str, &str), tuple!(
|
|
|
|
complete!(tag!("!")),
|
|
|
|
alt!(
|
2020-08-28 22:02:41 +00:00
|
|
|
//TODO figure out how to gracefully handle arbitrary single commands.
|
|
|
|
complete!(tag!("chance")) |
|
|
|
|
complete!(tag!("help")) |
|
2020-08-21 21:49:22 +00:00
|
|
|
complete!(take_while!(char::is_alphabetic))
|
|
|
|
)
|
|
|
|
));
|
|
|
|
|
2020-04-21 06:07:03 +00:00
|
|
|
let (input, command) = match command(input) {
|
|
|
|
// Strip the exclamation mark
|
|
|
|
Ok((input, (_, result))) => (input, result),
|
2020-08-28 22:02:41 +00:00
|
|
|
Err(_e) => {
|
|
|
|
return Ok((original_input, None));
|
|
|
|
}
|
2020-04-21 06:07:03 +00:00
|
|
|
};
|
2020-08-21 21:49:22 +00:00
|
|
|
|
2020-04-21 06:15:18 +00:00
|
|
|
match command {
|
|
|
|
"r" | "roll" => parse_roll(input).map(|(input, command)| (input, Some(command))),
|
2020-08-21 21:49:22 +00:00
|
|
|
"rp" | "pool" => parse_pool_roll(input).map(|(input, command)| (input, Some(command))),
|
|
|
|
"chance" => chance_die().map(|(input, command)| (input, Some(command))),
|
2020-08-28 22:02:41 +00:00
|
|
|
"help" => help(input).map(|(input, command)| (input, Some(command))),
|
2020-04-21 06:07:03 +00:00
|
|
|
// No recognized command, ignore this.
|
2020-04-21 06:15:18 +00:00
|
|
|
_ => Ok((original_input, None)),
|
|
|
|
}
|
2020-04-21 03:15:13 +00:00
|
|
|
}
|