diff options
| author | mat <github@matdoes.dev> | 2022-04-17 14:02:13 -0500 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2022-04-17 14:02:13 -0500 |
| commit | a72a47ced76065caf739898954cd18edbc39174b (patch) | |
| tree | 5526c7663f253bbd7c8318b9d98413f1f2074852 /azalea-brigadier/src/builder | |
| parent | 4ff67d4917ce333232189e86aee09f2d82451fc6 (diff) | |
| download | azalea-drasl-a72a47ced76065caf739898954cd18edbc39174b.tar.xz | |
Rewrite brigadier
Diffstat (limited to 'azalea-brigadier/src/builder')
3 files changed, 205 insertions, 225 deletions
diff --git a/azalea-brigadier/src/builder/argument_builder.rs b/azalea-brigadier/src/builder/argument_builder.rs index d0770be2..1fb775c2 100644 --- a/azalea-brigadier/src/builder/argument_builder.rs +++ b/azalea-brigadier/src/builder/argument_builder.rs @@ -1,137 +1,178 @@ -use crate::{ - arguments::argument_type::ArgumentType, - command::Command, - redirect_modifier::RedirectModifier, - single_redirect_modifier::SingleRedirectModifier, - tree::{ - command_node::{BaseCommandNode, CommandNodeTrait}, - root_command_node::RootCommandNode, - }, -}; -use std::fmt::Debug; - -pub struct BaseArgumentBuilder<'a, S> { - arguments: RootCommandNode<'a, S>, - command: Option<Box<dyn Command<S>>>, - requirement: Box<dyn Fn(&S) -> bool>, - target: Option<Box<dyn CommandNodeTrait<S>>>, - modifier: Option<Box<dyn RedirectModifier<S>>>, - forks: bool, +use crate::{context::CommandContext, modifier::RedirectModifier, tree::CommandNode}; + +use super::{literal_argument_builder::Literal, required_argument_builder::Argument}; +use std::{any::Any, cell::RefCell, collections::BTreeMap, fmt::Debug, rc::Rc}; + +#[derive(Debug, Clone)] +pub enum ArgumentBuilderType { + Literal(Literal), + Argument(Argument), } -pub trait ArgumentBuilder<S> { - fn build(self) -> Box<dyn CommandNodeTrait<S>>; +/// A node that hasn't yet been built. +#[derive(Clone)] +pub struct ArgumentBuilder<S: Any + Clone> { + value: ArgumentBuilderType, + + children: BTreeMap<String, Rc<RefCell<CommandNode<S>>>>, + literals: BTreeMap<String, Rc<RefCell<CommandNode<S>>>>, + arguments: BTreeMap<String, Rc<RefCell<CommandNode<S>>>>, + + executes: Option<Rc<dyn Fn(&CommandContext<S>) -> i32>>, + requirement: Rc<dyn Fn(Rc<S>) -> bool>, + forks: bool, + modifier: Option<Rc<dyn RedirectModifier<S>>>, } -impl<'a, S> BaseArgumentBuilder<'a, S> { - pub fn then(&mut self, argument: Box<dyn ArgumentBuilder<S>>) -> Result<&mut Self, String> { - if self.target.is_some() { - return Err("Cannot add children to a redirected node".to_string()); - } - self.arguments.add_child(argument.build()); - Ok(self) - } +// todo: maybe remake this to be based on a CommandNode like vanilla does? - pub fn arguments(&self) -> &Vec<&dyn CommandNodeTrait<S>> { - &self.arguments.get_children() +/// A node that isn't yet built. +impl<S: Any + Clone> ArgumentBuilder<S> { + pub fn new(value: ArgumentBuilderType) -> Self { + Self { + value, + children: BTreeMap::new(), + literals: BTreeMap::new(), + arguments: BTreeMap::new(), + executes: None, + requirement: Rc::new(|_| true), + forks: false, + modifier: None, + } } - pub fn executes(&mut self, command: Box<dyn Command<S>>) -> &mut Self { - self.command = Some(command); + pub fn then(&mut self, node: ArgumentBuilder<S>) -> &mut Self { + let built_node = node.build(); + let name = built_node.name(); + let node_reference = Rc::new(RefCell::new(built_node.clone())); + self.children + .insert(name.to_string(), node_reference.clone()); + match &built_node.value { + ArgumentBuilderType::Literal(literal) => { + self.literals.insert(name.to_string(), node_reference); + } + ArgumentBuilderType::Argument(argument) => { + self.arguments.insert(name.to_string(), node_reference); + } + } self } - pub fn command(&self) -> Option<Box<dyn Command<S>>> { - self.command + pub fn executes<F>(&mut self, f: F) -> Self + where + F: Fn(&CommandContext<S>) -> i32 + 'static, + { + self.executes = Some(Rc::new(f)); + self.clone() } - pub fn requires(&mut self, requirement: Box<dyn Fn(&S) -> bool>) -> &mut Self { - self.requirement = requirement; - self - } + pub fn build(self) -> CommandNode<S> { + println!("building {:?}", self); + CommandNode { + value: self.value, - pub fn requirement(&self) -> Box<dyn Fn(&S) -> bool> { - self.requirement - } + children: self.children, + literals: self.literals, + arguments: self.arguments, - pub fn redirect(&mut self, target: Box<dyn CommandNodeTrait<S>>) -> &mut Self { - self.forward(target, None, false) + command: self.executes.clone(), + requirement: self.requirement.clone(), + redirect: None, + forks: self.forks, + modifier: self.modifier, + } } +} - pub fn redirect_modifier( - &mut self, - target: &dyn CommandNodeTrait<S>, - modifier: &dyn SingleRedirectModifier<S>, - ) -> &mut Self { - // forward(target, modifier == null ? null : o -> Collections.singleton(modifier.apply(o)), false); - self.forward(target, modifier.map(|m| |o| vec![m.apply(o)]), false) +impl<S: Any + Clone> Debug for ArgumentBuilder<S> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ArgumentBuilder") + .field("value", &self.value) + .field("children", &self.children) + .field("literals", &self.literals) + .field("arguments", &self.arguments) + .field("executes", &self.executes.is_some()) + // .field("requirement", &self.requirement) + .field("forks", &self.forks) + // .field("modifier", &self.modifier) + .finish() } +} - pub fn fork( - &mut self, - target: &dyn CommandNodeTrait<S>, - modifier: &dyn RedirectModifier<S>, - ) -> &mut Self { - self.forward(target, Some(modifier), true) - } +#[cfg(test)] +mod tests { + use std::rc::Rc; - pub fn forward( - &mut self, - target: Option<Box<dyn CommandNodeTrait<S>>>, - modifier: Option<&dyn RedirectModifier<S>>, - fork: bool, - ) -> Result<&mut Self, String> { - if !self.arguments.get_children().is_empty() { - return Err("Cannot forward a node with children".to_string()); - } - self.target = target; - self.modifier = modifier; - self.forks = fork; - Ok(self) - } + use crate::{ + builder::{literal_argument_builder::literal, required_argument_builder::argument}, + parsers::integer, + }; - pub fn get_redirect(&self) -> Option<&dyn CommandNodeTrait<S>> { - self.target.as_ref() - } + use super::ArgumentBuilder; - pub fn get_redirect_modifier(&self) -> Option<&dyn RedirectModifier<S>> { - self.modifier.as_ref() - } + // public class ArgumentBuilderTest { + // private TestableArgumentBuilder<Object> builder; - pub fn is_fork(&self) -> bool { - self.forks - } + // @Before + // public void setUp() throws Exception { + // builder = new TestableArgumentBuilder<>(); + // } - pub fn build(self) -> BaseCommandNode<'a, S> { - let result: BaseCommandNode<'a, S> = BaseCommandNode { - command: self.command, - requirement: self.requirement, - redirect: self.target, - modifier: self.modifier, - forks: self.forks, + // @Test + // public void testArguments() throws Exception { + // final RequiredArgumentBuilder<Object, ?> argument = argument("bar", integer()); - arguments: Default::default(), - children: Default::default(), - literals: Default::default(), - }; + // builder.then(argument); - for argument in self.arguments() { - result.add_child(argument); - } + // assertThat(builder.getArguments(), hasSize(1)); + // assertThat(builder.getArguments(), hasItem((CommandNode<Object>) argument.build())); + // } - result - } -} + #[test] + fn test_arguments() { + let mut builder: ArgumentBuilder<()> = literal("foo"); -impl<S> Default for BaseArgumentBuilder<'_, S> { - fn default() -> Self { - Self { - arguments: Default::default(), - command: Default::default(), - requirement: Default::default(), - target: Default::default(), - modifier: Default::default(), - forks: Default::default(), - } + let argument: ArgumentBuilder<()> = argument("bar", integer()); + builder.then(argument.clone()); + assert_eq!(builder.children.len(), 1); + let built_argument = Rc::new(argument.build()); + assert!(builder + .children + .values() + .any(|e| *e.borrow() == *built_argument)); } + + // @Test + // public void testRedirect() throws Exception { + // final CommandNode<Object> target = mock(CommandNode.class); + // builder.redirect(target); + // assertThat(builder.getRedirect(), is(target)); + // } + + // @Test(expected = IllegalStateException.class) + // public void testRedirect_withChild() throws Exception { + // final CommandNode<Object> target = mock(CommandNode.class); + // builder.then(literal("foo")); + // builder.redirect(target); + // } + + // @Test(expected = IllegalStateException.class) + // public void testThen_withRedirect() throws Exception { + // final CommandNode<Object> target = mock(CommandNode.class); + // builder.redirect(target); + // builder.then(literal("foo")); + // } + + // private static class TestableArgumentBuilder<S> extends ArgumentBuilder<S, TestableArgumentBuilder<S>> { + // @Override + // protected TestableArgumentBuilder<S> getThis() { + // return this; + // } + + // @Override + // public CommandNode<S> build() { + // return null; + // } + // } + // } } diff --git a/azalea-brigadier/src/builder/literal_argument_builder.rs b/azalea-brigadier/src/builder/literal_argument_builder.rs index 4a95755c..d8898540 100644 --- a/azalea-brigadier/src/builder/literal_argument_builder.rs +++ b/azalea-brigadier/src/builder/literal_argument_builder.rs @@ -1,51 +1,35 @@ -use super::argument_builder::{ArgumentBuilder, BaseArgumentBuilder}; +use std::any::Any; + use crate::{ - arguments::argument_type::ArgumentType, - command::Command, - redirect_modifier::RedirectModifier, - tree::{ - command_node::CommandNodeTrait, literal_command_node::LiteralCommandNode, - root_command_node::RootCommandNode, + context::CommandContextBuilder, + exceptions::{ + builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException, }, + string_range::StringRange, + string_reader::StringReader, }; -use std::fmt::Debug; -pub struct LiteralArgumentBuilder<S> { - arguments: RootCommandNode<S>, - command: Option<Box<dyn Command<S>>>, - requirement: Box<dyn Fn(&S) -> bool>, - target: Option<Box<dyn CommandNodeTrait<S>>>, - modifier: Option<Box<dyn RedirectModifier<S>>>, - forks: bool, - literal: String, -} +use super::argument_builder::{ArgumentBuilder, ArgumentBuilderType}; -impl<S> LiteralArgumentBuilder<S> { - pub fn new(literal: String) -> Self { +#[derive(Debug, Clone, Default)] +pub struct Literal { + pub value: String, +} +impl Literal { + pub fn new(value: &str) -> Self { Self { - literal, - arguments: RootCommandNode::new(), - command: None, - requirement: Box::new(|_| true), - target: None, - modifier: None, - forks: false, + value: value.to_string(), } } +} - pub fn literal(name: String) -> Self { - Self::new(name) +impl From<Literal> for ArgumentBuilderType { + fn from(literal: Literal) -> Self { + Self::Literal(literal) } } -impl<S> ArgumentBuilder<S> for LiteralArgumentBuilder<S> { - fn build(self) -> Box<dyn CommandNodeTrait<S>> { - let result = LiteralCommandNode::new(self.literal, self.base.build()); - - for argument in self.base.arguments() { - result.add_child(argument); - } - - Box::new(result) - } +/// Shortcut for creating a new literal builder node. +pub fn literal<S: Any + Clone>(value: &str) -> ArgumentBuilder<S> { + ArgumentBuilder::new(ArgumentBuilderType::Literal(Literal::new(value))) } diff --git a/azalea-brigadier/src/builder/required_argument_builder.rs b/azalea-brigadier/src/builder/required_argument_builder.rs index fe6f2ecc..95f4da01 100644 --- a/azalea-brigadier/src/builder/required_argument_builder.rs +++ b/azalea-brigadier/src/builder/required_argument_builder.rs @@ -1,91 +1,46 @@ -use super::argument_builder::BaseArgumentBuilder; -use crate::{ - arguments::argument_type::ArgumentType, - command::Command, - redirect_modifier::RedirectModifier, - suggestion::suggestion_provider::SuggestionProvider, - tree::{ - argument_command_node::ArgumentCommandNode, - command_node::{BaseCommandNode, CommandNodeTrait}, - root_command_node::RootCommandNode, - }, -}; -use std::any::Any; -use std::fmt::Debug; - -pub struct RequiredArgumentBuilder<'a, S> { - arguments: RootCommandNode<'a, S>, - command: Option<Box<dyn Command<S>>>, - requirement: Box<dyn Fn(&S) -> bool>, - target: Option<Box<dyn CommandNodeTrait<S>>>, - modifier: Option<Box<dyn RedirectModifier<S>>>, - forks: bool, - - name: String, - type_: Box<dyn ArgumentType<Into = dyn Any>>, - suggestions_provider: Option<Box<dyn SuggestionProvider<S>>>, +use super::argument_builder::{ArgumentBuilder, ArgumentBuilderType}; +use crate::{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, +/// which can be anything. +#[derive(Clone)] +pub struct Argument { + pub name: String, + parser: Rc<dyn Parser>, } - -impl<'a, S> RequiredArgumentBuilder<'a, S> { - pub fn new(name: String, type_: Box<dyn ArgumentType<Into = dyn Any>>) -> Self { +impl Argument { + pub fn new(name: &str, parser: Rc<dyn Parser>) -> Self { Self { - name, - type_: type_, - suggestions_provider: None, - arguments: RootCommandNode::new(), - command: None, - requirement: Box::new(|_| true), - target: None, - modifier: None, - forks: false, + name: name.to_string(), + parser: parser, } } - pub fn argument(name: String, type_: Box<dyn ArgumentType<Into = dyn Any>>) -> Self { - Self::new(name, type_) - } - - pub fn suggests(mut self, provider: Box<dyn SuggestionProvider<S>>) -> Self { - self.suggestions_provider = Some(provider); - self - } - - pub fn suggestions_provider(&self) -> Option<Box<dyn SuggestionProvider<S>>> { - self.suggestions_provider + pub fn parse(&self, reader: &mut StringReader) -> Option<Rc<dyn Any>> { + self.parser.parse(reader) } +} - pub fn get_type(&self) -> Box<dyn ArgumentType<Into = dyn Any>> { - self.type_ +impl From<Argument> for ArgumentBuilderType { + fn from(argument: Argument) -> Self { + Self::Argument(argument) } +} - pub fn name(&self) -> &str { - &self.name +impl Debug for Argument { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Argument") + .field("name", &self.name) + // .field("parser", &self.parser) + .finish() } +} - // final ArgumentCommandNode<S> result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), isFork(), getSuggestionsProvider()); - - // for (final CommandNode<S> argument : getArguments()) { - // result.addChild(argument); - // } - - // return result; - pub fn build(self) -> ArgumentCommandNode<'a, S> { - let result = ArgumentCommandNode { - name: self.name, - type_: self.type_, - command: self.base.command(), - requirement: self.base.requirement(), - redirect: self.base.get_redirect(), - modifier: self.base.get_redirect_modifier(), - forks: self.base.forks, - custom_suggestions: self.base.custom_suggestions, - ..ArgumentCommandNode::default() - }; - - for argument in self.base.arguments() { - result.add_child(argument); - } - - result - } +/// Shortcut for creating a new argument builder node. +pub fn argument<'a, S: Any + Clone>( + name: &'a str, + parser: impl Parser + 'static, +) -> ArgumentBuilder<S> { + ArgumentBuilder::new(Argument::new(name, Rc::new(parser)).into()) } |
