aboutsummaryrefslogtreecommitdiff
path: root/azalea-brigadier/src
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-05-30 20:07:28 -0330
committermat <git@matdoes.dev>2025-05-30 16:37:40 -0700
commita5e7ff771d657258cedcc7a8b3ce265c655f0860 (patch)
treeea5fdbbee32c1b9917a7ece03f6a1a70ee8e63fa /azalea-brigadier/src
parentda73b4316de4b26322c53f14222c7751a0be55a1 (diff)
downloadazalea-drasl-a5e7ff771d657258cedcc7a8b3ce265c655f0860.tar.xz
implement missing brigadier features and cleanup some more
Diffstat (limited to 'azalea-brigadier/src')
-rw-r--r--azalea-brigadier/src/arguments/argument_type.rs4
-rw-r--r--azalea-brigadier/src/arguments/bool_argument_type.rs4
-rw-r--r--azalea-brigadier/src/arguments/double_argument_type.rs8
-rw-r--r--azalea-brigadier/src/arguments/float_argument_type.rs8
-rw-r--r--azalea-brigadier/src/arguments/integer_argument_type.rs8
-rw-r--r--azalea-brigadier/src/arguments/long_argument_type.rs8
-rw-r--r--azalea-brigadier/src/arguments/string_argument_type.rs6
-rw-r--r--azalea-brigadier/src/builder/argument_builder.rs11
-rw-r--r--azalea-brigadier/src/builder/required_argument_builder.rs4
-rw-r--r--azalea-brigadier/src/command_dispatcher.rs119
-rw-r--r--azalea-brigadier/src/context/command_context.rs72
-rw-r--r--azalea-brigadier/src/context/context_chain.rs169
-rw-r--r--azalea-brigadier/src/context/mod.rs2
-rw-r--r--azalea-brigadier/src/errors/builtin_errors.rs (renamed from azalea-brigadier/src/exceptions/builtin_exceptions.rs)70
-rw-r--r--azalea-brigadier/src/errors/command_syntax_error.rs (renamed from azalea-brigadier/src/exceptions/command_syntax_exception.rs)29
-rw-r--r--azalea-brigadier/src/errors/mod.rs5
-rw-r--r--azalea-brigadier/src/exceptions/mod.rs5
-rw-r--r--azalea-brigadier/src/lib.rs3
-rw-r--r--azalea-brigadier/src/modifier.rs4
-rw-r--r--azalea-brigadier/src/parse_results.rs6
-rw-r--r--azalea-brigadier/src/result_consumer.rs12
-rw-r--r--azalea-brigadier/src/string_reader.rs53
-rw-r--r--azalea-brigadier/src/tree/mod.rs9
23 files changed, 395 insertions, 224 deletions
diff --git a/azalea-brigadier/src/arguments/argument_type.rs b/azalea-brigadier/src/arguments/argument_type.rs
index d7bfa7d6..45859538 100644
--- a/azalea-brigadier/src/arguments/argument_type.rs
+++ b/azalea-brigadier/src/arguments/argument_type.rs
@@ -1,13 +1,13 @@
use std::{any::Any, sync::Arc};
use crate::{
- exceptions::CommandSyntaxException,
+ errors::CommandSyntaxError,
string_reader::StringReader,
suggestion::{Suggestions, SuggestionsBuilder},
};
pub trait ArgumentType {
- fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException>;
+ fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError>;
fn list_suggestions(&self, _builder: SuggestionsBuilder) -> Suggestions {
Suggestions::default()
diff --git a/azalea-brigadier/src/arguments/bool_argument_type.rs b/azalea-brigadier/src/arguments/bool_argument_type.rs
index efb86509..225e985e 100644
--- a/azalea-brigadier/src/arguments/bool_argument_type.rs
+++ b/azalea-brigadier/src/arguments/bool_argument_type.rs
@@ -3,7 +3,7 @@ use std::{any::Any, sync::Arc};
use super::ArgumentType;
use crate::{
context::CommandContext,
- exceptions::CommandSyntaxException,
+ errors::CommandSyntaxError,
string_reader::StringReader,
suggestion::{Suggestions, SuggestionsBuilder},
};
@@ -12,7 +12,7 @@ use crate::{
struct Boolean;
impl ArgumentType for Boolean {
- fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> {
+ fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> {
Ok(Arc::new(reader.read_boolean()?))
}
diff --git a/azalea-brigadier/src/arguments/double_argument_type.rs b/azalea-brigadier/src/arguments/double_argument_type.rs
index 2e50d291..5b5d8cce 100644
--- a/azalea-brigadier/src/arguments/double_argument_type.rs
+++ b/azalea-brigadier/src/arguments/double_argument_type.rs
@@ -3,7 +3,7 @@ use std::{any::Any, sync::Arc};
use super::ArgumentType;
use crate::{
context::CommandContext,
- exceptions::{BuiltInExceptions, CommandSyntaxException},
+ errors::{BuiltInError, CommandSyntaxError},
string_reader::StringReader,
};
@@ -14,14 +14,14 @@ struct Double {
}
impl ArgumentType for Double {
- fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> {
+ fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> {
let start = reader.cursor;
let result = reader.read_double()?;
if let Some(minimum) = self.minimum
&& result < minimum
{
reader.cursor = start;
- return Err(BuiltInExceptions::DoubleTooSmall {
+ return Err(BuiltInError::DoubleTooSmall {
found: result,
min: minimum,
}
@@ -31,7 +31,7 @@ impl ArgumentType for Double {
&& result > maximum
{
reader.cursor = start;
- return Err(BuiltInExceptions::DoubleTooBig {
+ return Err(BuiltInError::DoubleTooBig {
found: result,
max: maximum,
}
diff --git a/azalea-brigadier/src/arguments/float_argument_type.rs b/azalea-brigadier/src/arguments/float_argument_type.rs
index 23dc88a5..8ea3a417 100644
--- a/azalea-brigadier/src/arguments/float_argument_type.rs
+++ b/azalea-brigadier/src/arguments/float_argument_type.rs
@@ -3,7 +3,7 @@ use std::{any::Any, sync::Arc};
use super::ArgumentType;
use crate::{
context::CommandContext,
- exceptions::{BuiltInExceptions, CommandSyntaxException},
+ errors::{BuiltInError, CommandSyntaxError},
string_reader::StringReader,
};
@@ -14,14 +14,14 @@ struct Float {
}
impl ArgumentType for Float {
- fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> {
+ fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> {
let start = reader.cursor;
let result = reader.read_float()?;
if let Some(minimum) = self.minimum
&& result < minimum
{
reader.cursor = start;
- return Err(BuiltInExceptions::FloatTooSmall {
+ return Err(BuiltInError::FloatTooSmall {
found: result,
min: minimum,
}
@@ -31,7 +31,7 @@ impl ArgumentType for Float {
&& result > maximum
{
reader.cursor = start;
- return Err(BuiltInExceptions::FloatTooBig {
+ return Err(BuiltInError::FloatTooBig {
found: result,
max: maximum,
}
diff --git a/azalea-brigadier/src/arguments/integer_argument_type.rs b/azalea-brigadier/src/arguments/integer_argument_type.rs
index b993d200..9cdb9c34 100644
--- a/azalea-brigadier/src/arguments/integer_argument_type.rs
+++ b/azalea-brigadier/src/arguments/integer_argument_type.rs
@@ -3,7 +3,7 @@ use std::{any::Any, sync::Arc};
use super::ArgumentType;
use crate::{
context::CommandContext,
- exceptions::{BuiltInExceptions, CommandSyntaxException},
+ errors::{BuiltInError, CommandSyntaxError},
string_reader::StringReader,
};
@@ -14,14 +14,14 @@ struct Integer {
}
impl ArgumentType for Integer {
- fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> {
+ fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> {
let start = reader.cursor;
let result = reader.read_int()?;
if let Some(minimum) = self.minimum
&& result < minimum
{
reader.cursor = start;
- return Err(BuiltInExceptions::IntegerTooSmall {
+ return Err(BuiltInError::IntegerTooSmall {
found: result,
min: minimum,
}
@@ -31,7 +31,7 @@ impl ArgumentType for Integer {
&& result > maximum
{
reader.cursor = start;
- return Err(BuiltInExceptions::IntegerTooBig {
+ return Err(BuiltInError::IntegerTooBig {
found: result,
max: maximum,
}
diff --git a/azalea-brigadier/src/arguments/long_argument_type.rs b/azalea-brigadier/src/arguments/long_argument_type.rs
index 1e27cf9d..1d4b3c9b 100644
--- a/azalea-brigadier/src/arguments/long_argument_type.rs
+++ b/azalea-brigadier/src/arguments/long_argument_type.rs
@@ -3,7 +3,7 @@ use std::{any::Any, sync::Arc};
use super::ArgumentType;
use crate::{
context::CommandContext,
- exceptions::{BuiltInExceptions, CommandSyntaxException},
+ errors::{BuiltInError, CommandSyntaxError},
string_reader::StringReader,
};
@@ -14,14 +14,14 @@ struct Long {
}
impl ArgumentType for Long {
- fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> {
+ fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> {
let start = reader.cursor;
let result = reader.read_long()?;
if let Some(minimum) = self.minimum
&& result < minimum
{
reader.cursor = start;
- return Err(BuiltInExceptions::LongTooSmall {
+ return Err(BuiltInError::LongTooSmall {
found: result,
min: minimum,
}
@@ -31,7 +31,7 @@ impl ArgumentType for Long {
&& result > maximum
{
reader.cursor = start;
- return Err(BuiltInExceptions::LongTooBig {
+ return Err(BuiltInError::LongTooBig {
found: result,
max: maximum,
}
diff --git a/azalea-brigadier/src/arguments/string_argument_type.rs b/azalea-brigadier/src/arguments/string_argument_type.rs
index 96b9c998..bcb040d6 100644
--- a/azalea-brigadier/src/arguments/string_argument_type.rs
+++ b/azalea-brigadier/src/arguments/string_argument_type.rs
@@ -1,9 +1,7 @@
use std::{any::Any, sync::Arc};
use super::ArgumentType;
-use crate::{
- context::CommandContext, exceptions::CommandSyntaxException, string_reader::StringReader,
-};
+use crate::{context::CommandContext, errors::CommandSyntaxError, string_reader::StringReader};
pub enum StringArgument {
/// Match up until the next space.
@@ -16,7 +14,7 @@ pub enum StringArgument {
}
impl ArgumentType for StringArgument {
- fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> {
+ fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> {
let result = match self {
StringArgument::SingleWord => reader.read_unquoted_string().to_string(),
StringArgument::QuotablePhrase => reader.read_string()?,
diff --git a/azalea-brigadier/src/builder/argument_builder.rs b/azalea-brigadier/src/builder/argument_builder.rs
index bc7f0ac6..1731d44d 100644
--- a/azalea-brigadier/src/builder/argument_builder.rs
+++ b/azalea-brigadier/src/builder/argument_builder.rs
@@ -5,6 +5,7 @@ use parking_lot::RwLock;
use super::{literal_argument_builder::Literal, required_argument_builder::Argument};
use crate::{
context::CommandContext,
+ errors::CommandSyntaxError,
modifier::RedirectModifier,
tree::{Command, CommandNode},
};
@@ -90,6 +91,16 @@ impl<S> ArgumentBuilder<S> {
where
F: Fn(&CommandContext<S>) -> i32 + Send + Sync + 'static,
{
+ self.command = Some(Arc::new(move |ctx: &CommandContext<S>| Ok(f(ctx))));
+ self
+ }
+
+ /// Same as [`Self::executes`] but returns a `Result<i32,
+ /// CommandSyntaxError>`.
+ pub fn executes_result<F>(mut self, f: F) -> Self
+ where
+ F: Fn(&CommandContext<S>) -> Result<i32, CommandSyntaxError> + Send + Sync + 'static,
+ {
self.command = Some(Arc::new(f));
self
}
diff --git a/azalea-brigadier/src/builder/required_argument_builder.rs b/azalea-brigadier/src/builder/required_argument_builder.rs
index 7c0f1015..3fc33143 100644
--- a/azalea-brigadier/src/builder/required_argument_builder.rs
+++ b/azalea-brigadier/src/builder/required_argument_builder.rs
@@ -8,7 +8,7 @@ use super::argument_builder::{ArgumentBuilder, ArgumentBuilderType};
use crate::{
arguments::ArgumentType,
context::CommandContext,
- exceptions::CommandSyntaxException,
+ errors::CommandSyntaxError,
string_reader::StringReader,
suggestion::{SuggestionProvider, Suggestions, SuggestionsBuilder},
};
@@ -33,7 +33,7 @@ impl<S> Argument<S> {
}
}
- pub fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> {
+ pub fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> {
self.parser.parse(reader)
}
diff --git a/azalea-brigadier/src/command_dispatcher.rs b/azalea-brigadier/src/command_dispatcher.rs
index 4a3b51d7..df732291 100644
--- a/azalea-brigadier/src/command_dispatcher.rs
+++ b/azalea-brigadier/src/command_dispatcher.rs
@@ -1,7 +1,7 @@
use std::{
cmp::Ordering,
collections::{HashMap, HashSet},
- mem, ptr,
+ ptr,
rc::Rc,
sync::Arc,
};
@@ -10,9 +10,10 @@ use parking_lot::RwLock;
use crate::{
builder::argument_builder::ArgumentBuilder,
- context::{CommandContext, CommandContextBuilder},
- exceptions::{BuiltInExceptions, CommandSyntaxException},
+ context::{CommandContextBuilder, ContextChain},
+ errors::{BuiltInError, CommandSyntaxError},
parse_results::ParseResults,
+ result_consumer::{DefaultResultConsumer, ResultConsumer},
string_reader::StringReader,
suggestion::{Suggestions, SuggestionsBuilder},
tree::CommandNode,
@@ -30,12 +31,14 @@ where
Self: Sync + Send,
{
pub root: Arc<RwLock<CommandNode<S>>>,
+ consumer: Box<dyn ResultConsumer<S> + Send + Sync>,
}
impl<S> CommandDispatcher<S> {
pub fn new() -> Self {
Self {
root: Arc::new(RwLock::new(CommandNode::default())),
+ consumer: Box::new(DefaultResultConsumer),
}
}
@@ -64,10 +67,10 @@ impl<S> CommandDispatcher<S> {
node: &Arc<RwLock<CommandNode<S>>>,
original_reader: &StringReader,
context_so_far: CommandContextBuilder<'a, S>,
- ) -> Result<ParseResults<'a, S>, CommandSyntaxException> {
+ ) -> Result<ParseResults<'a, S>, CommandSyntaxError> {
let source = context_so_far.source.clone();
#[allow(clippy::mutable_key_type)] // this is fine because we don't mutate the key
- let mut errors = HashMap::<Rc<CommandNode<S>>, CommandSyntaxException>::new();
+ let mut errors = HashMap::<Rc<CommandNode<S>>, CommandSyntaxError>::new();
let mut potentials: Vec<ParseResults<S>> = vec![];
let cursor = original_reader.cursor();
@@ -83,7 +86,7 @@ impl<S> CommandDispatcher<S> {
if let Err(ex) = parse_with_context_result {
errors.insert(
Rc::new((*child.read()).clone()),
- BuiltInExceptions::DispatcherParseException {
+ BuiltInError::DispatcherParseException {
message: ex.message(),
}
.create_with_context(&reader),
@@ -94,8 +97,7 @@ impl<S> CommandDispatcher<S> {
if reader.can_read() && reader.peek() != ' ' {
errors.insert(
Rc::new((*child.read()).clone()),
- BuiltInExceptions::DispatcherExpectedArgumentSeparator
- .create_with_context(&reader),
+ BuiltInError::DispatcherExpectedArgumentSeparator.create_with_context(&reader),
);
reader.cursor = cursor;
continue;
@@ -179,11 +181,11 @@ impl<S> CommandDispatcher<S> {
&self,
input: impl Into<StringReader>,
source: S,
- ) -> Result<i32, CommandSyntaxException> {
+ ) -> Result<i32, CommandSyntaxError> {
let input = input.into();
let parse = self.parse(input, source);
- Self::execute_parsed(parse)
+ self.execute_parsed(parse)
}
pub fn add_paths(
@@ -235,91 +237,26 @@ impl<S> CommandDispatcher<S> {
}
/// Executes a given pre-parsed command.
- pub fn execute_parsed(parse: ParseResults<S>) -> Result<i32, CommandSyntaxException> {
+ pub fn execute_parsed(&self, parse: ParseResults<S>) -> Result<i32, CommandSyntaxError> {
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 {
- let child = &context.child;
- if let Some(child) = child {
- forked |= child.forks;
- if child.has_nodes() {
- found_command = true;
- let modifier = &context.modifier;
- if let Some(modifier) = modifier {
- let results = modifier(context);
- match results {
- Ok(results) => {
- if !results.is_empty() {
- next.extend(
- results.iter().map(|s| child.copy_for(s.clone())),
- );
- }
- }
- _ => {
- // 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();
+ return Err(if parse.exceptions.len() == 1 {
+ parse.exceptions.values().next().unwrap().clone()
+ } else if parse.context.range.is_empty() {
+ BuiltInError::DispatcherUnknownCommand.create_with_context(&parse.reader)
+ } else {
+ BuiltInError::DispatcherUnknownArgument.create_with_context(&parse.reader)
+ });
}
- if !found_command {
- // consumer.on_command_complete(original, false, 0);
- return Err(
- BuiltInExceptions::DispatcherUnknownCommand.create_with_context(&parse.reader)
- );
- }
+ let command = parse.reader.string();
+ let original = Rc::new(parse.context.build(command));
+ let flat_context = ContextChain::try_flatten(original.clone());
+ let Some(flat_context) = flat_context else {
+ self.consumer.on_command_complete(original, false, 0);
+ return Err(BuiltInError::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 })
+ flat_context.execute_all(original.source().clone(), self.consumer.as_ref())
}
pub fn get_all_usage(
diff --git a/azalea-brigadier/src/context/command_context.rs b/azalea-brigadier/src/context/command_context.rs
index 202d6f21..224f2d63 100644
--- a/azalea-brigadier/src/context/command_context.rs
+++ b/azalea-brigadier/src/context/command_context.rs
@@ -10,16 +10,16 @@ use crate::{
/// A built `CommandContextBuilder`.
pub struct CommandContext<S> {
- pub source: Arc<S>,
- pub input: String,
- pub arguments: HashMap<String, ParsedArgument>,
- pub command: Command<S>,
- pub root_node: Arc<RwLock<CommandNode<S>>>,
- pub nodes: Vec<ParsedCommandNode<S>>,
- pub range: StringRange,
- pub child: Option<Rc<CommandContext<S>>>,
- pub modifier: Option<Arc<RedirectModifier<S>>>,
- pub forks: bool,
+ pub(super) source: Arc<S>,
+ pub(super) input: String,
+ pub(super) arguments: HashMap<String, ParsedArgument>,
+ pub(super) command: Command<S>,
+ pub(super) root_node: Arc<RwLock<CommandNode<S>>>,
+ pub(super) nodes: Vec<ParsedCommandNode<S>>,
+ pub(super) range: StringRange,
+ pub(super) child: Option<Rc<CommandContext<S>>>,
+ pub(super) modifier: Option<Arc<RedirectModifier<S>>>,
+ pub(super) forks: bool,
}
impl<S> Clone for CommandContext<S> {
@@ -59,8 +59,10 @@ impl<S> Debug for CommandContext<S> {
impl<S> CommandContext<S> {
pub fn copy_for(&self, source: Arc<S>) -> Self {
if Arc::ptr_eq(&source, &self.source) {
+ // fast path
return self.clone();
}
+
CommandContext {
source,
input: self.input.clone(),
@@ -75,12 +77,56 @@ impl<S> CommandContext<S> {
}
}
+ pub fn child(&self) -> Option<&CommandContext<S>> {
+ self.child.as_ref().map(|c| c.as_ref())
+ }
+
+ pub fn last_child(&self) -> &CommandContext<S> {
+ let mut result = self;
+ while let Some(child) = result.child() {
+ result = child;
+ }
+ result
+ }
+
+ pub fn command(&self) -> &Command<S> {
+ &self.command
+ }
+
+ pub fn source(&self) -> &Arc<S> {
+ &self.source
+ }
+
+ pub fn argument(&self, name: &str) -> Option<&dyn Any> {
+ let argument = self.arguments.get(name);
+ argument.map(|a| a.result.as_ref())
+ }
+
+ pub fn redirect_modifier(&self) -> Option<&RedirectModifier<S>> {
+ self.modifier.as_ref().map(|m| m.as_ref())
+ }
+
+ pub fn range(&self) -> &StringRange {
+ &self.range
+ }
+
+ pub fn input(&self) -> &str {
+ &self.input
+ }
+
+ pub fn root_node(&self) -> &Arc<RwLock<CommandNode<S>>> {
+ &self.root_node
+ }
+
+ pub fn nodes(&self) -> &[ParsedCommandNode<S>] {
+ &self.nodes
+ }
+
pub fn has_nodes(&self) -> bool {
!self.nodes.is_empty()
}
- pub fn argument(&self, name: &str) -> Option<Arc<dyn Any>> {
- let argument = self.arguments.get(name);
- argument.map(|a| a.result.clone())
+ pub fn is_forked(&self) -> bool {
+ self.forks
}
}
diff --git a/azalea-brigadier/src/context/context_chain.rs b/azalea-brigadier/src/context/context_chain.rs
new file mode 100644
index 00000000..74fe6e01
--- /dev/null
+++ b/azalea-brigadier/src/context/context_chain.rs
@@ -0,0 +1,169 @@
+use std::{rc::Rc, sync::Arc};
+
+use super::CommandContext;
+use crate::{errors::CommandSyntaxError, result_consumer::ResultConsumer};
+
+pub struct ContextChain<S> {
+ modifiers: Vec<Rc<CommandContext<S>>>,
+ executable: Rc<CommandContext<S>>,
+ next_stage_cache: Option<Rc<ContextChain<S>>>,
+}
+
+impl<S> ContextChain<S> {
+ pub fn new(modifiers: Vec<Rc<CommandContext<S>>>, executable: Rc<CommandContext<S>>) -> Self {
+ if executable.command.is_none() {
+ panic!("Last command in chain must be executable");
+ }
+ Self {
+ modifiers,
+ executable,
+ next_stage_cache: None,
+ }
+ }
+
+ pub fn try_flatten(root_context: Rc<CommandContext<S>>) -> Option<Self> {
+ let mut modifiers = Vec::new();
+ let mut current = root_context;
+ loop {
+ let child = current.child.clone();
+ let Some(child) = child else {
+ // Last entry must be executable command
+ if current.command.is_none() {
+ return None;
+ }
+
+ return Some(ContextChain::new(modifiers, current));
+ };
+
+ modifiers.push(current);
+ current = child;
+ }
+ }
+
+ pub fn run_modifier(
+ modifier: Rc<CommandContext<S>>,
+ source: Arc<S>,
+ result_consumer: &dyn ResultConsumer<S>,
+ forked_mode: bool,
+ ) -> Result<Vec<Arc<S>>, CommandSyntaxError> {
+ let source_modifier = modifier.redirect_modifier();
+ let Some(source_modifier) = source_modifier else {
+ return Ok(vec![source]);
+ };
+
+ let context_to_use = Rc::new(modifier.copy_for(source));
+ let err = match (source_modifier)(&context_to_use) {
+ Ok(res) => return Ok(res),
+ Err(e) => e,
+ };
+
+ result_consumer.on_command_complete(context_to_use, false, 0);
+ if forked_mode {
+ return Ok(vec![]);
+ }
+ Err(err)
+ }
+
+ pub fn run_executable(
+ &self,
+ executable: Rc<CommandContext<S>>,
+ source: Arc<S>,
+ result_consumer: &dyn ResultConsumer<S>,
+ forked_mode: bool,
+ ) -> Result<i32, CommandSyntaxError> {
+ let context_to_use = Rc::new(executable.copy_for(source));
+ let Some(command) = &executable.command else {
+ unimplemented!();
+ };
+
+ let err = match (command)(&context_to_use) {
+ Ok(result) => {
+ result_consumer.on_command_complete(context_to_use, true, result);
+ return if forked_mode { Ok(1) } else { Ok(result) };
+ }
+ Err(err) => err,
+ };
+
+ result_consumer.on_command_complete(context_to_use, false, 0);
+ if forked_mode { Ok(0) } else { Err(err) }
+ }
+
+ pub fn execute_all(
+ &self,
+ source: Arc<S>,
+ result_consumer: &(dyn ResultConsumer<S>),
+ ) -> Result<i32, CommandSyntaxError> {
+ if self.modifiers.is_empty() {
+ return self.run_executable(self.executable.clone(), source, result_consumer, false);
+ }
+
+ let mut forked_mode = false;
+ let mut current_sources = vec![source];
+
+ for modifier in &self.modifiers {
+ forked_mode |= modifier.is_forked();
+
+ let mut next_sources = Vec::new();
+ for source_to_run in current_sources {
+ next_sources.extend(Self::run_modifier(
+ modifier.clone(),
+ source_to_run.clone(),
+ result_consumer,
+ forked_mode,
+ )?);
+ }
+ if next_sources.is_empty() {
+ return Ok(0);
+ }
+ current_sources = next_sources;
+ }
+
+ let mut result = 0;
+ for execution_source in current_sources {
+ result += self.run_executable(
+ self.executable.clone(),
+ execution_source,
+ result_consumer,
+ forked_mode,
+ )?;
+ }
+
+ Ok(result)
+ }
+
+ pub fn stage(&self) -> Stage {
+ if self.modifiers.is_empty() {
+ Stage::Execute
+ } else {
+ Stage::Modify
+ }
+ }
+
+ pub fn top_context(&self) -> Rc<CommandContext<S>> {
+ self.modifiers
+ .first()
+ .cloned()
+ .unwrap_or_else(|| self.executable.clone())
+ }
+
+ pub fn next_stage(&mut self) -> Option<Rc<ContextChain<S>>> {
+ let modifier_count = self.modifiers.len();
+ if modifier_count == 0 {
+ return None;
+ }
+
+ if self.next_stage_cache.is_none() {
+ self.next_stage_cache = Some(Rc::new(ContextChain::new(
+ self.modifiers[1..].to_vec(),
+ self.executable.clone(),
+ )));
+ }
+
+ self.next_stage_cache.clone()
+ }
+}
+
+pub enum Stage {
+ Modify,
+ Execute,
+}
diff --git a/azalea-brigadier/src/context/mod.rs b/azalea-brigadier/src/context/mod.rs
index 28e1a12e..815892bf 100644
--- a/azalea-brigadier/src/context/mod.rs
+++ b/azalea-brigadier/src/context/mod.rs
@@ -1,5 +1,6 @@
mod command_context;
mod command_context_builder;
+mod context_chain;
mod parsed_argument;
mod parsed_command_node;
mod string_range;
@@ -7,6 +8,7 @@ pub mod suggestion_context;
pub use command_context::CommandContext;
pub use command_context_builder::CommandContextBuilder;
+pub use context_chain::ContextChain;
pub use parsed_argument::ParsedArgument;
pub use parsed_command_node::ParsedCommandNode;
pub use string_range::StringRange;
diff --git a/azalea-brigadier/src/exceptions/builtin_exceptions.rs b/azalea-brigadier/src/errors/builtin_errors.rs
index bf2072c1..36803397 100644
--- a/azalea-brigadier/src/exceptions/builtin_exceptions.rs
+++ b/azalea-brigadier/src/errors/builtin_errors.rs
@@ -1,10 +1,10 @@
use std::fmt;
-use super::command_syntax_exception::CommandSyntaxException;
+use super::command_syntax_error::CommandSyntaxError;
use crate::string_reader::StringReader;
#[derive(Clone, PartialEq)]
-pub enum BuiltInExceptions {
+pub enum BuiltInError {
DoubleTooSmall { found: f64, min: f64 },
DoubleTooBig { found: f64, max: f64 },
@@ -40,114 +40,114 @@ pub enum BuiltInExceptions {
DispatcherParseException { message: String },
}
-impl fmt::Debug for BuiltInExceptions {
+impl fmt::Debug for BuiltInError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- BuiltInExceptions::DoubleTooSmall { found, min } => {
+ BuiltInError::DoubleTooSmall { found, min } => {
write!(f, "Double must not be less than {min}, found {found}")
}
- BuiltInExceptions::DoubleTooBig { found, max } => {
+ BuiltInError::DoubleTooBig { found, max } => {
write!(f, "Double must not be more than {max}, found {found}")
}
- BuiltInExceptions::FloatTooSmall { found, min } => {
+ BuiltInError::FloatTooSmall { found, min } => {
write!(f, "Float must not be less than {min}, found {found}")
}
- BuiltInExceptions::FloatTooBig { found, max } => {
+ BuiltInError::FloatTooBig { found, max } => {
write!(f, "Float must not be more than {max}, found {found}")
}
- BuiltInExceptions::IntegerTooSmall { found, min } => {
+ BuiltInError::IntegerTooSmall { found, min } => {
write!(f, "Integer must not be less than {min}, found {found}")
}
- BuiltInExceptions::IntegerTooBig { found, max } => {
+ BuiltInError::IntegerTooBig { found, max } => {
write!(f, "Integer must not be more than {max}, found {found}")
}
- BuiltInExceptions::LongTooSmall { found, min } => {
+ BuiltInError::LongTooSmall { found, min } => {
write!(f, "Long must not be less than {min}, found {found}")
}
- BuiltInExceptions::LongTooBig { found, max } => {
+ BuiltInError::LongTooBig { found, max } => {
write!(f, "Long must not be more than {max}, found {found}")
}
- BuiltInExceptions::LiteralIncorrect { expected } => {
+ BuiltInError::LiteralIncorrect { expected } => {
write!(f, "Expected literal {expected}")
}
- BuiltInExceptions::ReaderExpectedStartOfQuote => {
+ BuiltInError::ReaderExpectedStartOfQuote => {
write!(f, "Expected quote to start a string")
}
- BuiltInExceptions::ReaderExpectedEndOfQuote => {
+ BuiltInError::ReaderExpectedEndOfQuote => {
write!(f, "Unclosed quoted string")
}
- BuiltInExceptions::ReaderInvalidEscape { character } => {
+ BuiltInError::ReaderInvalidEscape { character } => {
write!(f, "Invalid escape sequence '{character}' in quoted string")
}
- BuiltInExceptions::ReaderInvalidBool { value } => {
+ BuiltInError::ReaderInvalidBool { value } => {
write!(
f,
"Invalid bool, expected true or false but found '{value}'"
)
}
- BuiltInExceptions::ReaderInvalidInt { value } => {
+ BuiltInError::ReaderInvalidInt { value } => {
write!(f, "Invalid Integer '{value}'")
}
- BuiltInExceptions::ReaderExpectedInt => {
+ BuiltInError::ReaderExpectedInt => {
write!(f, "Expected Integer")
}
- BuiltInExceptions::ReaderInvalidLong { value } => {
+ BuiltInError::ReaderInvalidLong { value } => {
write!(f, "Invalid long '{value}'")
}
- BuiltInExceptions::ReaderExpectedLong => {
+ BuiltInError::ReaderExpectedLong => {
write!(f, "Expected long")
}
- BuiltInExceptions::ReaderInvalidDouble { value } => {
+ BuiltInError::ReaderInvalidDouble { value } => {
write!(f, "Invalid double '{value}'")
}
- BuiltInExceptions::ReaderExpectedDouble => {
+ BuiltInError::ReaderExpectedDouble => {
write!(f, "Expected double")
}
- BuiltInExceptions::ReaderInvalidFloat { value } => {
+ BuiltInError::ReaderInvalidFloat { value } => {
write!(f, "Invalid Float '{value}'")
}
- BuiltInExceptions::ReaderExpectedFloat => {
+ BuiltInError::ReaderExpectedFloat => {
write!(f, "Expected Float")
}
- BuiltInExceptions::ReaderExpectedBool => {
+ BuiltInError::ReaderExpectedBool => {
write!(f, "Expected bool")
}
- BuiltInExceptions::ReaderExpectedSymbol { symbol } => {
+ BuiltInError::ReaderExpectedSymbol { symbol } => {
write!(f, "Expected '{symbol}'")
}
- BuiltInExceptions::DispatcherUnknownCommand => {
+ BuiltInError::DispatcherUnknownCommand => {
write!(f, "Unknown command")
}
- BuiltInExceptions::DispatcherUnknownArgument => {
+ BuiltInError::DispatcherUnknownArgument => {
write!(f, "Incorrect argument for command")
}
- BuiltInExceptions::DispatcherExpectedArgumentSeparator => {
+ BuiltInError::DispatcherExpectedArgumentSeparator => {
write!(
f,
"Expected whitespace to end one argument, but found trailing data"
)
}
- BuiltInExceptions::DispatcherParseException { message } => {
+ BuiltInError::DispatcherParseException { message } => {
write!(f, "Could not parse command: {message}")
}
}
}
}
-impl BuiltInExceptions {
- pub fn create(self) -> CommandSyntaxException {
+impl BuiltInError {
+ pub fn create(self) -> CommandSyntaxError {
let message = format!("{self:?}");
- CommandSyntaxException::create(self, message)
+ CommandSyntaxError::create(self, message)
}
- pub fn create_with_context(self, reader: &StringReader) -> CommandSyntaxException {
+ pub fn create_with_context(self, reader: &StringReader) -> CommandSyntaxError {
let message = format!("{self:?}");
- CommandSyntaxException::new(self, message, reader.string(), reader.cursor())
+ CommandSyntaxError::new(self, message, reader.string(), reader.cursor())
}
}
diff --git a/azalea-brigadier/src/exceptions/command_syntax_exception.rs b/azalea-brigadier/src/errors/command_syntax_error.rs
index c9b8134f..a476fec4 100644
--- a/azalea-brigadier/src/exceptions/command_syntax_exception.rs
+++ b/azalea-brigadier/src/errors/command_syntax_error.rs
@@ -1,13 +1,13 @@
use std::{
cmp,
- fmt::{self, Write},
+ fmt::{self, Debug, Write},
};
-use super::builtin_exceptions::BuiltInExceptions;
+use super::builtin_errors::BuiltInError;
#[derive(Clone, PartialEq)]
-pub struct CommandSyntaxException {
- pub type_: BuiltInExceptions,
+pub struct CommandSyntaxError {
+ kind: BuiltInError,
message: String,
input: Option<String>,
cursor: Option<usize>,
@@ -15,19 +15,19 @@ pub struct CommandSyntaxException {
const CONTEXT_AMOUNT: usize = 10;
-impl CommandSyntaxException {
- pub fn new(type_: BuiltInExceptions, message: String, input: &str, cursor: usize) -> Self {
+impl CommandSyntaxError {
+ pub fn new(kind: BuiltInError, message: String, input: &str, cursor: usize) -> Self {
Self {
- type_,
+ kind,
message,
input: Some(input.to_string()),
cursor: Some(cursor),
}
}
- pub fn create(type_: BuiltInExceptions, message: String) -> Self {
+ pub fn create(kind: BuiltInError, message: String) -> Self {
Self {
- type_,
+ kind,
message,
input: None,
cursor: None,
@@ -40,9 +40,8 @@ impl CommandSyntaxException {
if let Some(context) = context {
write!(
message,
- " at position {}: {}",
- self.cursor.unwrap_or(usize::MAX),
- context
+ " at position {}: {context}",
+ self.cursor.unwrap_or(usize::MAX)
)
.unwrap();
}
@@ -74,8 +73,8 @@ impl CommandSyntaxException {
None
}
- pub fn get_type(&self) -> &BuiltInExceptions {
- &self.type_
+ pub fn kind(&self) -> &BuiltInError {
+ &self.kind
}
pub fn input(&self) -> &Option<String> {
@@ -87,7 +86,7 @@ impl CommandSyntaxException {
}
}
-impl fmt::Debug for CommandSyntaxException {
+impl Debug for CommandSyntaxError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message())
}
diff --git a/azalea-brigadier/src/errors/mod.rs b/azalea-brigadier/src/errors/mod.rs
new file mode 100644
index 00000000..facebe5e
--- /dev/null
+++ b/azalea-brigadier/src/errors/mod.rs
@@ -0,0 +1,5 @@
+mod builtin_errors;
+mod command_syntax_error;
+
+pub use builtin_errors::BuiltInError;
+pub use command_syntax_error::CommandSyntaxError;
diff --git a/azalea-brigadier/src/exceptions/mod.rs b/azalea-brigadier/src/exceptions/mod.rs
deleted file mode 100644
index 6b9c8d62..00000000
--- a/azalea-brigadier/src/exceptions/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-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 4f704d46..28f529f2 100644
--- a/azalea-brigadier/src/lib.rs
+++ b/azalea-brigadier/src/lib.rs
@@ -4,9 +4,10 @@ pub mod arguments;
pub mod builder;
pub mod command_dispatcher;
pub mod context;
-pub mod exceptions;
+pub mod errors;
pub mod modifier;
pub mod parse_results;
+pub mod result_consumer;
pub mod string_reader;
pub mod suggestion;
pub mod tree;
diff --git a/azalea-brigadier/src/modifier.rs b/azalea-brigadier/src/modifier.rs
index bebdd0cb..aba5e95f 100644
--- a/azalea-brigadier/src/modifier.rs
+++ b/azalea-brigadier/src/modifier.rs
@@ -1,6 +1,6 @@
use std::sync::Arc;
-use crate::{context::CommandContext, exceptions::CommandSyntaxException};
+use crate::{context::CommandContext, errors::CommandSyntaxError};
pub type RedirectModifier<S> =
- dyn Fn(&CommandContext<S>) -> Result<Vec<Arc<S>>, CommandSyntaxException> + Send + Sync;
+ dyn Fn(&CommandContext<S>) -> Result<Vec<Arc<S>>, CommandSyntaxError> + Send + Sync;
diff --git a/azalea-brigadier/src/parse_results.rs b/azalea-brigadier/src/parse_results.rs
index a2cefcf7..73de8d47 100644
--- a/azalea-brigadier/src/parse_results.rs
+++ b/azalea-brigadier/src/parse_results.rs
@@ -1,14 +1,14 @@
use std::{collections::HashMap, fmt::Debug, rc::Rc};
use crate::{
- context::CommandContextBuilder, exceptions::CommandSyntaxException,
- string_reader::StringReader, tree::CommandNode,
+ context::CommandContextBuilder, errors::CommandSyntaxError, string_reader::StringReader,
+ tree::CommandNode,
};
pub struct ParseResults<'a, S> {
pub context: CommandContextBuilder<'a, S>,
pub reader: StringReader,
- pub exceptions: HashMap<Rc<CommandNode<S>>, CommandSyntaxException>,
+ pub exceptions: HashMap<Rc<CommandNode<S>>, CommandSyntaxError>,
}
impl<S> Debug for ParseResults<'_, S> {
diff --git a/azalea-brigadier/src/result_consumer.rs b/azalea-brigadier/src/result_consumer.rs
new file mode 100644
index 00000000..fb9dd135
--- /dev/null
+++ b/azalea-brigadier/src/result_consumer.rs
@@ -0,0 +1,12 @@
+use std::rc::Rc;
+
+use crate::context::CommandContext;
+
+pub trait ResultConsumer<S> {
+ fn on_command_complete(&self, context: Rc<CommandContext<S>>, success: bool, result: i32);
+}
+
+pub struct DefaultResultConsumer;
+impl<S> ResultConsumer<S> for DefaultResultConsumer {
+ fn on_command_complete(&self, _context: Rc<CommandContext<S>>, _success: bool, _result: i32) {}
+}
diff --git a/azalea-brigadier/src/string_reader.rs b/azalea-brigadier/src/string_reader.rs
index 963a2244..8dd41ed3 100644
--- a/azalea-brigadier/src/string_reader.rs
+++ b/azalea-brigadier/src/string_reader.rs
@@ -1,6 +1,6 @@
use std::str::FromStr;
-use crate::exceptions::{BuiltInExceptions, CommandSyntaxException};
+use crate::errors::{BuiltInError, CommandSyntaxError};
#[derive(Clone)]
pub struct StringReader {
@@ -91,19 +91,19 @@ impl StringReader {
}
}
- pub fn read_int(&mut self) -> Result<i32, CommandSyntaxException> {
+ pub fn read_int(&mut self) -> Result<i32, CommandSyntaxError> {
let start = self.cursor;
while self.can_read() && StringReader::is_allowed_number(self.peek()) {
self.skip();
}
let number = &self.string[start..self.cursor];
if number.is_empty() {
- return Err(BuiltInExceptions::ReaderExpectedInt.create_with_context(self));
+ return Err(BuiltInError::ReaderExpectedInt.create_with_context(self));
}
let result = i32::from_str(number);
if result.is_err() {
self.cursor = start;
- return Err(BuiltInExceptions::ReaderInvalidInt {
+ return Err(BuiltInError::ReaderInvalidInt {
value: number.to_string(),
}
.create_with_context(self));
@@ -112,19 +112,19 @@ impl StringReader {
Ok(result.unwrap())
}
- pub fn read_long(&mut self) -> Result<i64, CommandSyntaxException> {
+ pub fn read_long(&mut self) -> Result<i64, CommandSyntaxError> {
let start = self.cursor;
while self.can_read() && StringReader::is_allowed_number(self.peek()) {
self.skip();
}
let number = &self.string[start..self.cursor];
if number.is_empty() {
- return Err(BuiltInExceptions::ReaderExpectedLong.create_with_context(self));
+ return Err(BuiltInError::ReaderExpectedLong.create_with_context(self));
}
let result = i64::from_str(number);
if result.is_err() {
self.cursor = start;
- return Err(BuiltInExceptions::ReaderInvalidLong {
+ return Err(BuiltInError::ReaderInvalidLong {
value: number.to_string(),
}
.create_with_context(self));
@@ -133,19 +133,19 @@ impl StringReader {
Ok(result.unwrap())
}
- pub fn read_double(&mut self) -> Result<f64, CommandSyntaxException> {
+ pub fn read_double(&mut self) -> Result<f64, CommandSyntaxError> {
let start = self.cursor;
while self.can_read() && StringReader::is_allowed_number(self.peek()) {
self.skip();
}
let number = &self.string[start..self.cursor];
if number.is_empty() {
- return Err(BuiltInExceptions::ReaderExpectedDouble.create_with_context(self));
+ return Err(BuiltInError::ReaderExpectedDouble.create_with_context(self));
}
let result = f64::from_str(number);
if result.is_err() {
self.cursor = start;
- return Err(BuiltInExceptions::ReaderInvalidDouble {
+ return Err(BuiltInError::ReaderInvalidDouble {
value: number.to_string(),
}
.create_with_context(self));
@@ -154,19 +154,19 @@ impl StringReader {
Ok(result.unwrap())
}
- pub fn read_float(&mut self) -> Result<f32, CommandSyntaxException> {
+ pub fn read_float(&mut self) -> Result<f32, CommandSyntaxError> {
let start = self.cursor;
while self.can_read() && StringReader::is_allowed_number(self.peek()) {
self.skip();
}
let number = &self.string[start..self.cursor];
if number.is_empty() {
- return Err(BuiltInExceptions::ReaderExpectedFloat.create_with_context(self));
+ return Err(BuiltInError::ReaderExpectedFloat.create_with_context(self));
}
let result = f32::from_str(number);
if result.is_err() {
self.cursor = start;
- return Err(BuiltInExceptions::ReaderInvalidFloat {
+ return Err(BuiltInError::ReaderInvalidFloat {
value: number.to_string(),
}
.create_with_context(self));
@@ -193,22 +193,19 @@ impl StringReader {
&self.string[start..self.cursor]
}
- pub fn read_quoted_string(&mut self) -> Result<String, CommandSyntaxException> {
+ pub fn read_quoted_string(&mut self) -> Result<String, CommandSyntaxError> {
if !self.can_read() {
return Ok(String::new());
}
let next = self.peek();
if !StringReader::is_quoted_string_start(next) {
- return Err(BuiltInExceptions::ReaderExpectedStartOfQuote.create_with_context(self));
+ return Err(BuiltInError::ReaderExpectedStartOfQuote.create_with_context(self));
}
self.skip();
self.read_string_until(next)
}
- pub fn read_string_until(
- &mut self,
- terminator: char,
- ) -> Result<String, CommandSyntaxException> {
+ pub fn read_string_until(&mut self, terminator: char) -> Result<String, CommandSyntaxError> {
let mut result = String::new();
let mut escaped = false;
while self.can_read() {
@@ -219,7 +216,7 @@ impl StringReader {
escaped = false;
} else {
self.cursor -= 1;
- return Err(BuiltInExceptions::ReaderInvalidEscape { character: c }
+ return Err(BuiltInError::ReaderInvalidEscape { character: c }
.create_with_context(self));
}
} else if c == SYNTAX_ESCAPE {
@@ -231,10 +228,10 @@ impl StringReader {
}
}
- Err(BuiltInExceptions::ReaderExpectedEndOfQuote.create_with_context(self))
+ Err(BuiltInError::ReaderExpectedEndOfQuote.create_with_context(self))
}
- pub fn read_string(&mut self) -> Result<String, CommandSyntaxException> {
+ pub fn read_string(&mut self) -> Result<String, CommandSyntaxError> {
if !self.can_read() {
return Ok(String::new());
}
@@ -246,11 +243,11 @@ impl StringReader {
Ok(self.read_unquoted_string().to_string())
}
- pub fn read_boolean(&mut self) -> Result<bool, CommandSyntaxException> {
+ pub fn read_boolean(&mut self) -> Result<bool, CommandSyntaxError> {
let start = self.cursor;
let value = self.read_string()?;
if value.is_empty() {
- return Err(BuiltInExceptions::ReaderExpectedBool.create_with_context(self));
+ return Err(BuiltInError::ReaderExpectedBool.create_with_context(self));
}
if value == "true" {
@@ -259,15 +256,13 @@ impl StringReader {
Ok(false)
} else {
self.cursor = start;
- Err(BuiltInExceptions::ReaderInvalidBool { value }.create_with_context(self))
+ Err(BuiltInError::ReaderInvalidBool { value }.create_with_context(self))
}
}
- pub fn expect(&mut self, c: char) -> Result<(), CommandSyntaxException> {
+ pub fn expect(&mut self, c: char) -> Result<(), CommandSyntaxError> {
if !self.can_read() || self.peek() != c {
- return Err(
- BuiltInExceptions::ReaderExpectedSymbol { symbol: c }.create_with_context(self)
- );
+ return Err(BuiltInError::ReaderExpectedSymbol { symbol: c }.create_with_context(self));
}
self.skip();
Ok(())
diff --git a/azalea-brigadier/src/tree/mod.rs b/azalea-brigadier/src/tree/mod.rs
index 8181f817..bf53b4ff 100644
--- a/azalea-brigadier/src/tree/mod.rs
+++ b/azalea-brigadier/src/tree/mod.rs
@@ -14,13 +14,14 @@ use crate::{
required_argument_builder::Argument,
},
context::{CommandContext, CommandContextBuilder, ParsedArgument, StringRange},
- exceptions::{BuiltInExceptions, CommandSyntaxException},
+ errors::{BuiltInError, CommandSyntaxError},
modifier::RedirectModifier,
string_reader::StringReader,
suggestion::{Suggestions, SuggestionsBuilder},
};
-pub type Command<S> = Option<Arc<dyn Fn(&CommandContext<S>) -> i32 + Send + Sync>>;
+pub type Command<S> =
+ Option<Arc<dyn Fn(&CommandContext<S>) -> Result<i32, CommandSyntaxError> + Send + Sync>>;
/// An ArgumentBuilder that has been built.
#[non_exhaustive]
@@ -149,7 +150,7 @@ impl<S> CommandNode<S> {
&self,
reader: &mut StringReader,
context_builder: &mut CommandContextBuilder<S>,
- ) -> Result<(), CommandSyntaxException> {
+ ) -> Result<(), CommandSyntaxError> {
match self.value {
ArgumentBuilderType::Argument(ref argument) => {
let start = reader.cursor();
@@ -176,7 +177,7 @@ impl<S> CommandNode<S> {
return Ok(());
}
- Err(BuiltInExceptions::LiteralIncorrect {
+ Err(BuiltInError::LiteralIncorrect {
expected: literal.value.clone(),
}
.create_with_context(reader))