aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-04-18 18:13:15 +0000
committermat <github@matdoes.dev>2022-04-18 18:13:15 +0000
commitb3864af9c4af83552e37fd71a46262967572f9e6 (patch)
tree14938d1b278ad18efd86868094a73f6de85f09fa
parent17d9f676ccdc69743e7717bb91f7ff2999c065f8 (diff)
downloadazalea-drasl-b3864af9c4af83552e37fd71a46262967572f9e6.tar.xz
split stuff into more modules
-rw-r--r--azalea-brigadier/src/builder/required_argument_builder.rs5
-rw-r--r--azalea-brigadier/src/context.rs202
-rw-r--r--azalea-brigadier/src/dispatcher.rs713
-rw-r--r--azalea-brigadier/src/exceptions/mod.rs7
-rw-r--r--azalea-brigadier/src/lib.rs5
-rw-r--r--azalea-brigadier/src/modifier.rs4
-rw-r--r--azalea-brigadier/src/parse_results.rs2
-rw-r--r--azalea-brigadier/src/parsers.rs4
-rw-r--r--azalea-brigadier/src/string_range.rs45
-rw-r--r--azalea-brigadier/src/string_reader.rs4
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)]