implement tag declaration

This commit is contained in:
Moritz Hölting 2024-09-21 22:45:05 +02:00
parent 0133661ad4
commit 6abe437c70
6 changed files with 144 additions and 3 deletions

View File

@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- lua blocks - lua blocks
- imports - imports
- group - group
- Tags
### Changed ### Changed

View File

@ -14,7 +14,7 @@ Namespace: 'namespace' StringLiteral;
### Declaration ### Declaration
```ebnf ```ebnf
Declaration: FunctionDeclaration | Import; Declaration: FunctionDeclaration | Import | TagDeclaration;
``` ```
### Import ### Import
@ -22,6 +22,11 @@ Declaration: FunctionDeclaration | Import;
Import: 'from' StringLiteral 'import' Identifier; Import: 'from' StringLiteral 'import' Identifier;
``` ```
### TagDeclaration
```ebnf
TagDeclaration: 'tag' StringLiteral ('of' StringLiteral)? 'replace'? '[' (StringLiteral (',' StringLiteral)*)? ']';
```
### FunctionDeclaration ### FunctionDeclaration
```ebnf ```ebnf
Function: Function:

View File

@ -41,6 +41,9 @@ pub enum KeywordKind {
Namespace, Namespace,
From, From,
Import, Import,
Tag,
Of,
Replace,
} }
impl Display for KeywordKind { impl Display for KeywordKind {
@ -101,6 +104,9 @@ impl KeywordKind {
Self::Namespace => "namespace", Self::Namespace => "namespace",
Self::From => "from", Self::From => "from",
Self::Import => "import", Self::Import => "import",
Self::Tag => "tag",
Self::Of => "of",
Self::Replace => "replace",
} }
} }

View File

@ -20,7 +20,7 @@ use crate::{
}, },
}; };
use super::{statement::Block, ConnectedList}; use super::{statement::Block, ConnectedList, DelimitedList};
/// Syntax Synopsis: /// Syntax Synopsis:
/// ///
@ -35,6 +35,7 @@ use super::{statement::Block, ConnectedList};
pub enum Declaration { pub enum Declaration {
Function(Function), Function(Function),
Import(Import), Import(Import),
Tag(Tag),
} }
impl SourceElement for Declaration { impl SourceElement for Declaration {
@ -42,6 +43,7 @@ impl SourceElement for Declaration {
match self { match self {
Self::Function(function) => function.span(), Self::Function(function) => function.span(),
Self::Import(import) => import.span(), Self::Import(import) => import.span(),
Self::Tag(tag) => tag.span(),
} }
} }
} }
@ -226,6 +228,79 @@ impl SourceElement for Import {
} }
} }
/// Syntax Synopsis:
///
/// ``` ebnf
/// TagDeclaration:
/// 'tag' StringLiteral ('of' StringLiteral)? 'replace'? '[' (StringLiteral (',' StringLiteral)*)? ']'
/// ;
/// ```
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
pub struct Tag {
#[get = "pub"]
tag_keyword: Keyword,
#[get = "pub"]
name: StringLiteral,
#[get = "pub"]
of_type: Option<(Keyword, StringLiteral)>,
#[get = "pub"]
replace: Option<Keyword>,
#[get = "pub"]
entries: DelimitedList<StringLiteral>,
}
impl Tag {
#[must_use]
#[allow(clippy::type_complexity)]
pub fn dissolve(
self,
) -> (
Keyword,
StringLiteral,
Option<(Keyword, StringLiteral)>,
Option<Keyword>,
DelimitedList<StringLiteral>,
) {
(
self.tag_keyword,
self.name,
self.of_type,
self.replace,
self.entries,
)
}
#[cfg(feature = "shulkerbox")]
#[must_use]
pub fn tag_type(&self) -> shulkerbox::datapack::tag::TagType {
use shulkerbox::datapack::tag::TagType;
self.of_type
.as_ref()
.map_or(TagType::Functions, |(_, tag_type)| {
match tag_type.str_content().as_ref() {
"function" => TagType::Functions,
"block" => TagType::Blocks,
"entity_type" => TagType::Entities,
"fluid" => TagType::Fluids,
"game_event" => TagType::GameEvents,
"item" => TagType::Items,
other => TagType::Others(other.to_string()),
}
})
}
}
impl SourceElement for Tag {
fn span(&self) -> Span {
self.tag_keyword
.span()
.join(&self.entries.close.span)
.unwrap()
}
}
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
/// Parses an annotation. /// Parses an annotation.
/// ///
@ -384,6 +459,44 @@ impl<'a> Parser<'a> {
} }
} }
Reading::Atomic(Token::Keyword(tag_keyword))
if tag_keyword.keyword == KeywordKind::Tag =>
{
// eat the tag keyword
self.forward();
// parse the name
let name = self.parse_string_literal(handler)?;
let of_type = self
.try_parse(|parser| {
let of_keyword = parser.parse_keyword(KeywordKind::Of, &VoidHandler)?;
let of_type = parser.parse_string_literal(handler)?;
Ok((of_keyword, of_type))
})
.ok();
let replace = self
.try_parse(|parser| parser.parse_keyword(KeywordKind::Replace, &VoidHandler))
.ok();
let entries = self.parse_enclosed_list(
Delimiter::Bracket,
',',
|parser| parser.parse_string_literal(handler),
handler,
)?;
Ok(Declaration::Tag(Tag {
tag_keyword,
name,
of_type,
replace,
entries,
}))
}
unexpected => { unexpected => {
// make progress // make progress
self.forward(); self.forward();

View File

@ -49,6 +49,7 @@ pub struct ConnectedList<Element, Separator> {
/// Represents a syntax tree node with a pattern of having [`ConnectedList`] delimited by a pair of /// Represents a syntax tree node with a pattern of having [`ConnectedList`] delimited by a pair of
/// punctuation like such `(a, b, c)`. /// punctuation like such `(a, b, c)`.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DelimitedList<T> { pub struct DelimitedList<T> {
/// The open punctuation of the list. /// The open punctuation of the list.

View File

@ -84,7 +84,6 @@ impl Transpiler {
let mut always_transpile_functions = Vec::new(); let mut always_transpile_functions = Vec::new();
// #[allow(clippy::significant_drop_in_scrutinee)]
{ {
let functions = self.functions.read().unwrap(); let functions = self.functions.read().unwrap();
for (_, data) in functions.iter() { for (_, data) in functions.iter() {
@ -183,6 +182,22 @@ impl Transpiler {
} }
} }
} }
Declaration::Tag(tag) => {
let namespace = self
.datapack
.namespace_mut(&namespace.namespace_name().str_content());
let sb_tag = namespace.tag_mut(&tag.name().str_content(), tag.tag_type());
if let Some(list) = &tag.entries().list {
for value in list.elements() {
sb_tag.add_value(value.str_content().as_ref().into());
}
}
if tag.replace().is_some() {
sb_tag.set_replace(true);
}
}
}; };
} }