1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

Fix clippy issues and add a couple tests to dispatcher

This commit is contained in:
mat 2022-04-17 15:57:28 -05:00
parent 10cd1733cb
commit 2e90422561
33 changed files with 158 additions and 79 deletions

View file

@ -41,21 +41,21 @@ impl<S: Any + Clone> ArgumentBuilder<S> {
} }
} }
pub fn then(&mut self, node: ArgumentBuilder<S>) -> &mut Self { pub fn then(&mut self, node: ArgumentBuilder<S>) -> Self {
let built_node = node.build(); let built_node = node.build();
let name = built_node.name(); let name = built_node.name();
let node_reference = Rc::new(RefCell::new(built_node.clone())); let node_reference = Rc::new(RefCell::new(built_node.clone()));
self.children self.children
.insert(name.to_string(), node_reference.clone()); .insert(name.to_string(), node_reference.clone());
match &built_node.value { match &built_node.value {
ArgumentBuilderType::Literal(literal) => { ArgumentBuilderType::Literal(_) => {
self.literals.insert(name.to_string(), node_reference); self.literals.insert(name.to_string(), node_reference);
} }
ArgumentBuilderType::Argument(argument) => { ArgumentBuilderType::Argument(_) => {
self.arguments.insert(name.to_string(), node_reference); self.arguments.insert(name.to_string(), node_reference);
} }
} }
self self.clone()
} }
pub fn executes<F>(&mut self, f: F) -> Self pub fn executes<F>(&mut self, f: F) -> Self

View file

@ -1,14 +1,5 @@
use std::any::Any; use std::any::Any;
use crate::{
context::CommandContextBuilder,
exceptions::{
builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException,
},
string_range::StringRange,
string_reader::StringReader,
};
use super::argument_builder::{ArgumentBuilder, ArgumentBuilderType}; use super::argument_builder::{ArgumentBuilder, ArgumentBuilderType};
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]

View file

@ -16,7 +16,7 @@ impl Argument {
pub fn new(name: &str, parser: Rc<dyn Parser>) -> Self { pub fn new(name: &str, parser: Rc<dyn Parser>) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
parser: parser, parser,
} }
} }
@ -41,9 +41,6 @@ impl Debug for Argument {
} }
/// Shortcut for creating a new argument builder node. /// Shortcut for creating a new argument builder node.
pub fn argument<'a, S: Any + Clone>( pub fn argument<S: Any + Clone>(name: &str, parser: impl Parser + 'static) -> ArgumentBuilder<S> {
name: &'a str,
parser: impl Parser + 'static,
) -> ArgumentBuilder<S> {
ArgumentBuilder::new(Argument::new(name, Rc::new(parser)).into()) ArgumentBuilder::new(Argument::new(name, Rc::new(parser)).into())
} }

View file

@ -1,4 +1,4 @@
use std::{any::Any, cell::RefCell, collections::HashMap, fmt::Debug, ptr, rc::Rc}; use std::{any::Any, cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
use crate::{ use crate::{
dispatcher::CommandDispatcher, modifier::RedirectModifier, string_range::StringRange, dispatcher::CommandDispatcher, modifier::RedirectModifier, string_range::StringRange,
@ -73,7 +73,7 @@ impl<S: Any + Clone> CommandContextBuilder<S> {
nodes: self.nodes.clone(), nodes: self.nodes.clone(),
source: self.source.clone(), source: self.source.clone(),
command: self.command.clone(), command: self.command.clone(),
child: self.child.clone().map(|c| Rc::new(c.build(&input))), child: self.child.clone().map(|c| Rc::new(c.build(input))),
range: self.range.clone(), range: self.range.clone(),
forks: self.forks, forks: self.forks,
modifier: self.modifier.clone(), modifier: self.modifier.clone(),
@ -125,7 +125,7 @@ impl<S: Any + Clone> CommandContext<S> {
if Rc::ptr_eq(&source, &self.source) { if Rc::ptr_eq(&source, &self.source) {
return self.clone(); return self.clone();
} }
return CommandContext { CommandContext {
source, source,
input: self.input.clone(), input: self.input.clone(),
arguments: self.arguments.clone(), arguments: self.arguments.clone(),
@ -136,11 +136,11 @@ impl<S: Any + Clone> CommandContext<S> {
child: self.child.clone(), child: self.child.clone(),
modifier: self.modifier.clone(), modifier: self.modifier.clone(),
forks: self.forks, forks: self.forks,
}; }
} }
pub fn has_nodes(&self) -> bool { pub fn has_nodes(&self) -> bool {
return !self.nodes.is_empty(); !self.nodes.is_empty()
} }
pub fn argument(&self, name: &str) -> Option<Rc<dyn Any>> { pub fn argument(&self, name: &str) -> Option<Rc<dyn Any>> {

View file

@ -75,16 +75,14 @@ impl<S: Any + Clone> CommandDispatcher<S> {
reader.cursor = cursor; reader.cursor = cursor;
continue; continue;
} }
if reader.can_read() { if reader.can_read() && reader.peek() != ' ' {
if reader.peek() != ' ' { errors.insert(
errors.insert( Rc::new((*child.borrow()).clone()),
Rc::new((*child.borrow()).clone()), BuiltInExceptions::DispatcherExpectedArgumentSeparator
BuiltInExceptions::DispatcherExpectedArgumentSeparator .create_with_context(&reader),
.create_with_context(&reader), );
); reader.cursor = cursor;
reader.cursor = cursor; continue;
continue;
}
} }
context.with_command(&child.borrow().command); context.with_command(&child.borrow().command);
@ -120,7 +118,7 @@ impl<S: Any + Clone> CommandDispatcher<S> {
} }
} }
if potentials.len() > 0 { if !potentials.is_empty() {
if potentials.len() > 1 { if potentials.len() > 1 {
potentials.sort_by(|a, b| { potentials.sort_by(|a, b| {
if !a.reader.can_read() && b.reader.can_read() { if !a.reader.can_read() && b.reader.can_read() {
@ -174,11 +172,11 @@ impl<S: Any + Clone> CommandDispatcher<S> {
let mut forked = false; let mut forked = false;
let mut found_command = false; let mut found_command = false;
let command = parse.reader.string(); let command = parse.reader.string();
let original = parse.context.build(&command); let original = parse.context.build(command);
let mut contexts = vec![original]; let mut contexts = vec![original];
let mut next: Vec<CommandContext<S>> = vec![]; let mut next: Vec<CommandContext<S>> = vec![];
while contexts.len() > 0 { while !contexts.is_empty() {
for context in contexts.iter() { for context in contexts.iter() {
let child = &context.child; let child = &context.child;
if let Some(child) = child { if let Some(child) = child {
@ -239,3 +237,111 @@ impl<S: Any + Clone> Clone for CommandDispatcher<S> {
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
use crate::builder::literal_argument_builder::literal;
struct CommandSource {}
fn input_with_offset(input: &str, offset: usize) -> StringReader {
let mut result: StringReader = input.into();
result.cursor = offset;
result
}
// @Test
// public void testCreateAndExecuteCommand() throws Exception {
// subject.register(literal("foo").executes(command));
// assertThat(subject.execute("foo", source), is(42));
// verify(command).run(any(CommandContext.class));
// }
#[test]
fn create_and_execute_command() {
let mut subject = CommandDispatcher::<Rc<CommandSource>>::new();
subject.register(literal("foo").executes(|_| 42));
assert_eq!(
subject
.execute("foo".into(), Rc::new(CommandSource {}))
.unwrap(),
42
);
}
// @Test
// public void testCreateAndExecuteOffsetCommand() throws Exception {
// subject.register(literal("foo").executes(command));
// assertThat(subject.execute(inputWithOffset("/foo", 1), source), is(42));
// verify(command).run(any(CommandContext.class));
// }
#[test]
fn create_and_execute_offset_command() {
let mut subject = CommandDispatcher::<Rc<CommandSource>>::new();
subject.register(literal("foo").executes(|_| 42));
assert_eq!(
subject
.execute(input_with_offset("/foo", 1), Rc::new(CommandSource {}))
.unwrap(),
42
);
}
// @Test
// public void testCreateAndMergeCommands() throws Exception {
// subject.register(literal("base").then(literal("foo").executes(command)));
// subject.register(literal("base").then(literal("bar").executes(command)));
// assertThat(subject.execute("base foo", source), is(42));
// assertThat(subject.execute("base bar", source), is(42));
// verify(command, times(2)).run(any(CommandContext.class));
// }
#[test]
fn create_and_merge_commands() {
let mut subject = CommandDispatcher::<Rc<CommandSource>>::new();
subject.register(literal("base").then(literal("foo").executes(|_| 42)));
subject.register(literal("base").then(literal("bar").executes(|_| 42)));
assert_eq!(
subject
.execute("base foo".into(), Rc::new(CommandSource {}))
.unwrap(),
42
);
assert_eq!(
subject
.execute("base bar".into(), Rc::new(CommandSource {}))
.unwrap(),
42
);
}
// @Test
// public void testExecuteUnknownCommand() throws Exception {
// subject.register(literal("bar"));
// subject.register(literal("baz"));
// try {
// subject.execute("foo", source);
// fail();
// } catch (final CommandSyntaxException ex) {
// assertThat(ex.getType(), is(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand()));
// assertThat(ex.getCursor(), is(0));
// }
// }
// #[test]
// fn execute_unknown_command() {
// let mut subject = CommandDispatcher::<Rc<CommandSource>>::new();
// subject.register(literal("bar"));
// subject.register(literal("baz"));
// assert_eq!(
// subject
// .execute("foo".into(), Rc::new(CommandSource {}))
// .err()
// .unwrap(),
// BuiltInExceptions::DispatcherUnknownCommand.create()
// );
// }
}

View file

@ -1,9 +1,9 @@
use std::{cmp, fmt, rc::Rc}; use std::{cmp, fmt};
use super::builtin_exceptions::BuiltInExceptions; use super::builtin_exceptions::BuiltInExceptions;
use crate::message::Message; use crate::message::Message;
#[derive(Clone)] #[derive(Clone, PartialEq)]
pub struct CommandSyntaxException { pub struct CommandSyntaxException {
type_: BuiltInExceptions, type_: BuiltInExceptions,
message: Message, message: Message,
@ -12,7 +12,6 @@ pub struct CommandSyntaxException {
} }
const CONTEXT_AMOUNT: usize = 10; const CONTEXT_AMOUNT: usize = 10;
const ENABLE_COMMAND_STACK_TRACES: bool = true;
impl CommandSyntaxException { impl CommandSyntaxException {
pub fn new(type_: BuiltInExceptions, message: Message, input: &str, cursor: usize) -> Self { pub fn new(type_: BuiltInExceptions, message: Message, input: &str, cursor: usize) -> Self {
@ -76,8 +75,8 @@ impl CommandSyntaxException {
&self.type_ &self.type_
} }
pub fn input(&self) -> String { pub fn input(&self) -> &Option<String> {
self.input() &self.input
} }
pub fn cursor(&self) -> Option<usize> { pub fn cursor(&self) -> Option<usize> {

View file

@ -1,5 +1,3 @@
use std::rc::Rc;
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Message(String); pub struct Message(String);

View file

@ -1,4 +1,4 @@
use std::{any::Any, marker::PhantomData, rc::Rc}; use std::{any::Any, rc::Rc};
use crate::{ use crate::{
context::CommandContext, context::CommandContext,
@ -24,6 +24,7 @@ impl Parser for Integer {
let result = reader.read_int()?; let result = reader.read_int()?;
if let Some(minimum) = self.minimum { if let Some(minimum) = self.minimum {
if result < minimum { if result < minimum {
reader.cursor = start;
return Err(BuiltInExceptions::IntegerTooSmall { return Err(BuiltInExceptions::IntegerTooSmall {
found: result, found: result,
min: minimum, min: minimum,
@ -33,6 +34,7 @@ impl Parser for Integer {
} }
if let Some(maximum) = self.maximum { if let Some(maximum) = self.maximum {
if result > maximum { if result > maximum {
reader.cursor = start;
return Err(BuiltInExceptions::IntegerTooBig { return Err(BuiltInExceptions::IntegerTooBig {
found: result, found: result,
max: maximum, max: maximum,
@ -52,5 +54,5 @@ pub fn get_integer<S: Any + Clone>(context: &CommandContext<S>, name: &str) -> O
.argument(name) .argument(name)
.unwrap() .unwrap()
.downcast_ref::<i32>() .downcast_ref::<i32>()
.map(|x| *x) .copied()
} }

View file

@ -1,7 +1,7 @@
use crate::exceptions::{ use crate::exceptions::{
builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException, builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException,
}; };
use std::{rc::Rc, str::FromStr}; use std::str::FromStr;
#[derive(Clone)] #[derive(Clone)]
pub struct StringReader { pub struct StringReader {
@ -79,7 +79,7 @@ impl StringReader {
} }
pub fn is_allowed_number(c: char) -> bool { pub fn is_allowed_number(c: char) -> bool {
c >= '0' && c <= '9' || c == '.' || c == '-' ('0'..='9').contains(&c) || c == '.' || c == '-'
} }
pub fn is_quoted_string_start(c: char) -> bool { pub fn is_quoted_string_start(c: char) -> bool {
@ -177,9 +177,9 @@ impl StringReader {
} }
pub fn is_allowed_in_unquoted_string(c: char) -> bool { pub fn is_allowed_in_unquoted_string(c: char) -> bool {
c >= '0' && c <= '9' ('0'..='9').contains(&c)
|| c >= 'A' && c <= 'Z' || ('A'..='Z').contains(&c)
|| c >= 'a' && c <= 'z' || ('a'..='z').contains(&c)
|| c == '_' || c == '_'
|| c == '-' || c == '-'
|| c == '.' || c == '.'
@ -232,7 +232,7 @@ impl StringReader {
} }
} }
return Err(BuiltInExceptions::ReaderExpectedEndOfQuote.create_with_context(self)); Err(BuiltInExceptions::ReaderExpectedEndOfQuote.create_with_context(self))
} }
pub fn read_string(&mut self) -> Result<String, CommandSyntaxException> { pub fn read_string(&mut self) -> Result<String, CommandSyntaxException> {
@ -255,12 +255,12 @@ impl StringReader {
} }
if value == "true" { if value == "true" {
return Ok(true); Ok(true)
} else if value == "false" { } else if value == "false" {
return Ok(false); Ok(false)
} else { } else {
self.cursor = start; self.cursor = start;
return Err(BuiltInExceptions::ReaderInvalidBool { value }.create_with_context(self)); Err(BuiltInExceptions::ReaderInvalidBool { value }.create_with_context(self))
} }
} }

View file

@ -11,15 +11,7 @@ use crate::{
string_range::StringRange, string_range::StringRange,
string_reader::StringReader, string_reader::StringReader,
}; };
use std::{ use std::{any::Any, cell::RefCell, collections::BTreeMap, fmt::Debug, hash::Hash, ptr, rc::Rc};
any::Any,
cell::RefCell,
collections::{BTreeMap, HashMap},
fmt::Debug,
hash::Hash,
ptr,
rc::Rc,
};
/// An ArgumentBuilder that has been built. /// An ArgumentBuilder that has been built.
#[derive(Clone)] #[derive(Clone)]
@ -67,7 +59,7 @@ impl<S: Any + Clone> CommandNode<S> {
pub fn get_relevant_nodes(&self, input: &mut StringReader) -> Vec<Rc<RefCell<CommandNode<S>>>> { pub fn get_relevant_nodes(&self, input: &mut StringReader) -> Vec<Rc<RefCell<CommandNode<S>>>> {
let literals = self.literals(); let literals = self.literals();
if literals.len() > 0 { if !literals.is_empty() {
let cursor = input.cursor(); let cursor = input.cursor();
while input.can_read() && input.peek() != ' ' { while input.can_read() && input.peek() != ' ' {
input.skip(); input.skip();
@ -83,18 +75,10 @@ impl<S: Any + Clone> CommandNode<S> {
if let Some(literal) = literal { if let Some(literal) = literal {
return vec![literal.clone()]; return vec![literal.clone()];
} else { } else {
return self return self.arguments().values().cloned().collect();
.arguments()
.values()
.map(|argument| argument.clone())
.collect();
} }
} else { } else {
return self self.arguments().values().cloned().collect()
.arguments()
.values()
.map(|argument| argument.clone())
.collect();
} }
} }
@ -147,7 +131,7 @@ impl<S: Any + Clone> CommandNode<S> {
.expect("Couldn't get result for some reason"); .expect("Couldn't get result for some reason");
let parsed = ParsedArgument { let parsed = ParsedArgument {
range: StringRange::between(start, reader.cursor()), range: StringRange::between(start, reader.cursor()),
result: result, result,
}; };
context_builder.with_argument(&argument.name, parsed.clone()); context_builder.with_argument(&argument.name, parsed.clone());
@ -175,7 +159,7 @@ impl<S: Any + Clone> CommandNode<S> {
fn parse(&self, reader: &mut StringReader) -> Option<usize> { fn parse(&self, reader: &mut StringReader) -> Option<usize> {
match self.value { match self.value {
ArgumentBuilderType::Argument(ref argument) => { ArgumentBuilderType::Argument(_) => {
panic!("Can't parse argument.") panic!("Can't parse argument.")
} }
ArgumentBuilderType::Literal(ref literal) => { ArgumentBuilderType::Literal(ref literal) => {
@ -252,7 +236,9 @@ impl<S: Any + Clone> PartialEq for CommandNode<S> {
return false; return false;
} }
if let Some(selfexecutes) = &self.command { if let Some(selfexecutes) = &self.command {
// idk how to do this better since we can't compare `dyn Fn`s
if let Some(otherexecutes) = &other.command { if let Some(otherexecutes) = &other.command {
#[allow(clippy::vtable_address_comparisons)]
if !Rc::ptr_eq(selfexecutes, otherexecutes) { if !Rc::ptr_eq(selfexecutes, otherexecutes) {
return false; return false;
} }
@ -260,6 +246,9 @@ impl<S: Any + Clone> PartialEq for CommandNode<S> {
return false; return false;
} }
} }
else if other.command.is_some() {
return false;
}
true true
} }
} }