diff options
Diffstat (limited to 'azalea-brigadier/src/errors')
| -rw-r--r-- | azalea-brigadier/src/errors/builtin_errors.rs | 153 | ||||
| -rw-r--r-- | azalea-brigadier/src/errors/command_syntax_error.rs | 93 | ||||
| -rw-r--r-- | azalea-brigadier/src/errors/mod.rs | 5 |
3 files changed, 251 insertions, 0 deletions
diff --git a/azalea-brigadier/src/errors/builtin_errors.rs b/azalea-brigadier/src/errors/builtin_errors.rs new file mode 100644 index 00000000..36803397 --- /dev/null +++ b/azalea-brigadier/src/errors/builtin_errors.rs @@ -0,0 +1,153 @@ +use std::fmt; + +use super::command_syntax_error::CommandSyntaxError; +use crate::string_reader::StringReader; + +#[derive(Clone, PartialEq)] +pub enum BuiltInError { + DoubleTooSmall { found: f64, min: f64 }, + DoubleTooBig { found: f64, max: f64 }, + + FloatTooSmall { found: f32, min: f32 }, + FloatTooBig { found: f32, max: f32 }, + + IntegerTooSmall { found: i32, min: i32 }, + IntegerTooBig { found: i32, max: i32 }, + + LongTooSmall { found: i64, min: i64 }, + LongTooBig { found: i64, max: i64 }, + + LiteralIncorrect { expected: String }, + + ReaderExpectedStartOfQuote, + ReaderExpectedEndOfQuote, + ReaderInvalidEscape { character: char }, + ReaderInvalidBool { value: String }, + ReaderInvalidInt { value: String }, + ReaderExpectedInt, + ReaderInvalidLong { value: String }, + ReaderExpectedLong, + ReaderInvalidDouble { value: String }, + ReaderExpectedDouble, + ReaderInvalidFloat { value: String }, + ReaderExpectedFloat, + ReaderExpectedBool, + ReaderExpectedSymbol { symbol: char }, + + DispatcherUnknownCommand, + DispatcherUnknownArgument, + DispatcherExpectedArgumentSeparator, + DispatcherParseException { message: String }, +} + +impl fmt::Debug for BuiltInError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + BuiltInError::DoubleTooSmall { found, min } => { + write!(f, "Double must not be less than {min}, found {found}") + } + BuiltInError::DoubleTooBig { found, max } => { + write!(f, "Double must not be more than {max}, found {found}") + } + + BuiltInError::FloatTooSmall { found, min } => { + write!(f, "Float must not be less than {min}, found {found}") + } + BuiltInError::FloatTooBig { found, max } => { + write!(f, "Float must not be more than {max}, found {found}") + } + + BuiltInError::IntegerTooSmall { found, min } => { + write!(f, "Integer must not be less than {min}, found {found}") + } + BuiltInError::IntegerTooBig { found, max } => { + write!(f, "Integer must not be more than {max}, found {found}") + } + + BuiltInError::LongTooSmall { found, min } => { + write!(f, "Long must not be less than {min}, found {found}") + } + BuiltInError::LongTooBig { found, max } => { + write!(f, "Long must not be more than {max}, found {found}") + } + + BuiltInError::LiteralIncorrect { expected } => { + write!(f, "Expected literal {expected}") + } + + BuiltInError::ReaderExpectedStartOfQuote => { + write!(f, "Expected quote to start a string") + } + BuiltInError::ReaderExpectedEndOfQuote => { + write!(f, "Unclosed quoted string") + } + BuiltInError::ReaderInvalidEscape { character } => { + write!(f, "Invalid escape sequence '{character}' in quoted string") + } + BuiltInError::ReaderInvalidBool { value } => { + write!( + f, + "Invalid bool, expected true or false but found '{value}'" + ) + } + BuiltInError::ReaderInvalidInt { value } => { + write!(f, "Invalid Integer '{value}'") + } + BuiltInError::ReaderExpectedInt => { + write!(f, "Expected Integer") + } + BuiltInError::ReaderInvalidLong { value } => { + write!(f, "Invalid long '{value}'") + } + BuiltInError::ReaderExpectedLong => { + write!(f, "Expected long") + } + BuiltInError::ReaderInvalidDouble { value } => { + write!(f, "Invalid double '{value}'") + } + BuiltInError::ReaderExpectedDouble => { + write!(f, "Expected double") + } + BuiltInError::ReaderInvalidFloat { value } => { + write!(f, "Invalid Float '{value}'") + } + BuiltInError::ReaderExpectedFloat => { + write!(f, "Expected Float") + } + BuiltInError::ReaderExpectedBool => { + write!(f, "Expected bool") + } + BuiltInError::ReaderExpectedSymbol { symbol } => { + write!(f, "Expected '{symbol}'") + } + + BuiltInError::DispatcherUnknownCommand => { + write!(f, "Unknown command") + } + BuiltInError::DispatcherUnknownArgument => { + write!(f, "Incorrect argument for command") + } + BuiltInError::DispatcherExpectedArgumentSeparator => { + write!( + f, + "Expected whitespace to end one argument, but found trailing data" + ) + } + BuiltInError::DispatcherParseException { message } => { + write!(f, "Could not parse command: {message}") + } + } + } +} + +impl BuiltInError { + pub fn create(self) -> CommandSyntaxError { + let message = format!("{self:?}"); + CommandSyntaxError::create(self, message) + } + + pub fn create_with_context(self, reader: &StringReader) -> CommandSyntaxError { + let message = format!("{self:?}"); + CommandSyntaxError::new(self, message, reader.string(), reader.cursor()) + } +} diff --git a/azalea-brigadier/src/errors/command_syntax_error.rs b/azalea-brigadier/src/errors/command_syntax_error.rs new file mode 100644 index 00000000..a476fec4 --- /dev/null +++ b/azalea-brigadier/src/errors/command_syntax_error.rs @@ -0,0 +1,93 @@ +use std::{ + cmp, + fmt::{self, Debug, Write}, +}; + +use super::builtin_errors::BuiltInError; + +#[derive(Clone, PartialEq)] +pub struct CommandSyntaxError { + kind: BuiltInError, + message: String, + input: Option<String>, + cursor: Option<usize>, +} + +const CONTEXT_AMOUNT: usize = 10; + +impl CommandSyntaxError { + pub fn new(kind: BuiltInError, message: String, input: &str, cursor: usize) -> Self { + Self { + kind, + message, + input: Some(input.to_string()), + cursor: Some(cursor), + } + } + + pub fn create(kind: BuiltInError, message: String) -> Self { + Self { + kind, + message, + input: None, + cursor: None, + } + } + + pub fn message(&self) -> String { + let mut message = self.message.clone(); + let context = self.context(); + if let Some(context) = context { + write!( + message, + " at position {}: {context}", + self.cursor.unwrap_or(usize::MAX) + ) + .unwrap(); + } + message + } + + pub fn raw_message(&self) -> &String { + &self.message + } + + pub fn context(&self) -> Option<String> { + if let Some(input) = &self.input + && let Some(cursor) = self.cursor + { + let mut builder = String::new(); + let cursor = cmp::min(input.len(), cursor); + + if cursor > CONTEXT_AMOUNT { + builder.push_str("..."); + } + + builder.push_str( + &input[(cmp::max(0, cursor as isize - CONTEXT_AMOUNT as isize) as usize)..cursor], + ); + builder.push_str("<--[HERE]"); + + return Some(builder); + } + None + } + + pub fn kind(&self) -> &BuiltInError { + &self.kind + } + + pub fn input(&self) -> &Option<String> { + &self.input + } + + pub fn cursor(&self) -> Option<usize> { + self.cursor + } +} + +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; |
