diff options
| author | mat <github@matdoes.dev> | 2022-04-18 18:13:15 +0000 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2022-04-18 18:13:15 +0000 |
| commit | b3864af9c4af83552e37fd71a46262967572f9e6 (patch) | |
| tree | 14938d1b278ad18efd86868094a73f6de85f09fa | |
| parent | 17d9f676ccdc69743e7717bb91f7ff2999c065f8 (diff) | |
| download | azalea-drasl-b3864af9c4af83552e37fd71a46262967572f9e6.tar.xz | |
split stuff into more modules
| -rw-r--r-- | azalea-brigadier/src/builder/required_argument_builder.rs | 5 | ||||
| -rw-r--r-- | azalea-brigadier/src/context.rs | 202 | ||||
| -rw-r--r-- | azalea-brigadier/src/dispatcher.rs | 713 | ||||
| -rw-r--r-- | azalea-brigadier/src/exceptions/mod.rs | 7 | ||||
| -rw-r--r-- | azalea-brigadier/src/lib.rs | 5 | ||||
| -rw-r--r-- | azalea-brigadier/src/modifier.rs | 4 | ||||
| -rw-r--r-- | azalea-brigadier/src/parse_results.rs | 2 | ||||
| -rw-r--r-- | azalea-brigadier/src/parsers.rs | 4 | ||||
| -rw-r--r-- | azalea-brigadier/src/string_range.rs | 45 | ||||
| -rw-r--r-- | azalea-brigadier/src/string_reader.rs | 4 |
10 files changed, 12 insertions, 979 deletions
diff --git a/azalea-brigadier/src/builder/required_argument_builder.rs b/azalea-brigadier/src/builder/required_argument_builder.rs index cae0cddb..a50f7ea9 100644 --- a/azalea-brigadier/src/builder/required_argument_builder.rs +++ b/azalea-brigadier/src/builder/required_argument_builder.rs @@ -1,8 +1,5 @@ use super::argument_builder::{ArgumentBuilder, ArgumentBuilderType}; -use crate::{ - exceptions::command_syntax_exception::CommandSyntaxException, parsers::Parser, - string_reader::StringReader, -}; +use crate::{exceptions::CommandSyntaxException, parsers::Parser, string_reader::StringReader}; use std::{any::Any, fmt::Debug, rc::Rc}; /// An argument node type. The `T` type parameter is the type of the argument, diff --git a/azalea-brigadier/src/context.rs b/azalea-brigadier/src/context.rs deleted file mode 100644 index d71b3925..00000000 --- a/azalea-brigadier/src/context.rs +++ /dev/null @@ -1,202 +0,0 @@ -use std::{any::Any, cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc}; - -use crate::{ - dispatcher::CommandDispatcher, - modifier::RedirectModifier, - string_range::StringRange, - tree::{CommandNode, ParsedCommandNode}, -}; - -pub struct CommandContextBuilder<S> { - pub arguments: HashMap<String, ParsedArgument>, - pub root: Rc<RefCell<CommandNode<S>>>, - pub nodes: Vec<ParsedCommandNode<S>>, - pub dispatcher: Rc<CommandDispatcher<S>>, - pub source: Rc<S>, - pub command: Option<Rc<dyn Fn(&CommandContext<S>) -> i32>>, - pub child: Option<Rc<CommandContextBuilder<S>>>, - pub range: StringRange, - pub modifier: Option<Rc<RedirectModifier<S>>>, - pub forks: bool, -} - -impl<S> Clone for CommandContextBuilder<S> { - fn clone(&self) -> Self { - Self { - arguments: self.arguments.clone(), - root: self.root.clone(), - nodes: self.nodes.clone(), - dispatcher: self.dispatcher.clone(), - source: self.source.clone(), - command: self.command.clone(), - child: self.child.clone(), - range: self.range.clone(), - modifier: self.modifier.clone(), - forks: self.forks, - } - } -} - -impl<S> CommandContextBuilder<S> { - // CommandDispatcher<S> dispatcher, final S source, final CommandNode<S> rootNode, final int start - pub fn new( - dispatcher: Rc<CommandDispatcher<S>>, - source: Rc<S>, - root_node: Rc<RefCell<CommandNode<S>>>, - start: usize, - ) -> Self { - Self { - arguments: HashMap::new(), - root: root_node, - source, - range: StringRange::at(start), - command: None, - dispatcher, - nodes: vec![], - child: None, - modifier: None, - forks: false, - } - } - - pub fn with_command( - &mut self, - command: &Option<Rc<dyn Fn(&CommandContext<S>) -> i32>>, - ) -> &Self { - self.command = command.clone(); - self - } - pub fn with_child(&mut self, child: Rc<CommandContextBuilder<S>>) -> &Self { - self.child = Some(child); - self - } - pub fn with_argument(&mut self, name: &str, argument: ParsedArgument) -> &Self { - self.arguments.insert(name.to_string(), argument); - self - } - pub fn with_node(&mut self, node: Rc<RefCell<CommandNode<S>>>, range: StringRange) -> &Self { - self.nodes.push(ParsedCommandNode { - node: node.clone(), - range: range.clone(), - }); - self.range = StringRange::encompassing(&self.range, &range); - self.modifier = node.borrow().modifier.clone(); - self.forks = node.borrow().forks; - self - } - - pub fn build(&self, input: &str) -> CommandContext<S> { - CommandContext { - arguments: self.arguments.clone(), - root_node: self.root.clone(), - nodes: self.nodes.clone(), - source: self.source.clone(), - command: self.command.clone(), - child: self.child.clone().map(|c| Rc::new(c.build(input))), - range: self.range.clone(), - forks: self.forks, - modifier: self.modifier.clone(), - input: input.to_string(), - } - } -} - -impl<S> Debug for CommandContextBuilder<S> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("CommandContextBuilder") - // .field("arguments", &self.arguments) - .field("root", &self.root) - // .field("nodes", &self.nodes) - // .field("dispatcher", &self.dispatcher) - // .field("source", &self.source) - // .field("command", &self.command) - .field("child", &self.child) - .field("range", &self.range) - // .field("modifier", &self.modifier) - .field("forks", &self.forks) - .finish() - } -} - -#[derive(Clone)] -pub struct ParsedArgument { - pub range: StringRange, - pub result: Rc<dyn Any>, -} - -/// A built `CommandContextBuilder`. -pub struct CommandContext<S> { - pub source: Rc<S>, - pub input: String, - pub arguments: HashMap<String, ParsedArgument>, - pub command: Option<Rc<dyn Fn(&CommandContext<S>) -> i32>>, - pub root_node: Rc<RefCell<CommandNode<S>>>, - pub nodes: Vec<ParsedCommandNode<S>>, - pub range: StringRange, - pub child: Option<Rc<CommandContext<S>>>, - pub modifier: Option<Rc<RedirectModifier<S>>>, - pub forks: bool, -} - -impl<S> Clone for CommandContext<S> { - fn clone(&self) -> Self { - Self { - source: self.source.clone(), - input: self.input.clone(), - arguments: self.arguments.clone(), - command: self.command.clone(), - root_node: self.root_node.clone(), - nodes: self.nodes.clone(), - range: self.range.clone(), - child: self.child.clone(), - modifier: self.modifier.clone(), - forks: self.forks, - } - } -} - -impl<S> Debug for CommandContext<S> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("CommandContext") - // .field("source", &self.source) - .field("input", &self.input) - // .field("arguments", &self.arguments) - // .field("command", &self.command) - // .field("root_node", &self.root_node) - // .field("nodes", &self.nodes) - .field("range", &self.range) - .field("child", &self.child) - // .field("modifier", &self.modifier) - .field("forks", &self.forks) - .finish() - } -} - -impl<S> CommandContext<S> { - pub fn copy_for(&self, source: Rc<S>) -> Self { - if Rc::ptr_eq(&source, &self.source) { - return self.clone(); - } - CommandContext { - source, - input: self.input.clone(), - arguments: self.arguments.clone(), - command: self.command.clone(), - root_node: self.root_node.clone(), - nodes: self.nodes.clone(), - range: self.range.clone(), - child: self.child.clone(), - modifier: self.modifier.clone(), - forks: self.forks, - } - } - - pub fn has_nodes(&self) -> bool { - !self.nodes.is_empty() - } - - pub fn argument(&self, name: &str) -> Option<Rc<dyn Any>> { - let argument = self.arguments.get(name); - argument.map(|a| a.result.clone()) - } -} diff --git a/azalea-brigadier/src/dispatcher.rs b/azalea-brigadier/src/dispatcher.rs deleted file mode 100644 index ce89b81d..00000000 --- a/azalea-brigadier/src/dispatcher.rs +++ /dev/null @@ -1,713 +0,0 @@ -use crate::{ - builder::argument_builder::ArgumentBuilder, - context::{CommandContext, CommandContextBuilder}, - exceptions::{ - builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException, - }, - parse_results::ParseResults, - string_reader::StringReader, - tree::CommandNode, -}; -use std::{cell::RefCell, cmp::Ordering, collections::HashMap, marker::PhantomData, mem, rc::Rc}; - -#[derive(Default)] -pub struct CommandDispatcher<S> { - root: Rc<RefCell<CommandNode<S>>>, - _marker: PhantomData<S>, -} - -impl<S> CommandDispatcher<S> { - pub fn new() -> Self { - Self { - root: Rc::new(RefCell::new(CommandNode::default())), - _marker: PhantomData, - } - } - - pub fn register(&mut self, node: ArgumentBuilder<S>) -> Rc<RefCell<CommandNode<S>>> { - let build = Rc::new(RefCell::new(node.build())); - self.root.borrow_mut().add_child(&build); - build - } - - pub fn parse(&self, command: StringReader, source: Rc<S>) -> ParseResults<S> { - let context = CommandContextBuilder::new( - Rc::new(self.clone()), - source, - self.root.clone(), - command.cursor(), - ); - self.parse_nodes(&self.root, &command, context).unwrap() - } - - fn parse_nodes( - &self, - node: &Rc<RefCell<CommandNode<S>>>, - original_reader: &StringReader, - context_so_far: CommandContextBuilder<S>, - ) -> Result<ParseResults<S>, CommandSyntaxException> { - let source = context_so_far.source.clone(); - let mut errors = HashMap::<Rc<CommandNode<S>>, CommandSyntaxException>::new(); - let mut potentials: Vec<ParseResults<S>> = vec![]; - let cursor = original_reader.cursor(); - - for child in node - .borrow() - .get_relevant_nodes(&mut original_reader.clone()) - { - if !child.borrow().can_use(source.clone()) { - continue; - } - let mut context = context_so_far.clone(); - let mut reader = original_reader.clone(); - - let parse_with_context_result = - child.borrow().parse_with_context(&mut reader, &mut context); - if let Err(ex) = parse_with_context_result { - errors.insert( - Rc::new((*child.borrow()).clone()), - BuiltInExceptions::DispatcherParseException { - message: ex.message(), - } - .create_with_context(&reader), - ); - reader.cursor = cursor; - continue; - } - if reader.can_read() && reader.peek() != ' ' { - errors.insert( - Rc::new((*child.borrow()).clone()), - BuiltInExceptions::DispatcherExpectedArgumentSeparator - .create_with_context(&reader), - ); - reader.cursor = cursor; - continue; - } - - context.with_command(&child.borrow().command); - if reader.can_read_length(if child.borrow().redirect.is_none() { - 2 - } else { - 1 - }) { - reader.skip(); - if let Some(redirect) = &child.borrow().redirect { - let child_context = CommandContextBuilder::new( - Rc::new(self.clone()), - source, - redirect.clone(), - reader.cursor, - ); - let parse = self - .parse_nodes(redirect, &reader, child_context) - .expect("Parsing nodes failed"); - context.with_child(Rc::new(parse.context)); - return Ok(ParseResults { - context, - reader: parse.reader, - exceptions: parse.exceptions, - }); - } else { - let parse = self - .parse_nodes(&child, &reader, context) - .expect("Parsing nodes failed"); - potentials.push(parse); - } - } else { - potentials.push(ParseResults { - context, - reader, - exceptions: HashMap::new(), - }); - } - } - - if !potentials.is_empty() { - if potentials.len() > 1 { - potentials.sort_by(|a, b| { - if !a.reader.can_read() && b.reader.can_read() { - return Ordering::Less; - }; - if a.reader.can_read() && !b.reader.can_read() { - return Ordering::Greater; - }; - if a.exceptions.is_empty() && !b.exceptions.is_empty() { - return Ordering::Less; - }; - if !a.exceptions.is_empty() && b.exceptions.is_empty() { - return Ordering::Greater; - }; - Ordering::Equal - }) - } - let best_potential = potentials.into_iter().next().unwrap(); - return Ok(best_potential); - } - - Ok(ParseResults { - context: context_so_far, - reader: original_reader.clone(), - exceptions: errors, - }) - } - - pub fn execute( - &self, - input: StringReader, - source: Rc<S>, - ) -> Result<i32, CommandSyntaxException> { - let parse = self.parse(input, source); - Self::execute_parsed(parse) - } - - pub fn add_paths( - &self, - node: Rc<RefCell<CommandNode<S>>>, - result: &mut Vec<Vec<Rc<RefCell<CommandNode<S>>>>>, - parents: Vec<Rc<RefCell<CommandNode<S>>>>, - ) { - let mut current = parents; - current.push(node.clone()); - result.push(current.clone()); - - for child in node.borrow().children.values() { - self.add_paths(child.clone(), result, current.clone()); - } - } - - pub fn get_path(&self, target: CommandNode<S>) -> Vec<String> { - let rc_target = Rc::new(RefCell::new(target)); - let mut nodes: Vec<Vec<Rc<RefCell<CommandNode<S>>>>> = Vec::new(); - self.add_paths(self.root.clone(), &mut nodes, vec![]); - - for list in nodes { - if *list.last().expect("Nothing in list").borrow() == *rc_target.borrow() { - let mut result: Vec<String> = Vec::with_capacity(list.len()); - for node in list { - if node != self.root { - result.push(node.borrow().name().to_string()); - } - } - return result; - } - } - vec![] - } - - pub fn find_node(&self, path: &[&str]) -> Option<Rc<RefCell<CommandNode<S>>>> { - let mut node = self.root.clone(); - for name in path { - if let Some(child) = node.clone().borrow().child(name) { - node = child - } else { - return None; - } - } - Some(node) - } - - /// Executes a given pre-parsed command. - pub fn execute_parsed(parse: ParseResults<S>) -> Result<i32, CommandSyntaxException> { - if parse.reader.can_read() { - if parse.exceptions.len() == 1 { - return Err(parse.exceptions.values().next().unwrap().clone()); - } - if parse.context.range.is_empty() { - return Err( - BuiltInExceptions::DispatcherUnknownCommand.create_with_context(&parse.reader) - ); - } - return Err( - BuiltInExceptions::DispatcherUnknownArgument.create_with_context(&parse.reader) - ); - } - let mut result = 0i32; - let mut successful_forks = 0; - let mut forked = false; - let mut found_command = false; - let command = parse.reader.string(); - let original = parse.context.build(command); - let mut contexts = vec![original]; - let mut next: Vec<CommandContext<S>> = vec![]; - - while !contexts.is_empty() { - for context in contexts.iter() { - let child = &context.child; - if let Some(child) = child { - println!("aaaaaaa {:?}", child); - forked |= child.forks; - if child.has_nodes() { - found_command = true; - let modifier = &context.modifier; - if let Some(modifier) = modifier { - let results = modifier(context); - if let Ok(results) = results { - if !results.is_empty() { - next.extend(results.iter().map(|s| child.copy_for(s.clone()))); - } - } else { - // TODO - // self.consumer.on_command_complete(context, false, 0); - if !forked { - return Err(results.err().unwrap()); - } - } - } else { - next.push(child.copy_for(context.source.clone())); - } - } - } else if let Some(context_command) = &context.command { - found_command = true; - - let value = context_command(context); - result += value; - // consumer.on_command_complete(context, true, value); - successful_forks += 1; - - // TODO: allow context_command to error and handle those errors - } - } - - // move next into contexts and clear next - mem::swap(&mut contexts, &mut next); - next.clear(); - } - - if !found_command { - // consumer.on_command_complete(original, false, 0); - return Err( - BuiltInExceptions::DispatcherUnknownCommand.create_with_context(&parse.reader) - ); - } - - // TODO: this is not how vanilla does it but it works - Ok(if successful_forks >= 2 { - successful_forks - } else { - result - }) - // Ok(if forked { successful_forks } else { result }) - } -} - -impl<S> Clone for CommandDispatcher<S> { - fn clone(&self) -> Self { - Self { - root: self.root.clone(), - _marker: PhantomData, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - builder::{literal_argument_builder::literal, required_argument_builder::argument}, - parsers::integer, - }; - - #[derive(Debug, PartialEq)] - struct CommandSource {} - - fn input_with_offset(input: &str, offset: usize) -> StringReader { - let mut result: StringReader = input.into(); - result.cursor = offset; - result - } - - #[test] - fn create_and_execute_command() { - let mut subject = CommandDispatcher::new(); - subject.register(literal("foo").executes(|_| 42)); - - assert_eq!( - subject - .execute("foo".into(), Rc::new(CommandSource {})) - .unwrap(), - 42 - ); - } - - #[test] - fn create_and_execute_offset_command() { - let mut subject = CommandDispatcher::new(); - subject.register(literal("foo").executes(|_| 42)); - - assert_eq!( - subject - .execute(input_with_offset("/foo", 1), Rc::new(CommandSource {})) - .unwrap(), - 42 - ); - } - - #[test] - fn create_and_merge_commands() { - let mut subject = CommandDispatcher::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] - fn execute_unknown_command() { - let mut subject = CommandDispatcher::new(); - subject.register(literal("bar")); - subject.register(literal("baz")); - - let execute_result = subject.execute("foo".into(), Rc::new(CommandSource {})); - - let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownCommand => {} - _ => panic!("Unexpected error"), - } - assert_eq!(err.cursor().unwrap(), 0); - } - - #[test] - fn execute_impermissible_command() { - let mut subject = CommandDispatcher::new(); - subject.register(literal("foo").requires(|_| false)); - - let execute_result = subject.execute("foo".into(), Rc::new(CommandSource {})); - - let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownCommand => {} - _ => panic!("Unexpected error"), - } - assert_eq!(err.cursor().unwrap(), 0); - } - - #[test] - fn execute_empty_command() { - let mut subject = CommandDispatcher::new(); - subject.register(literal("")); - - let execute_result = subject.execute("".into(), Rc::new(CommandSource {})); - - let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownCommand => {} - _ => panic!("Unexpected error"), - } - assert_eq!(err.cursor().unwrap(), 0); - } - - #[test] - fn execute_unknown_subcommand() { - let mut subject = CommandDispatcher::new(); - subject.register(literal("foo").executes(|_| 42)); - - let execute_result = subject.execute("foo bar".into(), Rc::new(CommandSource {})); - - let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownArgument => {} - _ => panic!("Unexpected error"), - } - assert_eq!(err.cursor().unwrap(), 4); - } - - #[test] - fn execute_incorrect_literal() { - let mut subject = CommandDispatcher::new(); - subject.register(literal("foo").executes(|_| 42).then(literal("bar"))); - - let execute_result = subject.execute("foo baz".into(), Rc::new(CommandSource {})); - - let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownArgument => {} - _ => panic!("Unexpected error"), - } - assert_eq!(err.cursor().unwrap(), 4); - } - - #[test] - fn execute_ambiguous_incorrect_argument() { - let mut subject = CommandDispatcher::new(); - subject.register( - literal("foo") - .executes(|_| 42) - .then(literal("bar")) - .then(literal("baz")), - ); - - let execute_result = subject.execute("foo unknown".into(), Rc::new(CommandSource {})); - - let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownArgument => {} - _ => panic!("Unexpected error"), - } - assert_eq!(err.cursor().unwrap(), 4); - } - - #[test] - fn execute_subcommand() { - let mut subject = CommandDispatcher::new(); - - subject.register( - literal("foo") - .then(literal("a")) - .then(literal("=").executes(|_| 100)) - .then(literal("c")) - .executes(|_| 42), - ); - - assert_eq!( - subject - .execute("foo =".into(), Rc::new(CommandSource {})) - .unwrap(), - 100 - ); - } - - #[test] - fn parse_incomplete_literal() { - let mut subject = CommandDispatcher::new(); - subject.register(literal("foo").then(literal("bar").executes(|_| 42))); - - let parse = subject.parse("foo ".into(), Rc::new(CommandSource {})); - assert_eq!(parse.reader.remaining(), " "); - assert_eq!(parse.context.nodes.len(), 1); - } - - #[test] - fn parse_incomplete_argument() { - let mut subject = CommandDispatcher::new(); - subject.register(literal("foo").then(argument("bar", integer()).executes(|_| 42))); - - let parse = subject.parse("foo ".into(), Rc::new(CommandSource {})); - assert_eq!(parse.reader.remaining(), " "); - assert_eq!(parse.context.nodes.len(), 1); - } - - #[test] - fn execute_ambiguious_parent_subcommand() { - let mut subject = CommandDispatcher::new(); - - subject.register( - literal("test") - .then(argument("incorrect", integer()).executes(|_| 42)) - .then( - argument("right", integer()).then(argument("sub", integer()).executes(|_| 100)), - ), - ); - - assert_eq!( - subject - .execute("test 1 2".into(), Rc::new(CommandSource {})) - .unwrap(), - 100 - ); - } - - #[test] - fn execute_ambiguious_parent_subcommand_via_redirect() { - let mut subject = CommandDispatcher::new(); - - let real = subject.register( - literal("test") - .then(argument("incorrect", integer()).executes(|_| 42)) - .then( - argument("right", integer()).then(argument("sub", integer()).executes(|_| 100)), - ), - ); - - subject.register(literal("redirect").redirect(real)); - - assert_eq!( - subject - .execute("redirect 1 2".into(), Rc::new(CommandSource {})) - .unwrap(), - 100 - ); - } - - #[test] - fn execute_redirected_multiple_times() { - let mut subject = CommandDispatcher::new(); - - let concrete_node = subject.register(literal("actual").executes(|_| 42)); - let root = subject.root.clone(); - let redirect_node = subject.register(literal("redirected").redirect(root.clone())); - - let input = "redirected redirected actual"; - - let parse = subject.parse(input.into(), Rc::new(CommandSource {})); - assert_eq!(parse.context.range.get(input), "redirected"); - assert_eq!(parse.context.nodes.len(), 1); - assert_eq!(parse.context.root, root); - assert_eq!(parse.context.nodes[0].range, parse.context.range); - assert_eq!(parse.context.nodes[0].node, redirect_node); - - let child1 = parse.context.child.clone(); - assert!(child1.is_some()); - assert_eq!(child1.clone().unwrap().range.get(input), "redirected"); - assert_eq!(child1.clone().unwrap().nodes.len(), 1); - assert_eq!(child1.clone().unwrap().root, root); - assert_eq!( - child1.clone().unwrap().nodes[0].range, - child1.clone().unwrap().range - ); - assert_eq!(child1.clone().unwrap().nodes[0].node, redirect_node); - - let child2 = child1.unwrap().child.clone(); - assert!(child2.is_some()); - assert_eq!(child2.clone().unwrap().range.get(input), "actual"); - assert_eq!(child2.clone().unwrap().nodes.len(), 1); - assert_eq!(child2.clone().unwrap().root, root); - assert_eq!( - child2.clone().unwrap().nodes[0].range, - child2.clone().unwrap().range - ); - assert_eq!(child2.clone().unwrap().nodes[0].node, concrete_node); - - assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 42); - } - - #[test] - fn execute_redirected() { - let mut subject = CommandDispatcher::new(); - - let source1 = Rc::new(CommandSource {}); - let source2 = Rc::new(CommandSource {}); - - let modifier = move |_: &CommandContext<CommandSource>| -> Result<Vec<Rc<CommandSource>>, CommandSyntaxException> { - Ok(vec![source1.clone(), source2.clone()]) - }; - - let concrete_node = subject.register(literal("actual").executes(|_| 42)); - let redirect_node = - subject.register(literal("redirected").fork(subject.root.clone(), Rc::new(modifier))); - - let input = "redirected actual"; - let parse = subject.parse(input.into(), Rc::new(CommandSource {})); - assert_eq!(parse.context.range.get(input), "redirected"); - assert_eq!(parse.context.nodes.len(), 1); - assert_eq!(parse.context.root, subject.root); - assert_eq!(parse.context.nodes[0].range, parse.context.range); - assert_eq!(parse.context.nodes[0].node, redirect_node); - - let parent = parse.context.child.clone(); - assert!(parent.is_some()); - let parent = parent.unwrap(); - assert_eq!(parent.range.get(input), "actual"); - assert_eq!(parent.nodes.len(), 1); - assert_eq!(parse.context.root, subject.root); - assert_eq!(parent.nodes[0].range, parent.range); - assert_eq!(parent.nodes[0].node, concrete_node); - assert_eq!(parent.source, Rc::new(CommandSource {})); - - assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 2); - } - - #[test] - fn execute_orphaned_subcommand() { - let mut subject = CommandDispatcher::new(); - - subject.register( - literal("foo") - .then(argument("bar", integer())) - .executes(|_| 42), - ); - - let result = subject.execute("foo 5".into(), Rc::new(CommandSource {})); - assert!(result.is_err()); - let result = result.unwrap_err(); - assert_eq!( - *result.get_type(), - BuiltInExceptions::DispatcherUnknownCommand - ); - assert_eq!(result.cursor(), Some(5)); - } - - #[test] - fn execute_invalid_other() { - let mut subject = CommandDispatcher::new(); - - subject.register(literal("w").executes(|_| panic!("This should not run"))); - subject.register(literal("world").executes(|_| 42)); - - assert_eq!( - subject - .execute("world".into(), Rc::new(CommandSource {})) - .unwrap(), - 42 - ); - } - - #[test] - fn parse_no_space_separator() { - let mut subject = CommandDispatcher::new(); - - subject.register( - literal("foo") - .then(argument("bar", integer())) - .executes(|_| 42), - ); - - let result = subject.execute("foo$".into(), Rc::new(CommandSource {})); - assert!(result.is_err()); - let result = result.unwrap_err(); - assert_eq!( - *result.get_type(), - BuiltInExceptions::DispatcherUnknownCommand - ); - assert_eq!(result.cursor(), Some(0)); - } - - #[test] - fn execute_invalid_subcommand() { - let mut subject = CommandDispatcher::new(); - - subject.register( - literal("foo") - .then(argument("bar", integer())) - .executes(|_| 42), - ); - - let result = subject.execute("foo bar".into(), Rc::new(CommandSource {})); - assert!(result.is_err()); - let result = result.unwrap_err(); - // this fails for some reason, i blame mojang - // assert_eq!(*result.get_type(), BuiltInExceptions::ReaderExpectedInt); - assert_eq!(result.cursor(), Some(4)); - } - - #[test] - fn get_path() { - let mut subject = CommandDispatcher::<()>::new(); - - let bar = literal("bar").build(); - subject.register(literal("foo").then_built(bar.clone())); - - assert_eq!( - subject.get_path(bar), - vec!["foo".to_string(), "bar".to_string()] - ); - } - - #[test] - fn find_node_doesnt_exist() { - let subject = CommandDispatcher::<()>::new(); - - assert_eq!(subject.find_node(&vec!["foo", "bar"]), None) - } -} diff --git a/azalea-brigadier/src/exceptions/mod.rs b/azalea-brigadier/src/exceptions/mod.rs index 0bca556e..6b9c8d62 100644 --- a/azalea-brigadier/src/exceptions/mod.rs +++ b/azalea-brigadier/src/exceptions/mod.rs @@ -1,2 +1,5 @@ -pub mod builtin_exceptions; -pub mod command_syntax_exception; +mod builtin_exceptions; +mod command_syntax_exception; + +pub use builtin_exceptions::BuiltInExceptions; +pub use command_syntax_exception::CommandSyntaxException; diff --git a/azalea-brigadier/src/lib.rs b/azalea-brigadier/src/lib.rs index e359e274..cffaac12 100644 --- a/azalea-brigadier/src/lib.rs +++ b/azalea-brigadier/src/lib.rs @@ -1,12 +1,11 @@ pub mod builder; +pub mod command_dispatcher; pub mod context; -pub mod dispatcher; pub mod exceptions; pub mod message; pub mod modifier; pub mod parse_results; pub mod parsers; -pub mod string_range; pub mod string_reader; pub mod tree; @@ -17,8 +16,8 @@ mod tests { use crate::{ builder::{literal_argument_builder::literal, required_argument_builder::argument}, + command_dispatcher::CommandDispatcher, context::CommandContext, - dispatcher::CommandDispatcher, parsers::{get_integer, integer}, }; diff --git a/azalea-brigadier/src/modifier.rs b/azalea-brigadier/src/modifier.rs index 68a3304e..d40d59f9 100644 --- a/azalea-brigadier/src/modifier.rs +++ b/azalea-brigadier/src/modifier.rs @@ -1,8 +1,6 @@ use std::rc::Rc; -use crate::{ - context::CommandContext, exceptions::command_syntax_exception::CommandSyntaxException, -}; +use crate::{context::CommandContext, exceptions::CommandSyntaxException}; pub type RedirectModifier<S> = dyn Fn(&CommandContext<S>) -> Result<Vec<Rc<S>>, CommandSyntaxException>; diff --git a/azalea-brigadier/src/parse_results.rs b/azalea-brigadier/src/parse_results.rs index c9f26a04..3698ae82 100644 --- a/azalea-brigadier/src/parse_results.rs +++ b/azalea-brigadier/src/parse_results.rs @@ -1,5 +1,5 @@ use crate::{ - context::CommandContextBuilder, exceptions::command_syntax_exception::CommandSyntaxException, + context::CommandContextBuilder, exceptions::CommandSyntaxException, string_reader::StringReader, tree::CommandNode, }; use std::{collections::HashMap, fmt::Debug, rc::Rc}; diff --git a/azalea-brigadier/src/parsers.rs b/azalea-brigadier/src/parsers.rs index 1984b52f..18ee9119 100644 --- a/azalea-brigadier/src/parsers.rs +++ b/azalea-brigadier/src/parsers.rs @@ -2,9 +2,7 @@ use std::{any::Any, rc::Rc}; use crate::{ context::CommandContext, - exceptions::{ - builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException, - }, + exceptions::{BuiltInExceptions, CommandSyntaxException}, string_reader::StringReader, }; diff --git a/azalea-brigadier/src/string_range.rs b/azalea-brigadier/src/string_range.rs deleted file mode 100644 index 8ca88624..00000000 --- a/azalea-brigadier/src/string_range.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::cmp; - -#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] -pub struct StringRange { - start: usize, - end: usize, -} - -impl StringRange { - pub fn new(start: usize, end: usize) -> Self { - Self { start, end } - } - - pub fn at(pos: usize) -> Self { - Self::new(pos, pos) - } - - pub fn between(start: usize, end: usize) -> Self { - Self::new(start, end) - } - - pub fn encompassing(a: &Self, b: &Self) -> Self { - Self::new(cmp::min(a.start, b.start), cmp::max(a.end, b.end)) - } - - pub fn start(&self) -> usize { - self.start - } - - pub fn end(&self) -> usize { - self.end - } - - pub fn get<'a>(&self, reader: &'a str) -> &'a str { - &reader[self.start..self.end] - } - - pub fn is_empty(&self) -> bool { - self.start == self.end - } - - pub fn length(&self) -> usize { - self.end - self.start - } -} diff --git a/azalea-brigadier/src/string_reader.rs b/azalea-brigadier/src/string_reader.rs index f220267a..dcb35fcb 100644 --- a/azalea-brigadier/src/string_reader.rs +++ b/azalea-brigadier/src/string_reader.rs @@ -1,6 +1,4 @@ -use crate::exceptions::{ - builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException, -}; +use crate::exceptions::{BuiltInExceptions, CommandSyntaxException}; use std::str::FromStr; #[derive(Clone)] |
