aboutsummaryrefslogtreecommitdiff
path: root/azalea-brigadier/src/builder
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-04-17 14:02:13 -0500
committermat <github@matdoes.dev>2022-04-17 14:02:13 -0500
commita72a47ced76065caf739898954cd18edbc39174b (patch)
tree5526c7663f253bbd7c8318b9d98413f1f2074852 /azalea-brigadier/src/builder
parent4ff67d4917ce333232189e86aee09f2d82451fc6 (diff)
downloadazalea-drasl-a72a47ced76065caf739898954cd18edbc39174b.tar.xz
Rewrite brigadier
Diffstat (limited to 'azalea-brigadier/src/builder')
-rw-r--r--azalea-brigadier/src/builder/argument_builder.rs257
-rw-r--r--azalea-brigadier/src/builder/literal_argument_builder.rs60
-rw-r--r--azalea-brigadier/src/builder/required_argument_builder.rs113
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())
}