aboutsummaryrefslogtreecommitdiff
path: root/azalea-brigadier/src
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-01-09 14:50:41 -0600
committermat <github@matdoes.dev>2022-01-09 14:50:41 -0600
commit8331851d972b42b68e1fb64e2ec9faef6c02be32 (patch)
tree35f8a0c9175a10f626835f7930660ef7e7415acf /azalea-brigadier/src
parentd959fb2d0cc4d8ad97eae86666876e22b2e50613 (diff)
downloadazalea-drasl-8331851d972b42b68e1fb64e2ec9faef6c02be32.tar.xz
string reader
Diffstat (limited to 'azalea-brigadier/src')
-rw-r--r--azalea-brigadier/src/arguments/argument_type.rs11
-rw-r--r--azalea-brigadier/src/arguments/mod.rs2
-rw-r--r--azalea-brigadier/src/context/command_context.rs3
-rw-r--r--azalea-brigadier/src/context/mod.rs6
-rw-r--r--azalea-brigadier/src/exceptions/builtin_exceptions.rs158
-rw-r--r--azalea-brigadier/src/exceptions/command_exception_type.rs0
-rw-r--r--azalea-brigadier/src/exceptions/command_syntax_exception.rs82
-rw-r--r--azalea-brigadier/src/exceptions/dynamic2_command_exception_type.rs0
-rw-r--r--azalea-brigadier/src/exceptions/dynamic3_command_exception_type.rs0
-rw-r--r--azalea-brigadier/src/exceptions/dynamic4_command_exception_type.rs0
-rw-r--r--azalea-brigadier/src/exceptions/dynamicN_command_exception_type.rs0
-rw-r--r--azalea-brigadier/src/exceptions/dynamic_command_exception_type.rs0
-rw-r--r--azalea-brigadier/src/exceptions/mod.rs3
-rw-r--r--azalea-brigadier/src/exceptions/simple_command_exception_type.rs0
-rw-r--r--azalea-brigadier/src/immutable_string_reader.rs2
-rw-r--r--azalea-brigadier/src/message.rs14
-rw-r--r--azalea-brigadier/src/string_reader.rs341
-rw-r--r--azalea-brigadier/src/suggestion/mod.rs5
-rw-r--r--azalea-brigadier/src/suggestion/suggestions.rs1
-rw-r--r--azalea-brigadier/src/suggestion/suggestions_builder.rs1
20 files changed, 529 insertions, 100 deletions
diff --git a/azalea-brigadier/src/arguments/argument_type.rs b/azalea-brigadier/src/arguments/argument_type.rs
index 4dc97ee0..4c48d6bb 100644
--- a/azalea-brigadier/src/arguments/argument_type.rs
+++ b/azalea-brigadier/src/arguments/argument_type.rs
@@ -1,3 +1,10 @@
+use crate::{
+ context::command_context::CommandContext,
+ exceptions::command_syntax_exception::CommandSyntaxException,
+ string_reader::StringReader,
+ suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder},
+};
+
pub trait ArgumentType<T> {
// T parse(StringReader reader) throws CommandSyntaxException;
@@ -9,12 +16,12 @@ pub trait ArgumentType<T> {
// return Collections.emptyList();
// }
- fn parse(reader: &mut StringReader) -> Result<T, CommandSyntaxError>;
+ fn parse(reader: &mut StringReader) -> Result<T, CommandSyntaxException>;
fn list_suggestions<S>(
context: &CommandContext<S>,
builder: &mut SuggestionsBuilder,
- ) -> Result<Suggestions, CommandSyntaxError>;
+ ) -> Result<Suggestions, CommandSyntaxException>;
fn get_examples() -> Vec<String>;
}
diff --git a/azalea-brigadier/src/arguments/mod.rs b/azalea-brigadier/src/arguments/mod.rs
index 18d01d88..50b0f09b 100644
--- a/azalea-brigadier/src/arguments/mod.rs
+++ b/azalea-brigadier/src/arguments/mod.rs
@@ -1 +1 @@
-mod argument_type;
+pub mod argument_type;
diff --git a/azalea-brigadier/src/context/command_context.rs b/azalea-brigadier/src/context/command_context.rs
index e69de29b..ddbb447e 100644
--- a/azalea-brigadier/src/context/command_context.rs
+++ b/azalea-brigadier/src/context/command_context.rs
@@ -0,0 +1,3 @@
+pub struct CommandContext<S> {
+ source: S,
+}
diff --git a/azalea-brigadier/src/context/mod.rs b/azalea-brigadier/src/context/mod.rs
index e69de29b..196d7c5b 100644
--- a/azalea-brigadier/src/context/mod.rs
+++ b/azalea-brigadier/src/context/mod.rs
@@ -0,0 +1,6 @@
+pub mod command_context;
+pub mod command_context_builder;
+pub mod parsed_argument;
+pub mod parsed_command_node;
+pub mod string_range;
+pub mod suggestion_context;
diff --git a/azalea-brigadier/src/exceptions/builtin_exceptions.rs b/azalea-brigadier/src/exceptions/builtin_exceptions.rs
index e69de29b..fcca49cd 100644
--- a/azalea-brigadier/src/exceptions/builtin_exceptions.rs
+++ b/azalea-brigadier/src/exceptions/builtin_exceptions.rs
@@ -0,0 +1,158 @@
+use std::fmt;
+
+use crate::{immutable_string_reader::ImmutableStringReader, message::Message};
+
+use super::command_syntax_exception::CommandSyntaxException;
+
+pub enum BuiltInExceptions {
+ DoubleTooSmall { found: usize, min: usize },
+ DoubleTooBig { found: usize, max: usize },
+
+ FloatTooSmall { found: usize, min: usize },
+ FloatTooBig { found: usize, max: usize },
+
+ IntegerTooSmall { found: usize, min: usize },
+ IntegerTooBig { found: usize, max: usize },
+
+ LONGTooSmall { found: usize, min: usize },
+ LONGTooBig { found: usize, max: usize },
+
+ 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 },
+
+ ReaderUnknownCommand,
+ ReaderUnknownArgument,
+ DusoatcgerExpectedArgumentSeparator,
+ DispatcherParseException { message: String },
+}
+
+impl fmt::Debug for BuiltInExceptions {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ BuiltInExceptions::DoubleTooSmall { found, min } => {
+ write!(f, "Double must not be less than {}, found {}", min, found)
+ }
+ BuiltInExceptions::DoubleTooBig { found, max } => {
+ write!(f, "Double must not be more than {}, found {}", max, found)
+ }
+
+ BuiltInExceptions::FloatTooSmall { found, min } => {
+ write!(f, "Float must not be less than {}, found {}", min, found)
+ }
+ BuiltInExceptions::FloatTooBig { found, max } => {
+ write!(f, "Float must not be more than {}, found {}", max, found)
+ }
+
+ BuiltInExceptions::IntegerTooSmall { found, min } => {
+ write!(f, "Integer must not be less than {}, found {}", min, found)
+ }
+ BuiltInExceptions::IntegerTooBig { found, max } => {
+ write!(f, "Integer must not be more than {}, found {}", max, found)
+ }
+
+ BuiltInExceptions::LONGTooSmall { found, min } => {
+ write!(f, "Long must not be less than {}, found {}", min, found)
+ }
+ BuiltInExceptions::LONGTooBig { found, max } => {
+ write!(f, "Long must not be more than {}, found {}", max, found)
+ }
+
+ BuiltInExceptions::LiteralIncorrect { expected } => {
+ write!(f, "Expected literal {}", expected)
+ }
+
+ BuiltInExceptions::ReaderExpectedStartOfQuote => {
+ write!(f, "Expected quote to start a string")
+ }
+ BuiltInExceptions::ReaderExpectedEndOfQuote => {
+ write!(f, "Unclosed quoted string")
+ }
+ BuiltInExceptions::ReaderInvalidEscape { character } => {
+ write!(
+ f,
+ "Invalid escape sequence '{}' in quoted string",
+ character
+ )
+ }
+ BuiltInExceptions::ReaderInvalidBool { value } => {
+ write!(
+ f,
+ "Invalid bool, expected true or false but found '{}'",
+ value
+ )
+ }
+ BuiltInExceptions::ReaderInvalidInt { value } => {
+ write!(f, "Invalid Integer '{}'", value)
+ }
+ BuiltInExceptions::ReaderExpectedInt => {
+ write!(f, "Expected Integer")
+ }
+ BuiltInExceptions::ReaderInvalidLong { value } => {
+ write!(f, "Invalid long '{}'", value)
+ }
+ BuiltInExceptions::ReaderExpectedLong => {
+ write!(f, "Expected long")
+ }
+ BuiltInExceptions::ReaderInvalidDouble { value } => {
+ write!(f, "Invalid double '{}'", value)
+ }
+ BuiltInExceptions::ReaderExpectedDouble => {
+ write!(f, "Expected double")
+ }
+ BuiltInExceptions::ReaderInvalidFloat { value } => {
+ write!(f, "Invalid Float '{}'", value)
+ }
+ BuiltInExceptions::ReaderExpectedFloat => {
+ write!(f, "Expected Float")
+ }
+ BuiltInExceptions::ReaderExpectedBool => {
+ write!(f, "Expected bool")
+ }
+ BuiltInExceptions::ReaderExpectedSymbol { symbol } => {
+ write!(f, "Expected '{}'", symbol)
+ }
+
+ BuiltInExceptions::ReaderUnknownCommand => {
+ write!(f, "Unknown command")
+ }
+ BuiltInExceptions::ReaderUnknownArgument => {
+ write!(f, "Incorrect argument for command")
+ }
+ BuiltInExceptions::DusoatcgerExpectedArgumentSeparator => {
+ write!(
+ f,
+ "Expected whitespace to end one argument, but found trailing data"
+ )
+ }
+ BuiltInExceptions::DispatcherParseException { message } => {
+ write!(f, "Could not parse command: {}", message)
+ }
+ }
+ }
+}
+
+impl BuiltInExceptions {
+ pub fn create(self) -> CommandSyntaxException {
+ let message = Message::from(format!("{:?}", self));
+ CommandSyntaxException::create(self, message)
+ }
+
+ pub fn create_with_context(self, reader: &dyn ImmutableStringReader) -> CommandSyntaxException {
+ let message = Message::from(format!("{:?}", self));
+ CommandSyntaxException::new(self, message, reader.string(), reader.cursor())
+ }
+}
diff --git a/azalea-brigadier/src/exceptions/command_exception_type.rs b/azalea-brigadier/src/exceptions/command_exception_type.rs
deleted file mode 100644
index e69de29b..00000000
--- a/azalea-brigadier/src/exceptions/command_exception_type.rs
+++ /dev/null
diff --git a/azalea-brigadier/src/exceptions/command_syntax_exception.rs b/azalea-brigadier/src/exceptions/command_syntax_exception.rs
index e69de29b..b9fbea45 100644
--- a/azalea-brigadier/src/exceptions/command_syntax_exception.rs
+++ b/azalea-brigadier/src/exceptions/command_syntax_exception.rs
@@ -0,0 +1,82 @@
+use std::{cmp, rc::Rc};
+
+use super::builtin_exceptions::BuiltInExceptions;
+use crate::message::Message;
+
+pub struct CommandSyntaxException {
+ type_: BuiltInExceptions,
+ message: Message,
+ input: Option<String>,
+ cursor: Option<usize>,
+}
+
+const CONTEXT_AMOUNT: usize = 10;
+const ENABLE_COMMAND_STACK_TRACES: bool = true;
+
+impl CommandSyntaxException {
+ pub fn new(type_: BuiltInExceptions, message: Message, input: &str, cursor: usize) -> Self {
+ Self {
+ type_,
+ message,
+ input: Some(input.to_string()),
+ cursor: Some(cursor),
+ }
+ }
+
+ pub fn create(type_: BuiltInExceptions, message: Message) -> Self {
+ Self {
+ type_,
+ message,
+ input: None,
+ cursor: None,
+ }
+ }
+
+ pub fn message(&self) -> String {
+ let mut message = self.message.string();
+ let context = self.context();
+ if let Some(context) = context {
+ message.push_str(&format!(
+ " at position {}: {}",
+ self.cursor.unwrap_or(usize::MAX),
+ context
+ ));
+ }
+ message
+ }
+
+ pub fn raw_message(&self) -> &Message {
+ &self.message
+ }
+
+ pub fn context(&self) -> Option<String> {
+ if let Some(input) = &self.input {
+ if 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 - CONTEXT_AMOUNT)..cursor]);
+ builder.push_str("<--[HERE]");
+
+ return Some(builder);
+ }
+ }
+ None
+ }
+
+ pub fn get_type(&self) -> &BuiltInExceptions {
+ &self.type_
+ }
+
+ pub fn input(&self) -> String {
+ self.input()
+ }
+
+ pub fn cursor(&self) -> Option<usize> {
+ self.cursor
+ }
+}
diff --git a/azalea-brigadier/src/exceptions/dynamic2_command_exception_type.rs b/azalea-brigadier/src/exceptions/dynamic2_command_exception_type.rs
deleted file mode 100644
index e69de29b..00000000
--- a/azalea-brigadier/src/exceptions/dynamic2_command_exception_type.rs
+++ /dev/null
diff --git a/azalea-brigadier/src/exceptions/dynamic3_command_exception_type.rs b/azalea-brigadier/src/exceptions/dynamic3_command_exception_type.rs
deleted file mode 100644
index e69de29b..00000000
--- a/azalea-brigadier/src/exceptions/dynamic3_command_exception_type.rs
+++ /dev/null
diff --git a/azalea-brigadier/src/exceptions/dynamic4_command_exception_type.rs b/azalea-brigadier/src/exceptions/dynamic4_command_exception_type.rs
deleted file mode 100644
index e69de29b..00000000
--- a/azalea-brigadier/src/exceptions/dynamic4_command_exception_type.rs
+++ /dev/null
diff --git a/azalea-brigadier/src/exceptions/dynamicN_command_exception_type.rs b/azalea-brigadier/src/exceptions/dynamicN_command_exception_type.rs
deleted file mode 100644
index e69de29b..00000000
--- a/azalea-brigadier/src/exceptions/dynamicN_command_exception_type.rs
+++ /dev/null
diff --git a/azalea-brigadier/src/exceptions/dynamic_command_exception_type.rs b/azalea-brigadier/src/exceptions/dynamic_command_exception_type.rs
deleted file mode 100644
index e69de29b..00000000
--- a/azalea-brigadier/src/exceptions/dynamic_command_exception_type.rs
+++ /dev/null
diff --git a/azalea-brigadier/src/exceptions/mod.rs b/azalea-brigadier/src/exceptions/mod.rs
index e69de29b..4a82b01e 100644
--- a/azalea-brigadier/src/exceptions/mod.rs
+++ b/azalea-brigadier/src/exceptions/mod.rs
@@ -0,0 +1,3 @@
+pub mod builtin_exception_provider;
+pub mod builtin_exceptions;
+pub mod command_syntax_exception;
diff --git a/azalea-brigadier/src/exceptions/simple_command_exception_type.rs b/azalea-brigadier/src/exceptions/simple_command_exception_type.rs
deleted file mode 100644
index e69de29b..00000000
--- a/azalea-brigadier/src/exceptions/simple_command_exception_type.rs
+++ /dev/null
diff --git a/azalea-brigadier/src/immutable_string_reader.rs b/azalea-brigadier/src/immutable_string_reader.rs
index 2e067ace..53531c64 100644
--- a/azalea-brigadier/src/immutable_string_reader.rs
+++ b/azalea-brigadier/src/immutable_string_reader.rs
@@ -1,6 +1,8 @@
pub trait ImmutableStringReader {
+ fn string(&self) -> &str;
fn remaining_length(&self) -> usize;
fn total_length(&self) -> usize;
+ fn cursor(&self) -> usize;
fn get_read(&self) -> &str;
fn remaining(&self) -> &str;
fn can_read_length(&self, length: usize) -> bool;
diff --git a/azalea-brigadier/src/message.rs b/azalea-brigadier/src/message.rs
index 8b137891..71d0b178 100644
--- a/azalea-brigadier/src/message.rs
+++ b/azalea-brigadier/src/message.rs
@@ -1 +1,15 @@
+use std::rc::Rc;
+pub struct Message(Rc<String>);
+
+impl Message {
+ pub fn string(&self) -> String {
+ self.0.to_string()
+ }
+}
+
+impl From<String> for Message {
+ fn from(s: String) -> Self {
+ Self(Rc::new(s))
+ }
+}
diff --git a/azalea-brigadier/src/string_reader.rs b/azalea-brigadier/src/string_reader.rs
index 376cc711..1119403a 100644
--- a/azalea-brigadier/src/string_reader.rs
+++ b/azalea-brigadier/src/string_reader.rs
@@ -1,23 +1,34 @@
-use crate::immutable_string_reader::ImmutableStringReader;
+use crate::{
+ exceptions::{
+ builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException,
+ },
+ immutable_string_reader::ImmutableStringReader,
+};
use std::str::FromStr;
#[derive(Clone)]
-struct StringReader<'a> {
- pub string: &'a str,
- pub cursor: usize,
+pub struct StringReader<'a> {
+ string: &'a str,
+ cursor: usize,
}
const SYNTAX_ESCAPE: char = '\\';
const SYNTAX_DOUBLE_QUOTE: char = '"';
const SYNTAX_SINGLE_QUOTE: char = '\'';
-impl<'a> From<&'a str> for &StringReader<'a> {
- fn from(string: &'a str) -> &StringReader<'a> {
- &StringReader { string, cursor: 0 }
+// impl<'a> From<&'a str> for &StringReader<'a> {}
+
+impl StringReader<'_> {
+ fn from(string: &str) -> StringReader {
+ StringReader { string, cursor: 0 }
}
}
impl ImmutableStringReader for StringReader<'_> {
+ fn string(&self) -> &str {
+ self.string
+ }
+
fn remaining_length(&self) -> usize {
self.string.len() - self.cursor
}
@@ -27,7 +38,7 @@ impl ImmutableStringReader for StringReader<'_> {
}
fn get_read(&self) -> &str {
- &self.string[self.cursor..]
+ &self.string[..self.cursor]
}
fn remaining(&self) -> &str {
@@ -49,122 +60,122 @@ impl ImmutableStringReader for StringReader<'_> {
fn peek_offset(&self, offset: usize) -> char {
self.string.chars().nth(self.cursor + offset).unwrap()
}
+
+ fn cursor(&self) -> usize {
+ self.cursor
+ }
}
impl StringReader<'_> {
- fn read(&mut self) -> char {
+ pub fn read(&mut self) -> char {
let c = self.peek();
self.cursor += 1;
c
}
- fn skip(&mut self) {
+ pub fn skip(&mut self) {
self.cursor += 1;
}
- fn is_allowed_number(c: char) -> bool {
+ pub fn is_allowed_number(c: char) -> bool {
c >= '0' && c <= '9' || c == '.' || c == '-'
}
- fn is_quoted_string_start(c: char) -> bool {
+ pub fn is_quoted_string_start(c: char) -> bool {
c == SYNTAX_DOUBLE_QUOTE || c == SYNTAX_SINGLE_QUOTE
}
- fn skip_whitespace(&mut self) {
+ pub fn skip_whitespace(&mut self) {
while self.can_read() && self.peek().is_whitespace() {
self.skip();
}
}
- fn read_int(&self) -> Result<(), CommandSyntaxException> {
+ pub fn read_int(&mut self) -> Result<(), CommandSyntaxException> {
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(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_expected_int()
- .create_with_context(self));
+ return Err(BuiltInExceptions::ReaderExpectedInt.create_with_context(self));
}
let result = i32::from_str(number);
if result.is_err() {
self.cursor = start;
- return Err(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_invalid_int()
- .create_with_context(self, number));
+ return Err(BuiltInExceptions::ReaderInvalidInt {
+ value: number.to_string(),
+ }
+ .create_with_context(self));
}
Ok(())
}
- fn read_long(&self) -> Result<(), CommandSyntaxException> {
+ pub fn read_long(&mut self) -> Result<(), CommandSyntaxException> {
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(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_expected_long()
- .create_with_context(self));
+ return Err(BuiltInExceptions::ReaderExpectedLong.create_with_context(self));
}
let result = i64::from_str(number);
if result.is_err() {
self.cursor = start;
- return Err(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_invalid_long()
- .create_with_context(self, number));
+ return Err(BuiltInExceptions::ReaderInvalidLong {
+ value: number.to_string(),
+ }
+ .create_with_context(self));
}
Ok(())
}
- fn read_double(&self) -> Result<(), CommandSyntaxException> {
+ pub fn read_double(&mut self) -> Result<(), CommandSyntaxException> {
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(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_expected_double()
- .create_with_context(self));
+ return Err(BuiltInExceptions::ReaderExpectedDouble.create_with_context(self));
}
let result = f64::from_str(number);
if result.is_err() {
self.cursor = start;
- return Err(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_invalid_double()
- .create_with_context(self, number));
+ return Err(BuiltInExceptions::ReaderInvalidDouble {
+ value: number.to_string(),
+ }
+ .create_with_context(self));
}
Ok(())
}
- fn read_float(&self) -> Result<(), CommandSyntaxException> {
+ pub fn read_float(&mut self) -> Result<(), CommandSyntaxException> {
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(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_expected_float()
- .create_with_context(self));
+ return Err(BuiltInExceptions::ReaderExpectedFloat.create_with_context(self));
}
let result = f32::from_str(number);
if result.is_err() {
self.cursor = start;
- return Err(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_invalid_float()
- .create_with_context(self, number));
+ return Err(BuiltInExceptions::ReaderInvalidFloat {
+ value: number.to_string(),
+ }
+ .create_with_context(self));
}
Ok(())
}
- fn is_allowed_in_unquoted_string(c: char) -> bool {
+ pub fn is_allowed_in_unquoted_string(c: char) -> bool {
c >= '0' && c <= '9'
|| c >= 'A' && c <= 'Z'
|| c >= 'a' && c <= 'z'
@@ -174,7 +185,7 @@ impl StringReader<'_> {
|| c == '+'
}
- fn read_unquoted_string(&self) -> &str {
+ pub fn read_unquoted_string(&mut self) -> &str {
let start = self.cursor;
while self.can_read() && StringReader::<'_>::is_allowed_in_unquoted_string(self.peek()) {
self.skip();
@@ -182,22 +193,23 @@ impl StringReader<'_> {
&self.string[start..self.cursor]
}
- fn read_quoted_string(&self) -> Result<&str, CommandSyntaxException> {
+ pub fn read_quoted_string(&mut self) -> Result<String, CommandSyntaxException> {
if !self.can_read() {
- return "";
+ return Ok(String::new());
}
let next = self.peek();
if !StringReader::<'_>::is_quoted_string_start(next) {
- return Err(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_expected_start_of_quote()
- .create_with_context(self));
+ return Err(BuiltInExceptions::ReaderExpectedStartOfQuote.create_with_context(self));
}
self.skip();
self.read_string_until(next)
}
- fn read_string_until(&self, terminator: char) -> Result<String, CommandSynatxException> {
- let result = String::new();
+ pub fn read_string_until(
+ &mut self,
+ terminator: char,
+ ) -> Result<String, CommandSyntaxException> {
+ let mut result = String::new();
let mut escaped = false;
while self.can_read() {
let c = self.read();
@@ -207,9 +219,8 @@ impl StringReader<'_> {
escaped = false;
} else {
self.cursor -= 1;
- return Err(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_invalid_escape()
- .create_with_context(self, c));
+ return Err(BuiltInExceptions::ReaderInvalidEscape { character: c }
+ .create_with_context(self));
}
} else if c == SYNTAX_ESCAPE {
escaped = true;
@@ -220,21 +231,10 @@ impl StringReader<'_> {
}
}
- Err(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_expected_end_of_quote()
- .create_with_context(self))
- }
-
- fn read_string(&self) -> Result<String, CommandSyntaxException> {
- // if (!canRead()) {
- // return "";
- // }
- // final char next = peek();
- // if (isQuotedStringStart(next)) {
- // skip();
- // return readStringUntil(next);
- // }
- // return readUnquotedString();
+ return Err(BuiltInExceptions::ReaderExpectedEndOfQuote.create_with_context(self));
+ }
+
+ pub fn read_string(&mut self) -> Result<String, CommandSyntaxException> {
if !self.can_read() {
return Ok(String::new());
}
@@ -246,32 +246,179 @@ impl StringReader<'_> {
Ok(self.read_unquoted_string().to_string())
}
- fn read_boolean(&self) -> Result<bool, CommandSyntaxException> {
- let start = self.cursor;
- let value = self.read_string()?;
- if value.is_empty() {
- return Err(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_expected_bool()
- .create_with_context(self));
- }
-
- if value == "true" {
- return Ok(true);
- } else if value == "false" {
- return Ok(false);
- } else {
- self.cursor = start;
- return Err(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_invalid_bool()
- .create_with_context(self, value));
- }
- }
-
- fn expect(&self, c: char) -> Result<(), CommandSyntaxException> {
- if !self.can_read() || self.peek() != c {
- return Err(CommandSyntaxException::BUILT_IN_EXCEPTIONS
- .reader_expected_symbol()
- .create_with_context(self, c));
- }
- self.skip();
- }
+ pub fn read_boolean(&mut self) -> Result<bool, CommandSyntaxException> {
+ let start = self.cursor;
+ let value = self.read_string()?;
+ if value.is_empty() {
+ return Err(BuiltInExceptions::ReaderExpectedBool.create_with_context(self));
+ }
+
+ if value == "true" {
+ return Ok(true);
+ } else if value == "false" {
+ return Ok(false);
+ } else {
+ self.cursor = start;
+ return Err(BuiltInExceptions::ReaderInvalidBool { value }.create_with_context(self));
+ }
+ }
+
+ pub fn expect(&mut self, c: char) -> Result<(), CommandSyntaxException> {
+ if !self.can_read() || self.peek() != c {
+ return Err(
+ BuiltInExceptions::ReaderExpectedSymbol { symbol: c }.create_with_context(self)
+ );
+ }
+ self.skip();
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn can_read() {
+ let mut reader = StringReader::from("abc");
+ assert_eq!(reader.can_read(), true);
+ reader.skip(); // 'a'
+ assert_eq!(reader.can_read(), true);
+ reader.skip(); // 'b'
+ assert_eq!(reader.can_read(), true);
+ reader.skip(); // 'c'
+ assert_eq!(reader.can_read(), false);
+ }
+
+ #[test]
+ fn get_remaining_length() {
+ let mut reader = StringReader::from("abc");
+ assert_eq!(reader.remaining_length(), 3);
+ reader.cursor = 1;
+ assert_eq!(reader.remaining_length(), 2);
+ reader.cursor = 2;
+ assert_eq!(reader.remaining_length(), 1);
+ reader.cursor = 3;
+ assert_eq!(reader.remaining_length(), 0);
+ }
+
+ #[test]
+ fn can_read_length() {
+ let reader = StringReader::from("abc");
+ assert_eq!(reader.can_read_length(1), true);
+ assert_eq!(reader.can_read_length(2), true);
+ assert_eq!(reader.can_read_length(3), true);
+ assert_eq!(reader.can_read_length(4), false);
+ assert_eq!(reader.can_read_length(5), false);
+ }
+
+ #[test]
+ fn peek() {
+ let mut reader = StringReader::from("abc");
+ assert_eq!(reader.peek(), 'a');
+ assert_eq!(reader.cursor(), 0);
+ reader.cursor = 2;
+ assert_eq!(reader.peek(), 'c');
+ assert_eq!(reader.cursor(), 2);
+ }
+
+ #[test]
+ fn peek_length() {
+ let mut reader = StringReader::from("abc");
+ assert_eq!(reader.peek_offset(0), 'a');
+ assert_eq!(reader.peek_offset(2), 'c');
+ assert_eq!(reader.cursor(), 0);
+ reader.cursor = 1;
+ assert_eq!(reader.peek_offset(1), 'c');
+ assert_eq!(reader.cursor(), 1);
+ }
+
+ #[test]
+ fn read() {
+ let mut reader = StringReader::from("abc");
+ assert_eq!(reader.read(), 'a');
+ assert_eq!(reader.read(), 'b');
+ assert_eq!(reader.read(), 'c');
+ assert_eq!(reader.cursor(), 3);
+ }
+
+ #[test]
+ fn skip() {
+ let mut reader = StringReader::from("abc");
+ reader.skip();
+ assert_eq!(reader.cursor(), 1);
+ }
+
+ #[test]
+ fn get_remaining() {
+ let mut reader = StringReader::from("Hello!");
+ assert_eq!(reader.remaining(), "Hello!");
+ reader.cursor = 3;
+ assert_eq!(reader.remaining(), "lo!");
+ reader.cursor = 6;
+ assert_eq!(reader.remaining(), "");
+ }
+
+ #[test]
+ fn get_read() {
+ let mut reader = StringReader::from("Hello!");
+ assert_eq!(reader.get_read(), "");
+ reader.cursor = 3;
+ assert_eq!(reader.get_read(), "Hel");
+ reader.cursor = 6;
+ assert_eq!(reader.get_read(), "Hello!");
+ }
+
+ #[test]
+ fn skip_whitespace_none() {
+ let mut reader = StringReader::from("Hello!");
+ reader.skip_whitespace();
+ assert_eq!(reader.cursor(), 0);
+ }
+
+ #[test]
+ fn skip_whitespace_mixed() {
+ let mut reader = StringReader::from(" \t \t\nHello!");
+ reader.skip_whitespace();
+ assert_eq!(reader.cursor(), 5);
+ }
+
+ #[test]
+ fn skip_whitespace_empty() {
+ let mut reader = StringReader::from("");
+ reader.skip_whitespace();
+ assert_eq!(reader.cursor(), 0);
+ }
+
+ #[test]
+ fn read_unquoted_string() {
+ let mut reader = StringReader::from("hello world");
+ assert_eq!(reader.read_unquoted_string(), "hello");
+ assert_eq!(reader.get_read(), "hello");
+ assert_eq!(reader.remaining(), "world");
+ }
+
+ #[test]
+ fn read_unquoted_string_empty() {
+ let mut reader = StringReader::from("");
+ assert_eq!(reader.read_unquoted_string(), "");
+ assert_eq!(reader.get_read(), "");
+ assert_eq!(reader.remaining(), "");
+ }
+
+ #[test]
+ fn read_unquoted_string_empty_with_remaining() {
+ let mut reader = StringReader::from(" hello world");
+ assert_eq!(reader.read_unquoted_string(), "");
+ assert_eq!(reader.get_read(), "");
+ assert_eq!(reader.remaining(), " hello world");
+ }
+
+ #[test]
+ fn read_quoted_string() {
+ let mut reader = StringReader::from("\"hello world\"");
+ assert_eq!(reader.read_unquoted_string(), "hello world");
+ assert_eq!(reader.get_read(), "\"hello world\"");
+ assert_eq!(reader.remaining(), "");
+ }
+}
diff --git a/azalea-brigadier/src/suggestion/mod.rs b/azalea-brigadier/src/suggestion/mod.rs
index e69de29b..050bae6c 100644
--- a/azalea-brigadier/src/suggestion/mod.rs
+++ b/azalea-brigadier/src/suggestion/mod.rs
@@ -0,0 +1,5 @@
+pub mod integer_suggestion;
+pub mod suggestion;
+pub mod suggestion_provider;
+pub mod suggestions;
+pub mod suggestions_builder;
diff --git a/azalea-brigadier/src/suggestion/suggestions.rs b/azalea-brigadier/src/suggestion/suggestions.rs
index e69de29b..354fc418 100644
--- a/azalea-brigadier/src/suggestion/suggestions.rs
+++ b/azalea-brigadier/src/suggestion/suggestions.rs
@@ -0,0 +1 @@
+pub struct Suggestions {}
diff --git a/azalea-brigadier/src/suggestion/suggestions_builder.rs b/azalea-brigadier/src/suggestion/suggestions_builder.rs
index e69de29b..6960f52b 100644
--- a/azalea-brigadier/src/suggestion/suggestions_builder.rs
+++ b/azalea-brigadier/src/suggestion/suggestions_builder.rs
@@ -0,0 +1 @@
+pub struct SuggestionsBuilder {}