From a72a47ced76065caf739898954cd18edbc39174b Mon Sep 17 00:00:00 2001 From: mat Date: Sun, 17 Apr 2022 14:02:13 -0500 Subject: Rewrite brigadier --- azalea-brigadier/src/builder/argument_builder.rs | 257 ++++++++++++--------- .../src/builder/literal_argument_builder.rs | 60 ++--- .../src/builder/required_argument_builder.rs | 113 +++------ 3 files changed, 205 insertions(+), 225 deletions(-) (limited to 'azalea-brigadier/src/builder') 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>>, - requirement: Box bool>, - target: Option>>, - modifier: Option>>, - 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 { - fn build(self) -> Box>; +/// A node that hasn't yet been built. +#[derive(Clone)] +pub struct ArgumentBuilder { + value: ArgumentBuilderType, + + children: BTreeMap>>>, + literals: BTreeMap>>>, + arguments: BTreeMap>>>, + + executes: Option) -> i32>>, + requirement: Rc) -> bool>, + forks: bool, + modifier: Option>>, } -impl<'a, S> BaseArgumentBuilder<'a, S> { - pub fn then(&mut self, argument: Box>) -> 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> { - &self.arguments.get_children() +/// A node that isn't yet built. +impl ArgumentBuilder { + 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>) -> &mut Self { - self.command = Some(command); + pub fn then(&mut self, node: ArgumentBuilder) -> &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>> { - self.command + pub fn executes(&mut self, f: F) -> Self + where + F: Fn(&CommandContext) -> i32 + 'static, + { + self.executes = Some(Rc::new(f)); + self.clone() } - pub fn requires(&mut self, requirement: Box bool>) -> &mut Self { - self.requirement = requirement; - self - } + pub fn build(self) -> CommandNode { + println!("building {:?}", self); + CommandNode { + value: self.value, - pub fn requirement(&self) -> Box bool> { - self.requirement - } + children: self.children, + literals: self.literals, + arguments: self.arguments, - pub fn redirect(&mut self, target: Box>) -> &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, - modifier: &dyn SingleRedirectModifier, - ) -> &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 Debug for ArgumentBuilder { + 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, - modifier: &dyn RedirectModifier, - ) -> &mut Self { - self.forward(target, Some(modifier), true) - } +#[cfg(test)] +mod tests { + use std::rc::Rc; - pub fn forward( - &mut self, - target: Option>>, - modifier: Option<&dyn RedirectModifier>, - 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> { - self.target.as_ref() - } + use super::ArgumentBuilder; - pub fn get_redirect_modifier(&self) -> Option<&dyn RedirectModifier> { - self.modifier.as_ref() - } + // public class ArgumentBuilderTest { + // private TestableArgumentBuilder 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 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) argument.build())); + // } - result - } -} + #[test] + fn test_arguments() { + let mut builder: ArgumentBuilder<()> = literal("foo"); -impl 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 target = mock(CommandNode.class); + // builder.redirect(target); + // assertThat(builder.getRedirect(), is(target)); + // } + + // @Test(expected = IllegalStateException.class) + // public void testRedirect_withChild() throws Exception { + // final CommandNode target = mock(CommandNode.class); + // builder.then(literal("foo")); + // builder.redirect(target); + // } + + // @Test(expected = IllegalStateException.class) + // public void testThen_withRedirect() throws Exception { + // final CommandNode target = mock(CommandNode.class); + // builder.redirect(target); + // builder.then(literal("foo")); + // } + + // private static class TestableArgumentBuilder extends ArgumentBuilder> { + // @Override + // protected TestableArgumentBuilder getThis() { + // return this; + // } + + // @Override + // public CommandNode 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 { - arguments: RootCommandNode, - command: Option>>, - requirement: Box bool>, - target: Option>>, - modifier: Option>>, - forks: bool, - literal: String, -} +use super::argument_builder::{ArgumentBuilder, ArgumentBuilderType}; -impl LiteralArgumentBuilder { - 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 for ArgumentBuilderType { + fn from(literal: Literal) -> Self { + Self::Literal(literal) } } -impl ArgumentBuilder for LiteralArgumentBuilder { - fn build(self) -> Box> { - 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(value: &str) -> ArgumentBuilder { + 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>>, - requirement: Box bool>, - target: Option>>, - modifier: Option>>, - forks: bool, - - name: String, - type_: Box>, - suggestions_provider: Option>>, +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, } - -impl<'a, S> RequiredArgumentBuilder<'a, S> { - pub fn new(name: String, type_: Box>) -> Self { +impl Argument { + pub fn new(name: &str, parser: Rc) -> 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>) -> Self { - Self::new(name, type_) - } - - pub fn suggests(mut self, provider: Box>) -> Self { - self.suggestions_provider = Some(provider); - self - } - - pub fn suggestions_provider(&self) -> Option>> { - self.suggestions_provider + pub fn parse(&self, reader: &mut StringReader) -> Option> { + self.parser.parse(reader) } +} - pub fn get_type(&self) -> Box> { - self.type_ +impl From 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 result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), isFork(), getSuggestionsProvider()); - - // for (final CommandNode 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 { + ArgumentBuilder::new(Argument::new(name, Rc::new(parser)).into()) } -- cgit v1.2.3